mirror of
https://github.com/morluto/rea.git
synced 2026-11-02 21:06:04 +00:00
* test(mcp): expect trace_feature to report references the provider truncated A provider that reports a capped xrefs read makes the trace truncated with a residual unknown for that target. An explicit complete report and a provider that reports nothing leave the trace as before. * fix(mcp): report references a provider truncated in trace_feature Executions gain an optional flag for a capped xrefs read, set by the IDA adapter from the upstream cap. trace_feature marks the trace truncated with a residual unknown for that target only when the provider reports a truncation; a provider that reports nothing keeps its previous result. The trace_feature workflow profile is revised so earlier results are not replayed. * refactor(ida): report reference truncation whenever the runner observed an xrefs cap * test(mcp): cover session forwarding, per-target state, native reports and failures of the trace coverage * test(mcp): format the session forwarding test * test(ida): expect headless IDA to resolve containing procedures from lookups and segment facts Cover positive and negative containment, segment boundaries including addresses above 2^53, failures of the lookup and of the segment survey, cancellation, input validation and the admitted program as the only document. * test(ida): expect feature tracing and address context to work on headless IDA Run trace_feature, including a capped reference read, and inspect_address_context with and without an explicit document through the IDA session client. * test(mcp): expect trace_feature availability to follow the search operations it calls * fix(mcp): derive trace_feature availability from the search operations it calls * feat(ida): resolve containing procedures and report the admitted program as the document The modern headless profile resolves an address through the function lookup and, when no function contains it, tells a mapped address from an unmapped one using the database-scoped minimal survey. A survey that is missing, truncated or inconsistent fails the read. list_documents reports the single admitted program. The attached profiles do not declare either operation. * docs(ida): describe containing procedures, the admitted document and truncated feature traces * test(ida): verify containing procedures, the admitted document and feature tracing on real IDA * docs(testing): list the headless IDA workflows the real lane verifies * test(ida): make each survey failure case isolate a single defect * test(ida): pin large addresses, segment order, document identity, attached refusals and each trace_feature prerequisite * test(mcp): expect a repeated reference source to be resolved once in trace_feature * fix(mcp): resolve the containing procedure of a repeated reference source once * test(ida): trace the fixture procedure and derive probe addresses from its facts in the real lane * test(process): format processCaptureLifecycle.test.ts after the merge * test(ida): declare the alignment each synthetic universal slice offset satisfies * refactor(ida): move the real lane's feature trace assertions into a helper * test(ida): expect the real lane's feature trace check to accept references to every matched address * fix(ida): check each trace reference against its own matched address in the real lane * test(ida): pin that the new operations reject a document other than the admitted program * refactor(ida): move the real lane's mapped non-function probe into a helper * test(ida): expect the real lane's mapped data probe to skip strings inside functions * fix(ida): try the target's strings in order for the mapped non-function probe * test(ida): declare the real lane helper types for the verifier tests * test(ida): expect the real lane to reject a listed string that resolves as unmapped * fix(ida): fail the real lane when a listed string resolves as unmapped
97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import { rm } from "node:fs/promises";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
createIdaTarget,
|
|
RecordingIdaMcp,
|
|
} from "../../tests/fixtures/idaMcp.js";
|
|
import {
|
|
callGraphSession as session,
|
|
removeCallGraphSessions,
|
|
} from "../../tests/fixtures/idaCallGraph.js";
|
|
|
|
import { IdaSessionClient } from "./IdaSessionClient.js";
|
|
|
|
const attachedRoots: string[] = [];
|
|
afterEach(async () => {
|
|
await removeCallGraphSessions();
|
|
for (const root of attachedRoots.splice(0))
|
|
await rm(root, { recursive: true, force: true });
|
|
});
|
|
|
|
const xrefs = async (more: boolean | undefined) => {
|
|
const { client, producer } = await session({ callees: [] }, "x86_64");
|
|
const inner = producer.overrideCall;
|
|
producer.overrideCall = (name, args) =>
|
|
name === "xrefs_to"
|
|
? [{ xrefs: [], ...(more === undefined ? {} : { more }) }]
|
|
: inner?.(name, args);
|
|
try {
|
|
const result = await client.execute("xrefs", { address: "0x1000" });
|
|
if (!result.ok) throw result.error;
|
|
return result.value;
|
|
} finally {
|
|
expect((await client.close()).ok).toBe(true);
|
|
}
|
|
};
|
|
|
|
describe("headless IDA reference coverage", () => {
|
|
it("reports a capped xrefs read as truncated", async () => {
|
|
const execution = await xrefs(true);
|
|
|
|
expect(execution.referencesTruncated).toBe(true);
|
|
expect(
|
|
execution.limitations,
|
|
"the diagnostic limitation is still reported",
|
|
).toContain(
|
|
"Upstream xrefs_to capped results at 1000 references; additional references remain unknown.",
|
|
);
|
|
});
|
|
|
|
it("reports an explicitly uncapped xrefs read as not truncated", async () => {
|
|
expect((await xrefs(false)).referencesTruncated).toBe(false);
|
|
});
|
|
|
|
it("reports nothing when the producer does not say whether the read was capped", async () => {
|
|
expect((await xrefs(undefined)).referencesTruncated).toBeUndefined();
|
|
});
|
|
|
|
it("does not report reference coverage for other operations", async () => {
|
|
const { client } = await session({ callees: [] }, "x86_64");
|
|
try {
|
|
const result = await client.execute("procedure_callees", {
|
|
procedure: "main",
|
|
});
|
|
|
|
if (!result.ok) throw result.error;
|
|
expect(result.value.referencesTruncated).toBeUndefined();
|
|
} finally {
|
|
expect((await client.close()).ok).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("reports nothing for the legacy profile, whose producer has no cap flag", async () => {
|
|
const { root, target } = await createIdaTarget("x86_64");
|
|
attachedRoots.push(root);
|
|
const client = new IdaSessionClient(
|
|
{
|
|
command: "fixture",
|
|
args: [],
|
|
env: {},
|
|
mode: "attached",
|
|
timeoutMs: 1000,
|
|
workspaceRoot: root,
|
|
},
|
|
target,
|
|
new RecordingIdaMcp(target, "attached"),
|
|
);
|
|
try {
|
|
const result = await client.execute("xrefs", { address: "0x1000" });
|
|
|
|
if (!result.ok) throw result.error;
|
|
expect(result.value.referencesTruncated).toBeUndefined();
|
|
} finally {
|
|
expect((await client.close()).ok).toBe(true);
|
|
}
|
|
});
|
|
});
|