Files
reverse-engineering-anything/tests/acceptance/inesContainer.test.ts
T
morluto 60149282fc test: strengthen integration oracles and verification (#8295)
* 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
2026-11-01 00:15:28 +08:00

314 lines
11 KiB
TypeScript

import { createHash } from "node:crypto";
import { readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { artifactInspectionResultSchema } from "../../src/domain/artifactInspection.js";
import {
artifactInventoryResultSchema,
artifactExtractionResultSchema,
} from "../../src/domain/artifactGraph.js";
import { analysisViewResultSchema } from "../../src/domain/analysisView/analysisView.js";
import { parseEvidence } from "../../src/domain/evidence.js";
import { cliTest } from "../support/cli/cliFixture.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
import { parseMcpToolError } from "../fixtures/mcpToolError.js";
import { inesFixture } from "../fixtures/ines.js";
import { writeOrderedZip } from "../fixtures/artifactEntryOrder.js";
import { ZIP_PACKAGE_FORMATS } from "../../src/domain/zipPackageFormat.js";
import { toolContract } from "../../src/contracts/toolContracts.js";
import { buildBinary } from "plist";
cliTest(
"refuses extraction after an already open plist is replaced through MCP",
async () => {
const root = await createTestTempDirectory("rea-ines-plist-refresh-");
const path = join(root, "source.bin");
await writeFile(path, buildBinary({ value: "old" }));
const { call } = await connectLocalToolsMcp();
const opened = await call("open_binary", { path });
expect(opened.isError, JSON.stringify(opened.structuredContent)).not.toBe(
true,
);
expect(
toolContract("open_binary").outputSchema.parse(opened.structuredContent)
.result,
).toMatchObject({ format: "plist" });
const bytes = inesFixture();
await writeFile(path, bytes);
const extracted = await call("extract_artifact", {});
expect(extracted.isError).toBe(true);
expect(JSON.stringify(parseMcpToolError(extracted))).toContain(
"Artifact format has no extraction reader: plist",
);
await call("close_binary", {});
},
);
cliTest(
"refreshes an iNES path through MCP for every ZIP package family",
async () => {
const root = await createTestTempDirectory("rea-ines-zip-refresh-");
const { call } = await connectLocalToolsMcp();
for (const format of ZIP_PACKAGE_FORMATS) {
const path = join(
root,
`cartridge.${format === "app-pack" ? "app" : format}`,
);
await writeFile(path, inesFixture());
const first = await call("open_binary", { path });
expect(first.isError, JSON.stringify(first)).not.toBe(true);
await writeOrderedZip(path, ["payload.txt"]);
const refreshed = await call("open_binary", { path });
expect(
refreshed.isError,
JSON.stringify({ format, response: refreshed }),
).not.toBe(true);
expect(
toolContract("open_binary").outputSchema.parse(
refreshed.structuredContent,
).result,
).toMatchObject({ kind: "archive", format });
const session = await call("binary_session", {});
expect(
session.isError,
JSON.stringify(session.structuredContent),
).not.toBe(true);
expect(
toolContract("binary_session").outputSchema.parse(
session.structuredContent,
).result,
).toMatchObject({ open: true, kind: "archive", format });
}
},
);
const inventoryFrom = (input: unknown) => {
const evidence = parseEvidence(input);
expect(evidence.subject).toMatchObject({
format: "ines",
architecture: null,
});
const inspection = artifactInspectionResultSchema.parse(
evidence.normalized_result,
);
expect(inspection.coverage.status).toBe("complete-within-substeps");
expect(inspection.observations.map(({ kind }) => kind)).toEqual([
"root-manifest",
"container-header",
"reconstruction",
]);
const substep = inspection.substeps[0];
if (substep === undefined) throw new Error("Missing inventory substep");
parseEvidence(substep.evidence);
const inventory = artifactInventoryResultSchema.parse(
substep.evidence.normalized_result,
);
expect(inventory.coverage.status).toBe("complete");
expect(inventory.limitations).toContainEqual(
expect.stringContaining("CPU bank mappings"),
);
return inventory;
};
cliTest(
"classic iNES has the same complete byte inventory through compiled CLI and stdio MCP",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-ines-public-");
const path = join(root, "卡带.hop");
const bytes = inesFixture({
trainer: true,
trailing: Buffer.from([0, 255, 3, 0]),
});
await writeFile(path, bytes);
const cliResult = await cli.run({
arguments: ["inspect-artifact", path, "--json"],
});
expect(cliResult.exitCode, cliResult.stderr).toBe(0);
const inventory = inventoryFrom(cliResult.json);
const digest = createHash("sha256").update(bytes).digest("hex");
expect(inventory.ines).toMatchObject({
header: {
header_hex: bytes.subarray(0, 16).toString("hex"),
mapper: 19,
trainer_present: true,
prg_rom_units_16k: 2,
chr_rom_units_8k: 1,
},
reconstruction: { bytes: bytes.length, sha256: digest, verified: true },
});
const expected = [
["header.bin", 0, 16],
["trainer.bin", 16, 512],
["prg/000.bin", 528, 16_384],
["prg/001.bin", 16_912, 16_384],
["chr/000.bin", 33_296, 8_192],
["trailing.bin", 41_488, 4],
] as const;
const nodes = new Map(
inventory.nodes.map((node) => [node.artifact_id, node]),
);
for (const [logical_path, offset, length] of expected) {
const occurrence = inventory.occurrences.find(
(item) => item.logical_path === logical_path,
);
if (
occurrence?.artifact_id === undefined ||
occurrence.artifact_id === null
)
throw new Error(`Missing region ${logical_path}`);
expect(occurrence.source_location).toEqual({ offset, length });
expect(nodes.get(occurrence.artifact_id)?.sha256).toBe(
createHash("sha256")
.update(bytes.subarray(offset, offset + length))
.digest("hex"),
);
expect(nodes.get(occurrence.artifact_id)?.size).toBe(length);
if (logical_path === "header.bin") {
expect(nodes.get(occurrence.artifact_id)?.format).toBe("file");
}
}
expect(inventory.ines?.reconstruction.region_order).toEqual(
expected.map(([logicalPath]) => logicalPath),
);
const { call } = await connectLocalToolsMcp();
const opened = await call("open_binary", { path });
if (opened.isError) throw new Error(JSON.stringify(opened));
const inspected = await call("inspect_artifact", {});
expect(
inspected.isError,
JSON.stringify(inspected.structuredContent),
).not.toBe(true);
expect(inventoryFrom(inspected.structuredContent)).toEqual(inventory);
const typed = artifactInspectionResultSchema.parse(
parseEvidence(inspected.structuredContent).normalized_result,
);
expect(typed.substeps[0]?.evidence.normalized_result).toMatchObject({
ines: inventory.ines,
});
const withInventory = (normalized_result: unknown) => ({
...typed,
substeps: typed.substeps.map((substep) => ({
...substep,
evidence: { ...substep.evidence, normalized_result },
})),
});
expect(
artifactInspectionResultSchema.safeParse(
withInventory({ ...inventory, ines: undefined }),
).success,
).toBe(false);
const withoutInes = { ...inventory };
delete withoutInes.ines;
expect(
artifactInspectionResultSchema.safeParse(withInventory(withoutInes))
.success,
).toBe(true);
const summary = await call("inspect_artifact", { detail: "summary" });
expect(summary.isError, JSON.stringify(summary.structuredContent)).not.toBe(
true,
);
const view = analysisViewResultSchema.parse(
parseEvidence(summary.structuredContent).normalized_result,
);
expect(view.kind).toBe("summary");
const regions = await call("inspect_analysis_view", {
source: {
kind: "retained-evidence",
evidence_id: view.parent_evidence_id,
},
view: {
kind: "inventory",
collection: "occurrences",
logical_paths: ["prg/000.bin"],
},
});
expect(regions.isError, JSON.stringify(regions.structuredContent)).not.toBe(
true,
);
expect(
parseEvidence(regions.structuredContent).normalized_result,
).toMatchObject({
kind: "inventory",
items: inventory.occurrences.filter(
(item) => item.logical_path === "prg/000.bin",
),
});
const extracted = await call("extract_artifact", {});
expect(
extracted.isError,
JSON.stringify(extracted.structuredContent),
).not.toBe(true);
const extraction = artifactExtractionResultSchema.parse(
parseEvidence(extracted.structuredContent).normalized_result,
);
try {
expect(extraction.artifacts).toHaveLength(expected.length);
const reconstructed = Buffer.concat(
await Promise.all(
expected.map(([region]) =>
readFile(join(extraction.output_root, region)),
),
),
);
expect(reconstructed.equals(bytes)).toBe(true);
} finally {
// The successful extraction transfers this exact output directory to the caller.
await rm(extraction.output_root, { recursive: true, force: true });
}
await call("close_binary", {});
expect((await readFile(path)).equals(bytes)).toBe(true);
},
);
cliTest(
"unsupported NES containers fail explicitly and leave a valid MCP session usable",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-ines-public-refusal-");
const validPath = join(root, "valid.nes");
await writeFile(validPath, inesFixture({ chrUnits: 0 }));
const { call } = await connectLocalToolsMcp();
const opened = await call("open_binary", { path: validPath });
if (opened.isError) throw new Error(JSON.stringify(opened));
for (const [name, bytes, reason] of [
["truncated", inesFixture().subarray(0, 20), "truncated iNES payload"],
[
"nes2",
(() => {
const bytes = inesFixture();
bytes[7] = 8;
return bytes;
})(),
"nes-2.0",
],
["unif", Buffer.from("UNIF"), "unif"],
] as const) {
const path = join(root, `${name}.nes`);
await writeFile(path, bytes);
const refused = await cli.run({
arguments: ["inspect-artifact", path, "--json"],
});
expect(refused.exitCode).not.toBe(0);
expect(JSON.stringify(refused.json)).toContain(reason);
const switched = await call("open_binary", { path });
expect(switched.isError).toBe(true);
expect(JSON.stringify(parseMcpToolError(switched))).toContain(reason);
}
const retained = await call("inspect_artifact", {});
expect(
retained.isError,
JSON.stringify(retained.structuredContent),
).not.toBe(true);
const inventory = inventoryFrom(retained.structuredContent);
expect(inventory.ines?.header.chr_rom_units_8k).toBe(0);
expect(
inventory.occurrences.some(({ logical_path }) =>
logical_path.startsWith("chr/"),
),
).toBe(false);
await call("close_binary", {});
},
);