Files
reverse-engineering-anything/scripts/lib/conformance-fixtures.mjs
T
morlutoandCursor Agent 83f0a4d238 fix(ci)!: verify exact conformance fixture records (#9977)
* fix(ci)!: verify exact conformance fixture records

BREAKING CHANGE: Regenerate unversioned conformance manifests with npm run build:fixtures. Schema version 2 separates exact string markers from intentional fragments and rejects the ambiguous strings field.

* test(conformance): wait out a cold verifier instead of treating SIGTERM as rejection

The compiler-produced complete/REA_C_ENTRY run was killed by its 10s
execFile timeout on the loaded source-test runner, with empty stderr and
SIGTERM. The stricter record checks already passed locally and for the
other compiler-produced cases. Assert the process status and give that
cold run room inside the test budget.

* fix(ci): preserve carriage returns in nm symbol records

nm -j terminates each name with LF. A carriage return before that LF is
part of the symbol. Splitting on CR LF dropped it, so a renamed symbol
ending in CR matched the name without it.

* test(ci): supervise conformance verifier subprocesses

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-11 17:28:10 +08:00

108 lines
3.7 KiB
JavaScript

import { createHash } from "node:crypto";
import { readFile, realpath } from "node:fs/promises";
import { isAbsolute, relative, resolve, sep } from "node:path";
export const LARGE_FIXTURE_COUNT = 1_205;
/** Admit the current producer contract; unversioned substring checks are retired. */
export const parseConformanceFixtureManifest = (manifest) => {
if (
manifest?.schemaVersion !== 2 ||
!["darwin", "linux"].includes(manifest.platform) ||
!Array.isArray(manifest.fixtures)
)
throw new Error(
"Unsupported conformance manifest; regenerate with npm run build:fixtures",
);
for (const fixture of manifest.fixtures) {
if (fixture === null || typeof fixture !== "object")
throw new Error("Invalid conformance fixture entry");
const expectations = fixture.expectations;
if (expectations === undefined) continue;
if (
expectations === null ||
typeof expectations !== "object" ||
Object.hasOwn(expectations, "strings") ||
["stringMarkers", "stringFragments"].some(
(key) =>
expectations[key] !== undefined &&
(!Array.isArray(expectations[key]) ||
expectations[key].some((value) => typeof value !== "string")),
)
)
throw new Error("Invalid conformance fixture string expectations");
}
return manifest;
};
export const HOPPER_C_ORACLE = Object.freeze({
mainProcedure: "main",
entryProcedure: "rea_entry",
branchProcedure: "rea_branch",
leafProcedure: "rea_leaf",
entryString: "REA_C_ENTRY",
leafString: "REA_C_LEAF",
globalName: "rea_c_global",
});
export const sha256 = (value) =>
createHash("sha256").update(value).digest("hex");
/** `nm -j` ends each name with LF. A carriage return before that LF belongs to the name. */
export const splitNmSymbolRecords = (output) =>
output.split("\n").filter((record) => record.length > 0);
export const generateLargeFixture = () => {
const declarations = Array.from(
{ length: LARGE_FIXTURE_COUNT },
(_, index) =>
`__attribute__((noinline, used)) int rea_inventory_${String(index).padStart(4, "0")}(void) { puts("REA_INVENTORY_${String(index).padStart(4, "0")}"); return ${index}; }`,
);
return [
"#include <stdio.h>",
...declarations,
"int main(void) { return rea_inventory_0000(); }",
"",
].join("\n");
};
export const sourceDigest = (sources) => {
const canonical = [...sources]
.sort(({ path: left }, { path: right }) => left.localeCompare(right))
.map(({ path, content }) => `${path}\0${sha256(content)}\n`)
.join("");
return sha256(canonical);
};
/** Resolve manifest-relative paths once, including their real symlink destination. */
export const resolveConformanceFixturePath = async (root, declaredPath) => {
if (typeof declaredPath !== "string")
throw new Error("Conformance manifest path is invalid");
const path = await realpath(resolve(root, declaredPath));
const relation = relative(root, path);
if (
relation === ".." ||
relation.startsWith(`..${sep}`) ||
isAbsolute(relation)
)
throw new Error(`Conformance path escapes its root: ${declaredPath}`);
return path;
};
/** Read a resolved artifact and bind its exact bytes to the manifest digest. */
export const bindConformanceFixtureArtifact = async (path, fixture) => {
if (
fixture === null ||
typeof fixture !== "object" ||
typeof fixture.artifactSha256 !== "string" ||
!/^[0-9a-f]{64}$/u.test(fixture.artifactSha256)
)
throw new Error("Invalid conformance artifact declaration");
const actual = sha256(await readFile(path));
if (actual !== fixture.artifactSha256)
throw new Error(
`Fixture ${fixture.name} digest did not match its manifest`,
);
return { path, sha256: actual };
};