Files
rea/scripts/lib/verify-wabt-cleanup.mjs
T
morluto 72ba1cd92b fix(verifiers): centralize failure and cleanup ownership
Own operation results and exact rejections in withVerifierCleanup, including
undefined, null and independent cleanup failures. Remove the optional-primary
cleanup contract and migrate every caller, preserving returns, annotations,
signal restoration and dependent cleanup order.

Make Frida/JEB reporters fail on reasonless rejections and retain JEB fixture
files while provider cleanup is incomplete. Own the nested packaged WASM
verifier and expose its composite process/root cleanup capability for retry.
Update runnable docs and isolated fixture dependencies.

Validation: 547 focused cases in 20 files, eight isolated boundary unit checks,
static/build/docs/discovery gates and duplication check (3.58%). Node process,
SDK and descriptor cleanup are exercised; provider and packaging results in
orchestration tests are simulated. Pack/install subprocess ownership remains
with the existing shared package runner outside the nested-command change.
2026-10-24 15:38:35 +08:00

209 lines
7.2 KiB
JavaScript

import assert from "node:assert/strict";
import {
mkdtemp,
mkdir,
readFile,
writeFile,
readdir,
rm,
} from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import { execFile } from "node:child_process";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { requireMcpToolError } from "./mcp-verifier-results.mjs";
import { withVerifierCleanup } from "./verifier-cleanup.mjs";
import { WABT_OPERATION_TIMEOUT_MS } from "./wabt-verifier-timeouts.mjs";
const execute = promisify(execFile);
/** Real WABT inspection with authored cleanup denials and same-connection recovery. */
export async function verifyWabtCleanup(entrypoint, environment, parent) {
const root = await mkdtemp(join(parent, "wabt-cleanup-"));
return withVerifierCleanup(async () => {
const valid = join(root, "valid.wasm"),
invalid = join(root, "invalid.wasm");
await writeFile(
valid,
Buffer.from("0061736d01000000000a066f7061717565616263", "hex"),
);
await writeFile(invalid, Buffer.from("0061736d01000000ff", "hex"));
const preload = fileURLToPath(
new URL("../../tests/fixtures/wasm/cleanupPreload.mjs", import.meta.url),
);
const records = [];
async function setup(name, mode, input) {
const temporary = join(root, name);
await mkdir(temporary);
const trace = join(root, name + ".jsonl");
return {
temporary,
trace,
env: {
...environment,
HOME: root,
USERPROFILE: root,
REA_LOG_LEVEL: "silent",
TMPDIR: temporary,
TMP: temporary,
TEMP: temporary,
REA_CLEANUP_PROBE_ROOT: temporary,
REA_CLEANUP_PROBE_TRACE: trace,
REA_CLEANUP_PROBE_MODE: mode,
REA_CLEANUP_PROBE_INPUT: input,
},
};
}
async function observations(configuration) {
const trace = await readFile(configuration.trace, "utf8").catch((e) => {
if (e.code === "ENOENT") return "";
throw e;
});
return {
trace:
trace.trim() === "" ? [] : trace.trim().split("\n").map(JSON.parse),
remaining: await readdir(configuration.temporary),
};
}
for (const [name, mode, input] of [
["normal", "normal", valid],
["valid-recovered", "runtime-once", valid],
["invalid-recovered", "runtime-once", invalid],
["descriptor-recovered", "input-once", valid],
]) {
const c = await setup(name, mode, input);
let response,
status = 0;
try {
response = await execute(
process.execPath,
[
"--import",
preload,
entrypoint,
"inspect-wasm-artifact",
input,
"--json",
],
{
env: c.env,
timeout: WABT_OPERATION_TIMEOUT_MS,
maxBuffer: 64 * 1024 * 1024,
},
);
} catch (e) {
if (typeof e.code !== "number" || typeof e.stdout !== "string") throw e;
response = e;
status = e.code;
}
const output = JSON.parse(response.stdout);
const facts = await observations(c);
assert.deepEqual(facts.remaining, []);
if (mode === "normal") {
assert.equal(status, 0);
assert.equal(output.normalized_result.validation, "valid");
} else {
assert.equal(status, 1);
assert.equal(
output.code,
name === "valid-recovered" ? "execution_failure" : "invalid_request",
);
if (name === "valid-recovered") {
assert.equal(
output.details?.partial_observation?.normalized_result?.validation,
"valid",
);
assert.equal(
output.details?.partial_observation?.evidence_id,
records[0].output.evidence_id,
);
}
if (mode === "input-once") {
assert.equal(
output.details?.issues?.[0]?.message,
"authored descriptor cleanup denial",
);
const closes = facts.trace.filter(
(fact) => fact.kind === "input-close",
);
assert.ok(closes.length >= 2);
assert.equal(closes[0].path, input);
assert.equal(closes[0].denied, true);
assert.ok(Number.isInteger(closes[0].descriptor));
for (const retry of closes.slice(1)) {
assert.equal(retry.path, input);
assert.equal(retry.descriptor, closes[0].descriptor);
assert.equal(retry.denied, false);
}
}
assert.notEqual(output.details?.cleanup, "incomplete");
assert.equal(output.details?.resources, undefined);
if (input === invalid) {
assert.equal(output.code, "invalid_request");
assert.ok(output.details?.captured_output?.stderr);
}
}
if (mode === "runtime-once") {
assert.equal(facts.trace.length, 2);
assert.equal(facts.trace[0].path, facts.trace[1].path);
assert.equal(facts.trace[0].denied, true);
assert.equal(facts.trace[1].exists, false);
}
records.push({ kind: "cli", name, status, output, ...facts });
}
for (const mode of ["runtime-once", "runtime-until-allowed"]) {
const c = await setup("mcp-" + mode, mode, valid);
const client = new Client({ name: "wabt-cleanup-probe", version: "1" });
const transport = new StdioClientTransport({
command: process.execPath,
args: ["--import", preload, entrypoint, "mcp"],
env: c.env,
stderr: "pipe",
});
const calls = [];
await withVerifierCleanup(async () => {
await client.connect(transport);
const request = {
name: "inspect_wasm_artifact",
arguments: { path: valid },
};
const call = () =>
client.callTool(request, { timeout: WABT_OPERATION_TIMEOUT_MS });
const first = await call();
calls.push(first);
assert.equal(requireMcpToolError(first).code, "cleanup_incomplete");
if (mode === "runtime-until-allowed") {
const second = await call();
calls.push(second);
assert.equal(requireMcpToolError(second).code, "cleanup_incomplete");
assert.equal(
(await observations(c)).remaining.filter((name) =>
name.startsWith("rea-wabt-"),
).length,
1,
);
await writeFile(join(c.temporary, "allow"), "restore");
}
const last = await call();
calls.push(last);
assert.notEqual(last.isError, true, JSON.stringify(last));
assert.equal(
last.structuredContent.normalized_result.validation,
"valid",
);
}, [() => client.close(), () => transport.close()]);
const facts = await observations(c);
assert.deepEqual(
facts.remaining,
mode === "runtime-until-allowed" ? ["allow"] : [],
);
records.push({ kind: "mcp", mode, calls, ...facts });
}
return records.reduce(
(count, record) =>
count + (record.kind === "cli" ? 1 : record.calls.length),
0,
);
}, [() => rm(root, { recursive: true, force: true })]);
}