Files
reverse-engineering-anything/tests/acceptance/hexRecordsCli.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

181 lines
6.1 KiB
TypeScript

import { readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, onTestFinished } from "vitest";
import { cliTest } from "../support/cli/cliFixture.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import {
INTEL_HEX_I32_GAP,
intelHexRecord,
SREC_S19,
} from "../../src/domain/firmware/hexRecords.fixture.js";
import { parseEvidence } from "../../src/domain/evidence.js";
import { artifactInspectionResultSchema } from "../../src/domain/artifactInspection.js";
import {
artifactExtractionResultSchema,
artifactInventoryResultSchema,
} from "../../src/domain/artifactGraph.js";
const cases = [
{
encoding: "intel-hex",
name: "firmware.hex",
text: INTEL_HEX_I32_GAP,
root: { variant: "I32HEX", start_address: 0x0800_0101 },
regions: {
"0x08000000-0x0800001f.bin": Buffer.from(
Array.from({ length: 32 }, (_, index) => index),
),
"0x08000100-0x08000103.bin": Buffer.from("deadbeef", "hex"),
},
},
{
encoding: "srec",
name: "firmware.s19",
text: SREC_S19,
root: { variant: "S19", header_text: "HDR", start_address_record: "S9" },
regions: {
"0x00000000-0x0000001f.bin": Buffer.from(
Array.from({ length: 32 }, (_, index) => index),
),
},
},
] as const;
cliTest.for(cases)(
"inventories and extracts $encoding regions through the compiled CLI",
async ({ encoding, name, text, root, regions }, { cli }) => {
const directory = await createTestTempDirectory("rea-hex-cli-");
const source = join(directory, name);
await writeFile(source, text);
const inspected = await cli.run({
arguments: ["inspect-artifact", source, "--json"],
});
expect(inspected.exitCode, inspected.stdout + inspected.stderr).toBe(0);
const inspection = artifactInspectionResultSchema.parse(
parseEvidence(inspected.json).normalized_result,
);
const graph = artifactInventoryResultSchema.parse(
inspection.substeps[0]?.evidence.normalized_result,
);
expect(graph.manifest.root_format).toBe(encoding);
expect(graph.coverage.status).toBe("complete");
expect(
graph.occurrences.find((row) => row.logical_path === ".")
?.format_metadata,
).toMatchObject({ kind: "hex-records", encoding, ...root });
expect(
graph.occurrences
.filter((row) => row.logical_path !== ".")
.map((row) => row.logical_path),
).toEqual(Object.keys(regions));
if (encoding === "intel-hex") {
expect(graph.coverage.scope).toBe("container-entries");
expect(graph.limitations).toContain(
"Intel HEX/S-record inventory decodes data records into address-contiguous regions. It does not establish CPU, byte order, memory map, or that a declared start address is executable; gaps are unwritten, not zero.",
);
expect(
graph.occurrences.find((row) => row.logical_path === "."),
).toMatchObject({
artifact_kind: "container",
format_metadata: { region_count: 2 },
});
expect(
graph.occurrences
.filter((row) => row.logical_path !== ".")
.map((row) => [
row.logical_path,
row.declared_size,
row.format_metadata,
]),
).toEqual([
[
"0x08000000-0x0800001f.bin",
32,
{
kind: "hex-record-region",
start_address: 0x0800_0000,
end_address: 0x0800_001f,
length: 32,
record_count: 2,
first_line: 2,
last_line: 3,
},
],
[
"0x08000100-0x08000103.bin",
4,
{
kind: "hex-record-region",
start_address: 0x0800_0100,
end_address: 0x0800_0103,
length: 4,
record_count: 1,
first_line: 4,
last_line: 4,
},
],
]);
}
expect(inspection.next_probes.map((probe) => probe.operation)).toEqual([
"open_binary",
]);
const extracted = await cli.run({
arguments: ["extract-artifact", source, "--json"],
environment: { TMPDIR: directory, TMP: directory, TEMP: directory },
});
expect(extracted.exitCode, extracted.stdout + extracted.stderr).toBe(0);
const result = artifactExtractionResultSchema.parse(
parseEvidence(extracted.json).normalized_result,
);
onTestFinished(() =>
rm(result.output_root, { recursive: true, force: true }),
);
expect(result.containment_verified).toBe(true);
for (const [path, bytes] of Object.entries(regions))
expect(
Buffer.compare(await readFile(join(result.output_root, path)), bytes),
).toBe(0);
},
);
cliTest("rejects a malformed record through the CLI", async ({ cli }) => {
const directory = await createTestTempDirectory("rea-hex-invalid-cli-");
const source = join(directory, "firmware.hex");
await writeFile(source, INTEL_HEX_I32_GAP.replace("BEEFC3", "BEEFC4"));
const result = await cli.run({
arguments: ["inspect-artifact", source, "--json"],
});
expect(result.exitCode).not.toBe(0);
expect(result.json).toMatchObject({
code: "artifact_operation_failed",
details: { operation: "inspect_artifact", reason: "format" },
});
expect(result.stdout + result.stderr).toContain(
"Intel HEX is malformed: line 4: record type 00 checksum 0xc4 does not match computed 0xc3",
);
});
cliTest.for([3, 5])(
"rejects reserved offsets in Intel HEX start record %i through the CLI",
async (type, { cli }) => {
const directory = await createTestTempDirectory("rea-hex-start-cli-");
const source = join(directory, "firmware.hex");
await writeFile(
source,
[
intelHexRecord(0, 0x20, [0xa5]),
intelHexRecord(type, 0x1234, [0, 0, 0, 1]),
intelHexRecord(1, 0),
].join("\n"),
);
const result = await cli.run({
arguments: ["inspect-artifact", source, "--json"],
});
expect(result.exitCode).toBe(1);
expect(result.json).toMatchObject({
code: "artifact_operation_failed",
details: { operation: "inspect_artifact", reason: "format" },
});
},
);