* test: strengthen integration oracles and verification * test: bound lifecycle gates and strengthen workflow checks * test: verify complete paged and extracted results * test: preserve bytecode and cancellation evidence * test: strengthen retained evidence and fixture cleanup * test: require cross-projection bridge identities * test: retain fixture owners through cleanup failures * test: verify graph examples and project selectors * test: tighten provider and lifecycle regressions * test: consolidate hex coverage and bound cutter cleanup * test: bound subprocess output waits and strengthen graph checks * test: check mcp recovery and preserve cleanup owners * test: verify structured mcp argument failures * test: preserve artifact cleanup and gdb limit evidence * test: preserve evidence identities and bound provider gates * test: retain browser and comparison cleanup owners * test: bound startup and strengthen fixture oracles * test: bound lifecycle gates and verify recovered evidence * test: verify public outcomes and lifecycle ownership * test: assert precise evidence and release lifecycle gates * test: verify selected facts and bound cleanup waits * test: check retained evidence and decoded records * test: verify final reports and retain cleanup ownership * test: bound reviewed startup gates and retain cleanup * test: verify PE errors and preserve MCP cleanup * test: preserve MCP fixture cleanup ownership * test: release provider gates before late startup
122 lines
4.2 KiB
TypeScript
122 lines
4.2 KiB
TypeScript
import { chmod, mkdtemp, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import type { Client } from "@modelcontextprotocol/client";
|
|
import { expect, it } from "vitest";
|
|
|
|
import { createProviderEnvironmentMcpHarness } from "../../support/reverseDebuggerMcpTestHelpers.js";
|
|
|
|
const writeProvider = async (path: string, output: string): Promise<void> => {
|
|
await writeFile(
|
|
path,
|
|
`#!${process.execPath}\nprocess.stdout.write('${output}');\n`,
|
|
);
|
|
await chmod(path, 0o755);
|
|
};
|
|
|
|
const connectProviderClient = (options: {
|
|
readonly directory: string;
|
|
readonly clientName: string;
|
|
readonly configuredProvider: string;
|
|
readonly providerEnvironment?: { REA_RIZIN_COMMAND: string };
|
|
}) =>
|
|
createProviderEnvironmentMcpHarness({
|
|
directory: options.directory,
|
|
clientName: options.clientName,
|
|
serverOptions: {
|
|
environment: { REA_RIZIN_COMMAND: options.configuredProvider },
|
|
...(options.providerEnvironment === undefined
|
|
? {}
|
|
: { providerEnvironment: options.providerEnvironment }),
|
|
},
|
|
});
|
|
|
|
const executeRizinCommand = async (
|
|
client: Client,
|
|
artifact: string,
|
|
): Promise<Awaited<ReturnType<Client["callTool"]>>> => {
|
|
const response = await client.callTool({
|
|
name: "execute_rizin_command",
|
|
arguments: { path: artifact, command: "iI" },
|
|
});
|
|
expect(response.isError).not.toBe(true);
|
|
return response;
|
|
};
|
|
|
|
it("uses the captured server environment to resolve reverse-engineering providers", async () => {
|
|
const directory = await mkdtemp(join(tmpdir(), "rea-provider-environment-"));
|
|
const provider = join(directory, "selected-rizin");
|
|
const artifact = join(directory, "fixture.bin");
|
|
await writeFile(artifact, "fixture");
|
|
await writeProvider(provider, "captured-environment-provider");
|
|
|
|
const { client } = await connectProviderClient({
|
|
directory,
|
|
clientName: "reverse-provider-environment",
|
|
configuredProvider: provider,
|
|
});
|
|
const response = await executeRizinCommand(client, artifact);
|
|
expect(response.structuredContent).toMatchObject({
|
|
raw_result: { stdout: "captured-environment-provider" },
|
|
});
|
|
});
|
|
|
|
it("prefers an explicit provider environment over the captured server environment", async () => {
|
|
const directory = await mkdtemp(join(tmpdir(), "rea-provider-override-"));
|
|
const configured = join(directory, "captured-rizin");
|
|
const override = join(directory, "override-rizin");
|
|
const artifact = join(directory, "fixture.bin");
|
|
await writeFile(artifact, "fixture");
|
|
for (const [path, output] of [
|
|
[configured, "captured"],
|
|
[override, "explicit-override"],
|
|
] as const) {
|
|
await writeProvider(path, output);
|
|
}
|
|
const { client } = await connectProviderClient({
|
|
directory,
|
|
clientName: "reverse-provider-override",
|
|
configuredProvider: configured,
|
|
providerEnvironment: { REA_RIZIN_COMMAND: override },
|
|
});
|
|
|
|
const response = await executeRizinCommand(client, artifact);
|
|
expect(response.structuredContent).toMatchObject({
|
|
raw_result: { stdout: "explicit-override" },
|
|
});
|
|
expect(JSON.stringify(response.structuredContent)).not.toContain(
|
|
'"captured"',
|
|
);
|
|
});
|
|
|
|
it("snapshots an explicit provider environment when the server is created", async () => {
|
|
const directory = await mkdtemp(join(tmpdir(), "rea-provider-snapshot-"));
|
|
const configured = join(directory, "captured-rizin");
|
|
const override = join(directory, "explicit-rizin");
|
|
const artifact = join(directory, "fixture.bin");
|
|
await writeFile(artifact, "fixture");
|
|
for (const [path, output] of [
|
|
[configured, "captured"],
|
|
[override, "explicit-snapshot"],
|
|
] as const) {
|
|
await writeProvider(path, output);
|
|
}
|
|
const providerEnvironment = { REA_RIZIN_COMMAND: override };
|
|
const { client } = await connectProviderClient({
|
|
directory,
|
|
clientName: "reverse-provider-snapshot",
|
|
configuredProvider: configured,
|
|
providerEnvironment,
|
|
});
|
|
providerEnvironment.REA_RIZIN_COMMAND = configured;
|
|
|
|
const response = await executeRizinCommand(client, artifact);
|
|
expect(response.structuredContent).toMatchObject({
|
|
raw_result: { stdout: "explicit-snapshot" },
|
|
});
|
|
expect(JSON.stringify(response.structuredContent)).not.toContain(
|
|
'"captured"',
|
|
);
|
|
});
|