mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
fix(verify): restore owned firmware fixture hashing
Replace the removed hashFirmwareFile export with shared stable verifier hashing. Keep hashing under the file scope and close MCP/file owners independently before removing their fixture parent. Preserve the primary failure if cleanup also fails. The actual firmware entrypoint now reaches its prerequisite gate; descriptor retry and mixed-cleanup controls pass. Real Linux firmware-engine qualification was not run here. Refs #4912.
This commit is contained in:
@@ -9,7 +9,9 @@ import { Client } from "@modelcontextprotocol/client";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
||||
import { firmwareResultSchemas } from "../../../dist/domain/firmware/firmwareAnalysis.js";
|
||||
import { parseEvidence } from "../../../dist/domain/evidence.js";
|
||||
import { hashFirmwareFile } from "../../../dist/firmware/FirmwareFiles.js";
|
||||
import { ArtifactResourceScope } from "../../../dist/artifacts/ArtifactResourceScope.js";
|
||||
import { hashVerifierFile } from "../../lib/verifier-file-resources.mjs";
|
||||
import { closeVerifierResources } from "../../lib/verifier-cleanup.mjs";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const { join, resolve, dirname } = nodePath;
|
||||
@@ -79,7 +81,7 @@ const oracle = JSON.parse(
|
||||
await fs.readFile(join(FIXTURE_ROOT, "oracle.json"), "utf8"),
|
||||
);
|
||||
const firmwarePath = join(FIXTURE_ROOT, "firmware.bin");
|
||||
assert.equal(await hashFirmwareFile(firmwarePath), oracle.sha256);
|
||||
const fileResources = new ArtifactResourceScope();
|
||||
|
||||
const workDir = await fs.mkdtemp(join(tmpdir(), "rea-real-firmware-"));
|
||||
const baseEnv = Object.fromEntries(
|
||||
@@ -160,7 +162,10 @@ async function verifyFiles(evidence) {
|
||||
assert.ok(entry !== undefined, `Missing extracted ${suffix}`);
|
||||
assert.equal(entry.sha256, expected.sha256);
|
||||
assert.equal(entry.size, expected.size);
|
||||
assert.equal(await hashFirmwareFile(entry.path), expected.sha256);
|
||||
assert.equal(
|
||||
(await hashVerifierFile(entry.path, fileResources)).sha256,
|
||||
expected.sha256,
|
||||
);
|
||||
assert.equal(entry.original_file_range, null);
|
||||
assert.equal(entry.runtime_address, null);
|
||||
}
|
||||
@@ -371,7 +376,12 @@ async function stageGhidra(mcpFiles) {
|
||||
// Entry point
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
let primaryError;
|
||||
try {
|
||||
assert.equal(
|
||||
(await hashVerifierFile(firmwarePath, fileResources)).sha256,
|
||||
oracle.sha256,
|
||||
);
|
||||
const cli = await stageCli();
|
||||
await connectMcp();
|
||||
const mcpFiles = await stageMcp(cli);
|
||||
@@ -381,11 +391,24 @@ try {
|
||||
await stageGhidra(mcpFiles);
|
||||
|
||||
assert.equal(
|
||||
await hashFirmwareFile(firmwarePath),
|
||||
(await hashVerifierFile(firmwarePath, fileResources)).sha256,
|
||||
oracle.sha256,
|
||||
"Original firmware bytes must remain unchanged",
|
||||
);
|
||||
} catch (cause) {
|
||||
primaryError = cause;
|
||||
throw cause;
|
||||
} finally {
|
||||
await mcpClient.close();
|
||||
await fs.rm(workDir, { recursive: true, force: true });
|
||||
await closeVerifierResources(
|
||||
[
|
||||
async () => {
|
||||
await closeVerifierResources([
|
||||
() => mcpClient.close(),
|
||||
() => fileResources.close(),
|
||||
]);
|
||||
await fs.rm(workDir, { recursive: true, force: true });
|
||||
},
|
||||
],
|
||||
primaryError,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,25 @@ it("Ghidra verifier probes await the shared owned inspection contract", async ()
|
||||
expect(violations).toEqual([]);
|
||||
});
|
||||
|
||||
it("firmware verifier loads its current hash API before reporting unavailable prerequisites", () => {
|
||||
const result = spawnSync(
|
||||
process.execPath,
|
||||
["scripts/verify/firmware/analysis.mjs"],
|
||||
{
|
||||
encoding: "utf8",
|
||||
timeout: 10_000,
|
||||
env: { PATH: process.env.PATH ?? "" },
|
||||
},
|
||||
);
|
||||
expect(result.status).toBe(1);
|
||||
expect(result.stderr).toContain(
|
||||
process.platform === "linux"
|
||||
? "requires REA_BINWALK_COMMAND"
|
||||
: "requires Linux",
|
||||
);
|
||||
expect(result.stderr).not.toContain("does not provide an export");
|
||||
});
|
||||
|
||||
it.each(["late-close", "retry-close", "retained-close", "opaque-cancellation"])(
|
||||
"owns Ghidra verifier prerequisite finalization: %s",
|
||||
async (mode) => {
|
||||
|
||||
Reference in New Issue
Block a user