mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 19:23:24 +00:00
refactor(verify): give the failure-retaining Ghidra lanes' workspaces to VerifierFixture (#11097)
The m68k, MIPS, MIPS16 shared, MIPS relocatable, PowerPC, RISC-V and DOL lanes kept their mkdtemp workspace for diagnosis whenever verification or cleanup failed, and removed it with rm after success. VerifierFixture now allocates the workspace (a plain root: Ghidra children use it as TMPDIR). Every failure branch that names the retained workspace records that reason with fixture.retain, and success releases the fixture. The verifier-fixture-root baseline shrinks by 7.
This commit is contained in:
1 parent
5b5ca68bb3
commit
0b95e55655
8 files changed
+139
-77
No files matched your search
@@ -1,8 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { readFile, mkdtemp, mkdir, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { readFile, mkdir } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
@@ -34,6 +33,7 @@ import {
|
||||
assertVerifierCleanupComplete,
|
||||
} from "./lib/verifier-run.mjs";
|
||||
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
// Optional cross-target lane. No tool acquisition and no target execution.
|
||||
if (process.argv.length !== 2)
|
||||
@@ -59,7 +59,17 @@ if (installation.status !== "available")
|
||||
const execute = promisify(execFile);
|
||||
const entrypoint = fileURLToPath(new URL("./rea.mjs", import.meta.url));
|
||||
const run = createVerifierRun();
|
||||
const workspace = await mkdtemp(join(tmpdir(), "rea-dol-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-dol-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const baseEnv = {
|
||||
@@ -309,11 +319,11 @@ try {
|
||||
},
|
||||
]);
|
||||
} catch (cause) {
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`GameCube DOL verification failed; retained workspace: ${workspace}`,
|
||||
{ cause },
|
||||
);
|
||||
}
|
||||
assert.ok(completed, "Verifier completion was not observed");
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
await workspaceFixture.release();
|
||||
console.log(JSON.stringify({ ...completed, fixtures: reports }, null, 2));
|
||||
@@ -1,14 +1,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import {
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
readFile,
|
||||
readdir,
|
||||
rm,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
@@ -21,6 +14,7 @@ import {
|
||||
requireMcpOutput,
|
||||
} from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
if (process.argv.length !== 2)
|
||||
throw new Error("Usage: node scripts/verify-real-ghidra-m68k.mjs");
|
||||
@@ -57,7 +51,18 @@ assert.equal(
|
||||
"7679358409efee4c5c2465f9a47158c4d49e0415ba12b3170898440db7ea0bc9",
|
||||
);
|
||||
await mkdir(join(root, "build"), { recursive: true });
|
||||
const workspace = await mkdtemp(join(root, "build", "rea-m68k-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-m68k-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
parent: join(root, "build"),
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const path = join(workspace, "image.bin");
|
||||
@@ -257,6 +262,9 @@ try {
|
||||
};
|
||||
} catch (cause) {
|
||||
if (stderr) process.stderr.write(stderr);
|
||||
workspaceFixture.retain(
|
||||
`m68k verification failed; retained workspace: ${workspace}`,
|
||||
);
|
||||
throw cause;
|
||||
} finally {
|
||||
try {
|
||||
@@ -265,16 +273,20 @@ try {
|
||||
await transport.close();
|
||||
}
|
||||
}
|
||||
assert.deepEqual(
|
||||
await readdir(runtime),
|
||||
[],
|
||||
`Runtime resources survived server shutdown; retained workspace: ${workspace}`,
|
||||
);
|
||||
const survivors = await readdir(runtime);
|
||||
if (survivors.length > 0)
|
||||
throw retainWorkspace(
|
||||
`Runtime resources survived server shutdown (${survivors.join(", ")}); retained workspace: ${workspace}`,
|
||||
);
|
||||
const verifierRun = await completeVerifierRun(run);
|
||||
assert.equal(verifierRun.process_lineage.status, "verified");
|
||||
assert.deepEqual(verifierRun.process_lineage.descendants, []);
|
||||
// Keep the workspace for diagnosis unless verification and cleanup both pass.
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
if (
|
||||
verifierRun.process_lineage.status !== "verified" ||
|
||||
verifierRun.process_lineage.descendants.length !== 0
|
||||
)
|
||||
throw retainWorkspace(
|
||||
`Cleanup unverified; retained diagnostic workspace: ${workspace}`,
|
||||
);
|
||||
await workspaceFixture.release();
|
||||
process.stdout.write(
|
||||
JSON.stringify({ verifier_run: verifierRun, ...report }) + "\n",
|
||||
);
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdtemp, mkdir, readFile, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { mkdir, readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
@@ -21,6 +20,7 @@ import {
|
||||
} from "../tests/conformance/ghidra/mips-relocatable-checks.mjs";
|
||||
import { requireMcpOperationResult } from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
// Optional cross-target lane for ET_REL objects. No tool acquisition, no
|
||||
// linking and no target execution.
|
||||
@@ -48,7 +48,17 @@ if (installation.status !== "available")
|
||||
const execute = promisify(execFile);
|
||||
const entrypoint = fileURLToPath(new URL("./rea.mjs", import.meta.url));
|
||||
const run = createVerifierRun();
|
||||
const workspace = await mkdtemp(join(tmpdir(), "rea-mips-rel-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-mips-rel-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const env = {
|
||||
@@ -320,14 +330,14 @@ if (
|
||||
completed.process_lineage.status !== "verified" ||
|
||||
completed.process_lineage.descendants.length !== 0
|
||||
)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`Cleanup unverified; retained diagnostic workspace: ${workspace}`,
|
||||
{ cause: primaryFailure },
|
||||
);
|
||||
if (primaryFailure !== undefined)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`MIPS relocatable verification failed; retained workspace: ${workspace}`,
|
||||
{ cause: primaryFailure },
|
||||
);
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
await workspaceFixture.release();
|
||||
console.log(JSON.stringify({ ...completed, fixtures: reports }, null, 2));
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { Client } from "@modelcontextprotocol/client";
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
requireMcpToolError,
|
||||
} from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
if (
|
||||
process.env.GHIDRA_INSTALL_DIR === undefined ||
|
||||
@@ -26,7 +26,17 @@ if (
|
||||
);
|
||||
const execute = promisify(execFile);
|
||||
const run = createVerifierRun();
|
||||
const workspace = await mkdtemp(join(tmpdir(), "rea-mips-shared-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-mips-shared-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const env = {
|
||||
@@ -328,13 +338,16 @@ if (
|
||||
completed.process_lineage.status !== "verified" ||
|
||||
completed.process_lineage.descendants.length !== 0
|
||||
)
|
||||
throw new Error(`Cleanup unverified; retained workspace: ${workspace}`, {
|
||||
cause: failure,
|
||||
});
|
||||
throw retainWorkspace(
|
||||
`Cleanup unverified; retained workspace: ${workspace}`,
|
||||
{
|
||||
cause: failure,
|
||||
},
|
||||
);
|
||||
if (failure !== undefined)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`MIPS16 shared verification failed; retained workspace: ${workspace}`,
|
||||
{ cause: failure },
|
||||
);
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
await workspaceFixture.release();
|
||||
console.log(JSON.stringify({ ...completed, fixtures: reports }, null, 2));
|
||||
@@ -3,15 +3,12 @@ import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import {
|
||||
mkdtemp,
|
||||
mkdir,
|
||||
readFile,
|
||||
readdir,
|
||||
realpath,
|
||||
rm,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, join, relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
@@ -48,6 +45,7 @@ import {
|
||||
} from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { runOwnedCommand } from "../dist/process/OwnedCommand.js";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
// Optional cross-target lane. No tool acquisition and no target execution.
|
||||
const mode = process.argv[2];
|
||||
@@ -78,7 +76,17 @@ if (installation.status !== "available")
|
||||
const execute = promisify(execFile);
|
||||
const entrypoint = fileURLToPath(new URL("./rea.mjs", import.meta.url));
|
||||
const run = createVerifierRun();
|
||||
const workspace = await mkdtemp(join(tmpdir(), "rea-mips-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-mips-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const env = {
|
||||
@@ -892,16 +900,16 @@ if (
|
||||
completed.process_lineage.status !== "verified" ||
|
||||
completed.process_lineage.descendants.length !== 0
|
||||
)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`Cleanup unverified; retained diagnostic workspace: ${workspace}`,
|
||||
{ cause: primaryFailure },
|
||||
);
|
||||
if (primaryFailure !== undefined)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`MIPS verification failed; retained workspace: ${workspace}`,
|
||||
{
|
||||
cause: primaryFailure,
|
||||
},
|
||||
);
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
await workspaceFixture.release();
|
||||
console.log(JSON.stringify({ ...completed, fixtures: reports }, null, 2));
|
||||
@@ -2,8 +2,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdtemp, mkdir, readFile, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { mkdir, readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
@@ -23,6 +22,7 @@ import { inspectVerifierGhidraInstallation } from "./lib/ghidra-installation-ins
|
||||
import { buildPowerPcFixture } from "../tests/conformance/ghidra/ppc-fixture.mjs";
|
||||
import { requireMcpOperationResult } from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
// Optional cross-target lane. No tool acquisition and no target execution.
|
||||
if (process.argv.length !== 2)
|
||||
@@ -47,7 +47,17 @@ if (installation.status !== "available")
|
||||
const execute = promisify(execFile);
|
||||
const entrypoint = fileURLToPath(new URL("./rea.mjs", import.meta.url));
|
||||
const run = createVerifierRun();
|
||||
const workspace = await mkdtemp(join(tmpdir(), "rea-ppc-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-ppc-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const env = {
|
||||
@@ -303,16 +313,16 @@ if (
|
||||
completed.process_lineage.status !== "verified" ||
|
||||
completed.process_lineage.descendants.length !== 0
|
||||
)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`Cleanup unverified; retained diagnostic workspace: ${workspace}`,
|
||||
{ cause: primaryFailure },
|
||||
);
|
||||
if (primaryFailure !== undefined)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`PowerPC verification failed; retained workspace: ${workspace}`,
|
||||
{
|
||||
cause: primaryFailure,
|
||||
},
|
||||
);
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
await workspaceFixture.release();
|
||||
console.log(JSON.stringify({ ...completed, fixtures: reports }, null, 2));
|
||||
@@ -3,15 +3,7 @@ import { schemaVerifierEnvironment } from "./lib/mcp-verification-environment.mj
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import {
|
||||
mkdtemp,
|
||||
mkdir,
|
||||
readFile,
|
||||
readdir,
|
||||
rm,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
@@ -42,6 +34,7 @@ import {
|
||||
requireMcpToolError,
|
||||
} from "./lib/mcp-verifier-results.mjs";
|
||||
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
|
||||
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
|
||||
|
||||
if (process.argv.length !== 2)
|
||||
throw new Error("Usage: node scripts/verify-real-ghidra-riscv.mjs");
|
||||
@@ -67,7 +60,17 @@ assert.equal(installation.providerVersion, "12.1.4");
|
||||
const execute = promisify(execFile);
|
||||
const entrypoint = fileURLToPath(new URL("./rea.mjs", import.meta.url));
|
||||
const run = createVerifierRun();
|
||||
const workspace = await mkdtemp(join(tmpdir(), "rea-riscv-proof-"));
|
||||
const workspaceFixture = await VerifierFixture.open({
|
||||
prefix: "rea-riscv-proof-",
|
||||
// Ghidra children use the workspace as TMPDIR; a plain root admits them on every host.
|
||||
private: false,
|
||||
});
|
||||
const workspace = workspaceFixture.path;
|
||||
// A failed run keeps its workspace for diagnosis; the fixture records why.
|
||||
const retainWorkspace = (message, options) => {
|
||||
workspaceFixture.retain(message);
|
||||
return new Error(message, options);
|
||||
};
|
||||
const runtime = join(workspace, "runtime");
|
||||
await mkdir(runtime);
|
||||
const env = {
|
||||
@@ -563,20 +566,23 @@ if (
|
||||
completed.process_lineage.status !== "verified" ||
|
||||
completed.process_lineage.descendants.length !== 0
|
||||
)
|
||||
throw new Error(`Cleanup unverified; retained workspace: ${workspace}`, {
|
||||
cause: failure,
|
||||
});
|
||||
throw retainWorkspace(
|
||||
`Cleanup unverified; retained workspace: ${workspace}`,
|
||||
{
|
||||
cause: failure,
|
||||
},
|
||||
);
|
||||
if (failure !== undefined)
|
||||
throw new Error(
|
||||
throw retainWorkspace(
|
||||
`RISC-V verification failed; retained workspace: ${workspace}; MCP stderr: ${stderr}`,
|
||||
{ cause: failure },
|
||||
);
|
||||
assert.deepEqual(
|
||||
await readdir(runtime),
|
||||
[],
|
||||
`Runtime resources survived server shutdown; retained workspace: ${workspace}`,
|
||||
);
|
||||
await rm(workspace, { recursive: true, force: true });
|
||||
const survivors = await readdir(runtime);
|
||||
if (survivors.length > 0)
|
||||
throw retainWorkspace(
|
||||
`Runtime resources survived server shutdown (${survivors.join(", ")}); retained workspace: ${workspace}`,
|
||||
);
|
||||
await workspaceFixture.release();
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{
|
||||
|
||||
@@ -423,15 +423,8 @@
|
||||
"scripts/verify-real-cutter.mjs": 1,
|
||||
"scripts/verify-real-ghidra-address-context.mjs": 1,
|
||||
"scripts/verify-real-ghidra-checkpoints.mjs": 1,
|
||||
"scripts/verify-real-ghidra-dol.mjs": 1,
|
||||
"scripts/verify-real-ghidra-function-bundle.mjs": 1,
|
||||
"scripts/verify-real-ghidra-m68k.mjs": 1,
|
||||
"scripts/verify-real-ghidra-mips-relocatable.mjs": 1,
|
||||
"scripts/verify-real-ghidra-mips-shared.mjs": 1,
|
||||
"scripts/verify-real-ghidra-mips.mjs": 1,
|
||||
"scripts/verify-real-ghidra-ppc.mjs": 1,
|
||||
"scripts/verify-real-ghidra-project-coverage.mjs": 1,
|
||||
"scripts/verify-real-ghidra-riscv.mjs": 1,
|
||||
"scripts/verify-real-ghidra-swift.mjs": 1,
|
||||
"scripts/verify-real-ghidra-switch.mjs": 1,
|
||||
"scripts/verify-real-ghidra.mjs": 1,
|
||||
|
||||
Reference in new issue
Block a user