mirror of
https://github.com/morluto/rea
synced 2026-10-27 06:33:32 -04:00
905cbaf239
Use pinned tsrs on supported development hosts while retaining stable official TypeScript on Windows and unsupported platforms. Partition compile/typecheck caches by actual compiler and qualify fallback hosts for compiler inputs and lifecycle hooks. Reduce PE acceptance startup through the existing bounded compiled CLI. Retain upstream named MCP definitions, every fixture/assertion and the original 30s deadline. Verify that browser transport loss preserves the observed target. Validation: full qualification and real host lanes in https://github.com/morluto/rea/actions/runs/39590450889 ; 450 focused regressions passed with two documented conditional skips. All 1724 production emit files match SHA-256 and size across both compilers. Current-head Codex/Greptile review found no actionable issues. Measurements and limitations are in the PR. Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
422 lines
14 KiB
TypeScript
422 lines
14 KiB
TypeScript
import { Client } from "@modelcontextprotocol/client";
|
|
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
|
import { createHash } from "node:crypto";
|
|
import { readFile, writeFile } from "node:fs/promises";
|
|
import { join, resolve } from "node:path";
|
|
import { expect } from "vitest";
|
|
import { toolContract } from "../../../src/contracts/toolContracts.js";
|
|
import { peResourcesSchema } from "../../../src/domain/native/peResources.js";
|
|
import { peResourceFixture } from "../../../src/native/pe/PeResources.fixture.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
|
|
import {
|
|
cliTest,
|
|
runFileCli,
|
|
type TestCli,
|
|
} from "../../support/cli/cliFixture.js";
|
|
|
|
type PeResourceCall = (
|
|
arguments_: Record<string, unknown>,
|
|
) => ReturnType<Client["callTool"]>;
|
|
|
|
const expectPeInputFailureAcrossAdapters = async (input: {
|
|
readonly cli: TestCli;
|
|
readonly call: PeResourceCall;
|
|
readonly path: string;
|
|
readonly reason: "invalid_format" | "invalid_value";
|
|
}) => {
|
|
const { cli, call, path, reason } = input;
|
|
const result = await runFileCli(cli, {
|
|
arguments: ["inspect-pe-resources", path, "--json"],
|
|
});
|
|
expect(result.exitCode).toBe(1);
|
|
expect(result.json).toMatchObject({
|
|
code: "invalid_request",
|
|
category: "invalid_input",
|
|
details: {
|
|
operation: "inspect_pe_resources",
|
|
issues: [{ path: ["path"], reason }],
|
|
},
|
|
});
|
|
const response = await call({ path });
|
|
expect(response.isError).toBe(true);
|
|
expect(parseMcpToolError(response)).toEqual({ error: result.json });
|
|
};
|
|
|
|
const expectPePaddingFailureAcrossAdapters = async (input: {
|
|
readonly cli: TestCli;
|
|
readonly call: PeResourceCall;
|
|
readonly path: string;
|
|
}) => {
|
|
const { cli, call, path } = input;
|
|
const fixture = peResourceFixture();
|
|
const virtualSize = fixture.bytes.readUInt32LE(fixture.sectionAt + 8);
|
|
fixture.bytes.writeUInt32LE(
|
|
0x2000 + virtualSize,
|
|
fixture.dataOffsets[0] ?? 0,
|
|
);
|
|
fixture.bytes.writeUInt32LE(4, (fixture.dataOffsets[0] ?? 0) + 4);
|
|
await writeFile(path, fixture.bytes);
|
|
const cliResult = await cli.run({
|
|
arguments: ["inspect-pe-resources", path, "--json"],
|
|
});
|
|
expect(cliResult.exitCode).not.toBe(0);
|
|
const mcpResult = await call({ path });
|
|
expect(mcpResult.isError).toBe(true);
|
|
expect(peResourcesSchema.safeParse(mcpResult.structuredContent).success).toBe(
|
|
false,
|
|
);
|
|
};
|
|
|
|
const expectPeInputFailuresAcrossAdapters = async (input: {
|
|
readonly cli: TestCli;
|
|
readonly call: PeResourceCall;
|
|
readonly root: string;
|
|
}) => {
|
|
const { cli, call, root } = input;
|
|
const malformedPath = join(root, "malformed.exe");
|
|
await writeFile(malformedPath, Buffer.from("not a PE image"));
|
|
for (const [path, reason] of [
|
|
[join(root, "missing.exe"), "invalid_value"],
|
|
[malformedPath, "invalid_format"],
|
|
] as const)
|
|
await expectPeInputFailureAcrossAdapters({
|
|
cli,
|
|
call,
|
|
path,
|
|
reason,
|
|
});
|
|
};
|
|
|
|
const contract = toolContract("inspect_pe_resources");
|
|
|
|
const expectPeWordAlignedRecordsAcrossAdapters = async (input: {
|
|
readonly cli: TestCli;
|
|
readonly call: PeResourceCall;
|
|
readonly root: string;
|
|
}): Promise<void> => {
|
|
const { cli, call, root } = input;
|
|
for (const plus of [false, true]) {
|
|
for (const [index, identities] of [
|
|
{ type: 10, name: 1, language: "AB" },
|
|
{ type: "AB", name: 1, language: 1033 },
|
|
].entries()) {
|
|
const fixture = peResourceFixture(
|
|
plus,
|
|
[{ ...identities, payload: Buffer.from("opaque resource") }],
|
|
65536,
|
|
2,
|
|
);
|
|
const path = join(root, `word-aligned-${plus}-${index}.exe`);
|
|
await writeFile(path, fixture.bytes);
|
|
const result = await runFileCli(cli, {
|
|
arguments: ["inspect-pe-resources", path, "--json"],
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
const evidence = contract.outputSchema.parse(result.json);
|
|
const report = peResourcesSchema.parse(evidence.normalized_result);
|
|
expect(report.coverage).toMatchObject({
|
|
status: "complete",
|
|
resources: 1,
|
|
});
|
|
expect(report.resources[0]?.data_entry_location).toEqual({
|
|
offset: fixture.dataOffsets[0],
|
|
bytes: 16,
|
|
});
|
|
expect(report.resources[0]?.payload.sha256).toBe(
|
|
createHash("sha256").update("opaque resource").digest("hex"),
|
|
);
|
|
const response = await call({ path });
|
|
expect(response.isError).not.toBe(true);
|
|
expect(
|
|
contract.outputSchema.parse(response.structuredContent)
|
|
.normalized_result,
|
|
).toEqual(evidence.normalized_result);
|
|
expect(await readFile(path)).toEqual(fixture.bytes);
|
|
}
|
|
}
|
|
};
|
|
|
|
const expectPeMappingOwnershipAcrossAdapters = async (
|
|
cli: TestCli,
|
|
call: PeResourceCall,
|
|
root: string,
|
|
): Promise<void> => {
|
|
for (const { name, payloadRva, payloadBytes, section, expectedOffset } of [
|
|
{
|
|
name: "empty-header",
|
|
payloadRva: 0x300,
|
|
payloadBytes: 0,
|
|
section: null,
|
|
expectedOffset: 0x300,
|
|
},
|
|
{
|
|
name: "header-section-collision",
|
|
payloadRva: 0x300,
|
|
payloadBytes: 0,
|
|
section: { rva: 0x300, bytes: 4 },
|
|
expectedOffset: null,
|
|
},
|
|
{
|
|
name: "empty-section-in-header",
|
|
payloadRva: 0x300,
|
|
payloadBytes: 4,
|
|
section: { rva: 0x301, bytes: 0 },
|
|
expectedOffset: 0x300,
|
|
},
|
|
{
|
|
name: "empty-section-in-resources",
|
|
payloadRva: null,
|
|
payloadBytes: 4,
|
|
section: { rva: 0x2001, bytes: 0 },
|
|
expectedOffset: "original",
|
|
},
|
|
]) {
|
|
const fixture = peResourceFixture(false, [
|
|
{ type: 10, name: 1, language: 1033, payload: Buffer.from("DATA") },
|
|
]);
|
|
const data = fixture.dataOffsets[0] ?? 0;
|
|
let bytes = fixture.bytes;
|
|
const originalPayloadOffset = bytes.readUInt32LE(data) - 0x1c00;
|
|
if (payloadRva !== null) bytes.writeUInt32LE(payloadRva, data);
|
|
bytes.writeUInt32LE(payloadBytes, data + 4);
|
|
if (section !== null) {
|
|
bytes.writeUInt16LE(2, 0x86);
|
|
const at = fixture.sectionAt + 40;
|
|
bytes.writeUInt32LE(section.bytes, at + 8);
|
|
bytes.writeUInt32LE(section.rva, at + 12);
|
|
bytes.writeUInt32LE(section.bytes, at + 16);
|
|
bytes.writeUInt32LE(bytes.length, at + 20);
|
|
bytes = Buffer.concat([bytes, Buffer.alloc(section.bytes)]);
|
|
}
|
|
const path = join(root, `${name}.exe`);
|
|
await writeFile(path, bytes);
|
|
if (expectedOffset === null) {
|
|
await expectPeInputFailureAcrossAdapters({
|
|
cli,
|
|
call,
|
|
path,
|
|
reason: "invalid_format",
|
|
});
|
|
continue;
|
|
}
|
|
const result = await runFileCli(cli, {
|
|
arguments: ["inspect-pe-resources", path, "--json"],
|
|
});
|
|
expect(result.exitCode, name).toBe(0);
|
|
const evidence = contract.outputSchema.parse(result.json);
|
|
const response = await call({ path });
|
|
expect(response.isError, name).not.toBe(true);
|
|
const mcp = contract.outputSchema.parse(response.structuredContent);
|
|
expect(mcp.subject).toEqual(evidence.subject);
|
|
expect(mcp.evidence_id).toBe(evidence.evidence_id);
|
|
expect(mcp.normalized_result).toEqual(evidence.normalized_result);
|
|
expect(evidence.normalized_result).toMatchObject({
|
|
coverage: { status: "complete", resources: 1 },
|
|
resources: [
|
|
{
|
|
payload: {
|
|
location: {
|
|
offset:
|
|
expectedOffset === "original"
|
|
? originalPayloadOffset
|
|
: expectedOffset,
|
|
bytes: payloadBytes,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
expect(await readFile(path)).toEqual(bytes);
|
|
}
|
|
};
|
|
|
|
const expectPeInventoriesAcrossAdapters = async (
|
|
cli: TestCli,
|
|
call: PeResourceCall,
|
|
root: string,
|
|
): Promise<void> => {
|
|
for (const [plus, empty] of [
|
|
[false, false],
|
|
[true, false],
|
|
[false, true],
|
|
[true, true],
|
|
]) {
|
|
const fixture = peResourceFixture(plus);
|
|
const virtualSize = fixture.bytes.readUInt32LE(fixture.sectionAt + 8);
|
|
if (empty) {
|
|
fixture.bytes.writeUInt32LE(0x2000 + virtualSize, fixture.dataOffsets[0]);
|
|
fixture.bytes.writeUInt32LE(0, (fixture.dataOffsets[0] ?? 0) + 4);
|
|
}
|
|
const path = join(
|
|
root,
|
|
`resource${plus ? "64" : "32"}${empty ? "-empty" : ""}.exe`,
|
|
);
|
|
await writeFile(path, fixture.bytes);
|
|
const invocation = {
|
|
arguments: ["inspect-pe-resources", path, "--json"],
|
|
};
|
|
// Keep an independent public-wrapper process for both PE32 and PE32+.
|
|
// The empty-payload variants reuse only compiled-command startup.
|
|
const result = await (empty
|
|
? runFileCli(cli, invocation)
|
|
: cli.run(invocation));
|
|
expect(result.exitCode).toBe(0);
|
|
const evidence = contract.outputSchema.parse(result.json);
|
|
const report = peResourcesSchema.parse(evidence.normalized_result);
|
|
expect(evidence.subject?.digest).toMatchObject({
|
|
sha256: createHash("sha256").update(fixture.bytes).digest("hex"),
|
|
});
|
|
expect(evidence.subject?.architecture).toBe(plus ? "x86_64" : "x86");
|
|
expect(report.coverage).toMatchObject({
|
|
status: "complete",
|
|
resources: 5,
|
|
});
|
|
expect(report.resources[0]?.payload.sha256).toBe(
|
|
createHash("sha256")
|
|
.update(empty ? "" : "ICON")
|
|
.digest("hex"),
|
|
);
|
|
if (empty)
|
|
expect(report.resources[0]?.payload.location).toEqual({
|
|
offset: 0x400 + virtualSize,
|
|
bytes: 0,
|
|
});
|
|
expect(
|
|
report.resources.find(({ name }) => name.kind === "name")?.name,
|
|
).toMatchObject({ kind: "name", name: "7", utf16le_hex: "3700" });
|
|
expect(report.icon_groups[0]?.images).toMatchObject([
|
|
{
|
|
resource_id: 1,
|
|
candidate_resource_indices: [0, 1],
|
|
same_language_resource_index: 0,
|
|
},
|
|
{
|
|
resource_id: 99,
|
|
candidate_resource_indices: [],
|
|
same_language_resource_index: null,
|
|
},
|
|
]);
|
|
const response = await call({ path });
|
|
expect(response.isError).not.toBe(true);
|
|
const mcp = contract.outputSchema.parse(response.structuredContent);
|
|
expect(mcp.subject).toEqual(evidence.subject);
|
|
expect(mcp.evidence_id).toBe(evidence.evidence_id);
|
|
expect(mcp.normalized_result).toEqual(evidence.normalized_result);
|
|
const text = response.content.find(({ type }) => type === "text");
|
|
if (text?.type !== "text") throw new Error("Missing MCP text Evidence");
|
|
expect(contract.outputSchema.parse(JSON.parse(text.text)).evidence_id).toBe(
|
|
evidence.evidence_id,
|
|
);
|
|
expect(await readFile(path)).toEqual(fixture.bytes);
|
|
}
|
|
};
|
|
|
|
cliTest(
|
|
"inspects PE32/PE32+ resources through compiled CLI and real stdio MCP without an active target",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-pe-resource-acceptance-");
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [resolve("scripts/rea.mjs"), "mcp"],
|
|
cwd: process.cwd(),
|
|
env: { PATH: process.env.PATH ?? "", REA_LOG_LEVEL: "silent" },
|
|
stderr: "pipe",
|
|
});
|
|
const client = new Client({ name: "pe-resource-acceptance", version: "1" });
|
|
try {
|
|
await client.connect(transport);
|
|
const inventory = await client.listTools();
|
|
const definition = inventory.tools.find(
|
|
({ name }) => name === contract.name,
|
|
);
|
|
if (definition === undefined)
|
|
throw new Error("Missing PE resource tool contract");
|
|
expect(inventory.tools).toContainEqual(
|
|
expect.objectContaining({
|
|
name: contract.name,
|
|
annotations: expect.objectContaining({
|
|
readOnlyHint: false,
|
|
openWorldHint: false,
|
|
}),
|
|
}),
|
|
);
|
|
const call: PeResourceCall = (arguments_) =>
|
|
client.callTool(
|
|
{ name: definition.name, arguments: arguments_ },
|
|
{ toolDefinition: definition },
|
|
);
|
|
const sessionDefinition = inventory.tools.find(
|
|
({ name }) => name === "binary_session",
|
|
);
|
|
if (sessionDefinition === undefined)
|
|
throw new Error("Missing binary_session tool contract");
|
|
const session = await client.callTool(
|
|
{ name: sessionDefinition.name, arguments: {} },
|
|
{ toolDefinition: sessionDefinition },
|
|
);
|
|
expect(JSON.stringify(session.structuredContent)).toContain(
|
|
"inspect_pe_resources",
|
|
);
|
|
await expectPeInventoriesAcrossAdapters(cli, call, root);
|
|
await expectPeWordAlignedRecordsAcrossAdapters({
|
|
cli,
|
|
call,
|
|
root,
|
|
});
|
|
await expectPeMappingOwnershipAcrossAdapters(cli, call, root);
|
|
await expectPePaddingFailureAcrossAdapters({
|
|
cli,
|
|
call,
|
|
path: join(root, "raw-padding.exe"),
|
|
});
|
|
await expectPeInputFailuresAcrossAdapters({
|
|
cli,
|
|
call,
|
|
root,
|
|
});
|
|
const absent = peResourceFixture();
|
|
absent.bytes.fill(0, absent.directoryAt, absent.directoryAt + 8);
|
|
const path = join(root, "absent.exe");
|
|
await writeFile(path, absent.bytes);
|
|
const empty = await call({ path });
|
|
expect(empty.isError).not.toBe(true);
|
|
expect(
|
|
contract.outputSchema.parse(empty.structuredContent).normalized_result,
|
|
).toMatchObject({
|
|
directory: null,
|
|
resources: [],
|
|
coverage: { status: "complete", resources: 0 },
|
|
});
|
|
for (const arguments_ of [
|
|
{ path, max_file_bytes: 64 },
|
|
{ path: "relative.exe" },
|
|
{ path, extra: true },
|
|
]) {
|
|
const rejected = await call(arguments_);
|
|
expect(rejected.isError).toBe(true);
|
|
expect(
|
|
contract.outputSchema.safeParse(rejected.structuredContent).success,
|
|
).toBe(false);
|
|
}
|
|
const damaged = peResourceFixture();
|
|
damaged.bytes.writeUInt32LE(17, damaged.directoryAt + 4);
|
|
const badPath = join(root, "damaged.exe");
|
|
await writeFile(badPath, damaged.bytes);
|
|
const rejected = await call({ path: badPath });
|
|
expect(rejected.isError).toBe(true);
|
|
expect(
|
|
contract.outputSchema.safeParse(rejected.structuredContent).success,
|
|
).toBe(false);
|
|
await client.ping();
|
|
} finally {
|
|
try {
|
|
await client.close();
|
|
} finally {
|
|
await transport.close();
|
|
}
|
|
}
|
|
},
|
|
30_000,
|
|
);
|