fix(ghidra): omit duplicate load-image result (#7777)
* fix(ghidra): omit duplicate load-image result * docs(mcp): describe load-image evidence projection
This commit is contained in:
1 parent
64d282b0a6
commit
a965cbab06
5 files changed
+59
-13
No files matched your search
@@ -69,13 +69,14 @@ the same Evidence authentication failures: an admitted source that fails
|
||||
authentication is `evidence_integrity_mismatch`, while an authenticated source with an unsupported
|
||||
workflow role or invalid selector is `invalid_request`.
|
||||
|
||||
Ghidra inventories and function replies use `raw_result: null` when their facts
|
||||
are already preserved in `normalized_result`, limitations, locations and
|
||||
relationship coverage. Distinct overview details, measured load-image
|
||||
observations, file-offset selection roles and database types supplemented with
|
||||
derived metadata keep their upstream representation. Read function results from
|
||||
`normalized_result`; older retained Evidence keeps its original representation
|
||||
and identity.
|
||||
Ghidra inventories, measured load-image observations and function replies use
|
||||
`raw_result: null` when their useful facts are already preserved in
|
||||
`normalized_result`, limitations, locations and relationship coverage. Distinct
|
||||
overview details, file-offset selection roles and database types supplemented
|
||||
with derived metadata keep their upstream representation. Native load-image
|
||||
attestation continues to use the bridge reply locally before Evidence
|
||||
projection. Read function results from `normalized_result`; older retained
|
||||
Evidence keeps its original representation and identity.
|
||||
|
||||
Artifact source-map filename relationships require a unique, identified regular
|
||||
file at the sibling path. A known directory cannot be the mapped file; the map
|
||||
|
||||
@@ -166,6 +166,17 @@ export type NativeLoadImage = z.infer<typeof nativeLoadImageSchema>;
|
||||
export type NativeLoadImageObservation = z.infer<
|
||||
typeof nativeLoadImageObservationSchema
|
||||
>;
|
||||
|
||||
/** Remove entry-context rows that carry no register observations. */
|
||||
export const normalizeNativeLoadImageObservation = (
|
||||
observation: NativeLoadImageObservation,
|
||||
): NativeLoadImageObservation => ({
|
||||
...observation,
|
||||
entry_context: observation.entry_context.filter(
|
||||
({ registers }) => registers.length > 0,
|
||||
),
|
||||
});
|
||||
|
||||
/** One independently compared native import fact. */
|
||||
export type NativeLoadImageCheck = z.infer<typeof nativeLoadImageCheckSchema>;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { z } from "zod";
|
||||
|
||||
import { nativeLoadImageObservationFixture } from "../../tests/fixtures/nativeLoadImage.js";
|
||||
import {
|
||||
parseGhidraInventoryInput,
|
||||
parseGhidraInventoryResult,
|
||||
@@ -98,6 +99,40 @@ it.each(["list_procedures", "search_procedures"] as const)(
|
||||
},
|
||||
);
|
||||
|
||||
describe("native load-image result projection", () => {
|
||||
it("omits raw bridge output when the observation keeps every reported fact", () => {
|
||||
const observations = JSON.parse(
|
||||
JSON.stringify(nativeLoadImageObservationFixture()),
|
||||
);
|
||||
const parsed = parseGhidraInventoryResult(
|
||||
"inspect_native_load_image",
|
||||
observations,
|
||||
);
|
||||
expect(parsed.ok).toBe(true);
|
||||
if (!parsed.ok) throw parsed.error;
|
||||
expect(JSON.stringify(parsed.value.value)).toBe(
|
||||
JSON.stringify(observations),
|
||||
);
|
||||
expect(parsed.value.rawResult).toBeUndefined();
|
||||
});
|
||||
|
||||
it("omits entry-context rows without register observations", () => {
|
||||
const observations = JSON.parse(
|
||||
JSON.stringify({
|
||||
...nativeLoadImageObservationFixture(),
|
||||
entry_context: [{ address: "ram:0x0010", registers: [] }],
|
||||
}),
|
||||
);
|
||||
const parsed = parseGhidraInventoryResult(
|
||||
"inspect_native_load_image",
|
||||
observations,
|
||||
);
|
||||
expect(parsed.ok).toBe(true);
|
||||
if (!parsed.ok) throw parsed.error;
|
||||
expect(JSON.stringify(parsed.value.value)).toContain('"entry_context":[]');
|
||||
});
|
||||
});
|
||||
|
||||
it("validates large masked byte queries at the provider boundary without changing caller spelling", () => {
|
||||
const input = {
|
||||
pattern: "aA??".repeat(1024 * 1024),
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
byteSearchResultSchema,
|
||||
} from "../domain/native/bytePattern.js";
|
||||
import {
|
||||
normalizeNativeLoadImageObservation,
|
||||
nativeLoadImageObservationSchema,
|
||||
type NativeLoadImageObservation,
|
||||
} from "../domain/native/nativeLoadImage.js";
|
||||
@@ -365,7 +366,7 @@ export function parseGhidraInventoryResult(
|
||||
if (operation === "inspect_native_load_image") {
|
||||
const parsed = resultSchemas.inspect_native_load_image.safeParse(value);
|
||||
return parsed.success
|
||||
? ok({ value: parsed.data, rawResult: value })
|
||||
? ok({ value: normalizeNativeLoadImageObservation(parsed.data) })
|
||||
: err(inventoryOutputFailure(operation, parsed.error));
|
||||
}
|
||||
const parsed = resultSchemas[operation].safeParse(value);
|
||||
|
||||
@@ -1811,7 +1811,7 @@ describe("Ghidra measured DOS load-image projection", () => {
|
||||
ok: true,
|
||||
value: {
|
||||
result: { status: state, observations: fixture.observation },
|
||||
rawResult: fixture.observation,
|
||||
rawResult: null,
|
||||
analysisProfile: profile.value.profile,
|
||||
},
|
||||
});
|
||||
@@ -1894,7 +1894,7 @@ it("returns read-only NativeAOT metadata inline and drills down by derived Metho
|
||||
],
|
||||
},
|
||||
},
|
||||
rawResult: observations,
|
||||
rawResult: null,
|
||||
},
|
||||
});
|
||||
for (const address of [
|
||||
@@ -2149,9 +2149,7 @@ it("shares one session snapshot across callers while isolating cancellation and
|
||||
expect(secondResult).toMatchObject({
|
||||
ok: true,
|
||||
value: {
|
||||
rawResult: {
|
||||
source_files: [{ name: "caller-2" }],
|
||||
},
|
||||
rawResult: null,
|
||||
result: {
|
||||
observations: {
|
||||
source_files: [{ name: "caller-2" }],
|
||||
|
||||
Reference in new issue
Block a user