Files
reverse-engineering-anything/tests/boundary/cli/idaRetainedCleanupCli.test.ts
T
84990f9777 test: remove fixed child-process deadlines from tests
239 literal timeoutMs values on cli.run and processes.run only restated
a guess at host speed. On hosted runners with four workers, cliOutput's
3-second value failed while the command still produced correct output.
Deadlines that are the behavior under test, derived from an operation
budget, or that bound a regression's wait remain.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 13:21:13 +08:00

103 lines
3.5 KiB
TypeScript

import { describe, expect } from "vitest";
import { workspaceCliTest } from "../../support/cli/workspaceCliFixture.js";
import { elf } from "../../../src/domain/binaryTarget.fixture.js";
/**
* A headless IDA supervisor that completes the MCP handshake and then leaves
* every tool call unanswered, as an `idb_open` still running auto-analysis
* would. It exits when REA closes its input.
*/
const UNRESPONSIVE_SUPERVISOR = `import { createInterface } from "node:readline";
const tools = ["idb_open", "idb_list", "idb_close", "server_health", "list_funcs",
"lookup_funcs", "find_regex", "decompile", "disasm", "callees", "xrefs_to"];
const send = (message) =>
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", ...message }) + "\\n");
for await (const line of createInterface({ input: process.stdin })) {
const request = JSON.parse(line);
if (request.method === "initialize")
send({ id: request.id, result: {
protocolVersion: request.params.protocolVersion,
capabilities: { tools: {} },
serverInfo: { name: "unresponsive-ida-fixture", version: "1" },
} });
else if (request.method === "tools/list")
send({ id: request.id, result: {
tools: tools.map((name) => ({ name, inputSchema: { type: "object" } })),
} });
}
`;
describe("headless IDA timeout through the one-shot CLI", () => {
workspaceCliTest(
"exits after a retained-cleanup failure instead of waiting on the supervisor",
async ({ cli, workspace }) => {
const supervisor = await workspace.write(
"supervisor.mjs",
UNRESPONSIVE_SUPERVISOR,
);
const workspaceRoot = await workspace.mkdir("ida-workspaces");
const registration = await workspace.write(
"ida-mcp.json",
JSON.stringify({
command: process.execPath,
args: [supervisor],
mode: "headless",
timeoutMs: 500,
workspaceRoot,
}),
);
const target = await workspace.write("target.elf", elf(2, 1, 62));
const result = await cli.run({
arguments: ["decompile", target, "main", "--json"],
environment: {
...workspace.environment,
REA_ANALYSIS_PROVIDER: "ida",
REA_IDA_MCP_CONFIG: registration,
REA_LOG_LEVEL: "silent",
},
});
expect(result.exitCode).toBe(1);
expect(result.json).toMatchObject({
code: "cleanup_incomplete",
details: {
cleanup: "incomplete",
execution_failure: "provider_timeout",
operation: "procedure_pseudo_code",
diagnostics: {
startup_operation: "idb_open",
},
timeout_ms: 500,
resources: [expect.stringContaining(workspaceRoot)],
cleanup_error: {
code: "cleanup_incomplete",
details: {
provider_id: "ida",
operation: "close",
diagnostics: {
upstream_sessions: {
state: "unverified",
sessions: [
{
session_id: expect.stringMatching(/^rea-/),
backend: "worker",
owned: null,
input_path: null,
is_active: null,
},
],
},
},
},
},
},
});
// The one-shot CLI exits after its close, so no close_binary retry exists.
expect(JSON.stringify(result.json)).not.toContain("retry_cleanup");
},
);
});