Files
rea/scripts/verify-go-binary.mjs
T
morluto 4d4631ac94 test: harden verification fixtures and runtime coverage
Use exact discovered test identities, production MCP sessions and byte-exact setup backups. Add CLI signal cleanup coverage and independent Ghidra, Go and firmware verification assertions; prune redundant test configuration and preserve platform limits.
2026-10-14 08:59:27 +08:00

574 lines
17 KiB
JavaScript

#!/usr/bin/env node
import assert from "node:assert/strict";
import { isUtf8 } from "node:buffer";
import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import { lstat, mkdir, readFile, writeFile } from "node:fs/promises";
import { isAbsolute, join } from "node:path";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { parseEvidence } from "../dist/domain/evidence.js";
import { goBinarySchema } from "../dist/domain/go/goBinary.js";
import { PrivateRuntimeRoot } from "../dist/process/PrivateRuntimeRoot.js";
import { mcpTextValue } from "./lib/mcp-verifier-results.mjs";
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
const execute = promisify(execFile);
const compiler = process.env.REA_VERIFY_GO_COMMAND ?? "go";
if (process.env.REA_VERIFY_GO_COMMAND !== undefined && !isAbsolute(compiler))
throw new Error(
"REA_VERIFY_GO_COMMAND must be an absolute Go compiler path.",
);
let compilerVersion = null;
const run = createVerifierRun();
const root = await PrivateRuntimeRoot.create({ prefix: "rea-go-verifier-" });
// Keep Go's directory enumeration below the private root's Windows ownership lease.
const sourceRoot = join(root.path, "source");
const entrypoint = fileURLToPath(new URL("./rea.mjs", import.meta.url));
const environment = Object.fromEntries(
Object.entries(process.env).filter(([, value]) => typeof value === "string"),
);
delete environment.HOPPER_TARGET_PATH;
const goEnvironment = {
...environment,
CGO_ENABLED: "0",
GOCACHEPROG: "",
GO111MODULE: "on",
GOENV: "off",
GOFLAGS: "",
GOMAXPROCS: "2",
GOTOOLCHAIN: "local",
GOWORK: "off",
GOPROXY: "off",
GOSUMDB: "off",
GOPATH: join(root.path, "gopath"),
GOCACHE: join(root.path, "cache"),
GOMODCACHE: join(root.path, "modules"),
GOTMPDIR: join(root.path, "tmp"),
// Go's own verifier seam isolates telemetry; no global configuration is changed.
TEST_TELEMETRY_DIR: join(root.path, "telemetry"),
};
const client = new Client({ name: "go-binary-verifier", version: "1" });
const transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env: environment,
stderr: "pipe",
});
const targets = [
["linux", "amd64", "elf", 64, "little"],
["linux", "386", "elf", 32, "little"],
["linux", "arm64", "elf", 64, "little"],
["linux", "ppc64", "elf", 64, "big"],
["linux", "mips", "elf", 32, "big"],
["windows", "amd64", "pe", 64, "little"],
["windows", "386", "pe", 32, "little"],
["darwin", "amd64", "macho", 64, "little"],
["darwin", "arm64", "macho", 64, "little"],
];
const verified = [];
const omittedCoverage = [];
const failures = [];
try {
await prepareFixture();
try {
compilerVersion = (
await execute(compiler, ["version"], {
cwd: root.path,
env: goEnvironment,
timeout: 10_000,
})
).stdout.trim();
} catch (cause) {
throw new Error(
"verify:go:binary requires Go on PATH or absolute REA_VERIFY_GO_COMMAND; Go is only a fixture producer, not a REA runtime dependency.",
{ cause },
);
}
const host = (await go(["env", "GOHOSTOS", "GOHOSTARCH"])).stdout
.trim()
.split("\n");
const oracle = join(
root.path,
host[0] === "windows" ? "buildinfo-oracle.exe" : "buildinfo-oracle",
);
await go(
["build", "-trimpath", "-buildvcs=false", "-o", oracle, "./oracle"],
{ GOOS: host[0], GOARCH: host[1] },
);
await client.connect(transport);
for (const target of targets) {
const [os, arch] = target;
const path = join(
root.path,
`${os}-${arch}${os === "windows" ? ".exe" : ""}`,
);
await go(
[
"build",
"-trimpath",
"-buildvcs=false",
"-ldflags=-s -w",
"-o",
path,
".",
],
{ GOOS: os, GOARCH: arch },
);
const strippedInfo = await verify(path, target, oracle, null, "stripped");
if (os === "linux" && arch === "amd64") {
const sectionless = join(root.path, "linux-amd64-sectionless");
const bytes = Buffer.from(await readFile(path));
bytes.fill(0, 40, 48); // ELF64 e_shoff.
bytes.fill(0, 58, 64); // e_shentsize, e_shnum and e_shstrndx.
await writeFile(sectionless, bytes);
const sectionlessInfo = await verify(
sectionless,
target,
oracle,
null,
"sectionless",
path,
);
assert.deepEqual(sectionlessInfo, strippedInfo);
const pie = join(root.path, "linux-amd64-pie");
await go(
[
"build",
"-trimpath",
"-buildvcs=false",
"-ldflags=-s -w",
"-buildmode=pie",
"-o",
pie,
".",
],
{ GOOS: os, GOARCH: arch },
);
const originalInfo = await verify(pie, target, oracle, null, "pie");
const pieBytes = Buffer.from(await readFile(pie));
pieBytes.fill(0, 40, 48);
pieBytes.fill(0, 58, 64);
const pieSectionless = `${pie}-sectionless`;
await writeFile(pieSectionless, pieBytes);
// Keep the producer image as the independent oracle. Removing section
// headers must preserve every metadata field and original source span.
const retainedInfo = await verify(
pieSectionless,
target,
oracle,
null,
"sectionless-pie",
pie,
);
assert.deepEqual(retainedInfo, originalInfo);
}
}
for (const target of targets.filter(([os]) => os === "darwin")) {
const [os, arch] = target;
const path = join(root.path, `${os}-${arch}-unstripped`);
await go(["build", "-trimpath", "-buildvcs=false", "-o", path, "."], {
GOOS: os,
GOARCH: arch,
});
await verify(path, target, oracle, null, "unstripped");
}
if (process.platform === "win32")
omittedCoverage.push(
"Compiler-produced non-UTF-8 argv strings were not verified on Windows; Windows argv cannot preserve arbitrary byte arguments.",
);
else {
const