refactor(verify): give the native verifiers' roots to VerifierFixture (#11180)

* refactor(verify): give the native verifiers' roots to VerifierFixture

* fix(verify): report every nested JEB cleanup failure reason

* test(verify): give the isolated ADB verifier runs the fixture owner it now imports
This commit is contained in:
morluto authored and GitHub committed 2026-11-16 00:06:34 +08:00
1 parent 0f53849160
commit fdf856ab84
13 files changed
+305 -277

No files matched your search

+26 -17
View File
@@ -1,13 +1,16 @@
import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import { mkdtemp, readFile, rm, stat } from "node:fs/promises";
import { tmpdir } from "node:os";
import { readFile, stat } from "node:fs/promises";
import { join, posix } from "node:path";
import { promisify } from "node:util";
import { AdbDeviceAnalysisService } from "../dist/application/adb/AdbDeviceAnalysisService.js";
import { createAdbDeviceAnalysisProvider } from "../dist/composition/adb.js";
import { closeVerifierResources } from "./lib/verifier-cleanup.mjs";
import {
VerifierFixture,
withVerifierFixture,
} from "./lib/verifier-fixture.mjs";
const execFileAsync = promisify(execFile);
const options = parseArguments(process.argv.slice(2));
@@ -279,8 +282,12 @@ try {
}
if (pullCandidate !== null) {
const directory = await mkdtemp(join(tmpdir(), "rea-adb-verify-"));
try {
const directoryFixture = await VerifierFixture.open({
prefix: "rea-adb-verify-",
private: false,
});
const directory = directoryFixture.path;
await withVerifierFixture(directoryFixture, async () => {
const pull = await run("pull_adb_package", {
serial,
package: pullCandidate,
@@ -309,15 +316,17 @@ try {
);
}
}
} finally {
await rm(directory, { recursive: true, force: true });
}
});
}
// File transfer: push one lane-owned file, verify both digests, pull it
// back, then clean up the device copy through the same fixed argv surface.
const transferRoot = await mkdtemp(join(tmpdir(), "rea-adb-transfer-"));
try {
const transferRootFixture = await VerifierFixture.open({
prefix: "rea-adb-transfer-",
private: false,
});
const transferRoot = transferRootFixture.path;
await withVerifierFixture(transferRootFixture, async () => {
const payload = join(transferRoot, "rea-verify.txt");
const payloadBytes = "rea adb transfer verification\n";
await import("node:fs/promises").then((fs) =>
@@ -331,8 +340,12 @@ try {
devicePath: deviceTarget,
outputDirectory: transferRoot,
});
const screenRoot = await mkdtemp(join(tmpdir(), "rea-adb-screen-"));
try {
const screenRootFixture = await VerifierFixture.open({
prefix: "rea-adb-screen-",
private: false,
});
const screenRoot = screenRootFixture.path;
await withVerifierFixture(screenRootFixture, async () => {
const screen = await run("capture_adb_screen", {
serial,
output_directory: screenRoot,
@@ -343,9 +356,7 @@ try {
screen.width !== null && screen.height !== null && screen.bytes > 0,
`${screen.width}x${screen.height}, ${screen.bytes} bytes`,
);
} finally {
await rm(screenRoot, { recursive: true, force: true });
}
});
if (options.pull !== null) {
const details = await run("inspect_adb_package", {
serial,
@@ -358,9 +369,7 @@ try {
`versionCode=${String(details.version_code)}`,
);
}
} finally {
await rm(transferRoot, { recursive: true, force: true });
}
});
}
} catch (cause) {
verifierFailed = true;
+14 -12
View File
@@ -1,11 +1,11 @@
/** Compare binary hardening rows with host toolchains when they exist. */
import assert from "node:assert/strict";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { importVerifierSource } from "./lib/verifier-source-loader.mjs";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { VerifierFixture, onceConfirmed } from "./lib/verifier-fixture.mjs";
const { readElfHardening } = await importVerifierSource(
"../src/native/hardening/ElfHardening.ts",
@@ -99,10 +99,11 @@ const versionLine = async (command, args = ["--version"]) => {
const statesOf = (rows) =>
Object.fromEntries(rows.map((row) => [row.property, row.state]));
// The root holds every compiled image. Remove it only after the owned
// commands have settled, and keep it when their cleanup failed.
// The root holds every compiled image. The fixture removes it only after the
// owned commands have settled, and keeps it when their cleanup failed.
const closeCommands = onceConfirmed(() => commands.close());
let rootFixture;
let root;
let commandsClosed = false;
await withVerifierCleanup(async () => {
const report = {
host: `${process.platform} ${process.arch}`,
@@ -144,20 +145,21 @@ await withVerifierCleanup(async () => {
}
`;
root = await mkdtemp(join(tmpdir(), "rea-binary-hardening-"));
rootFixture = await VerifierFixture.open({
prefix: "rea-binary-hardening-",
private: false,
});
rootFixture.releaseAfter(closeCommands);
root = rootFixture.path;
const cFile = join(root, "sample.c");
await writeFile(cFile, source);
await verifyElf(root, cFile, report);
await verifyMacho(root, cFile, report);
console.log(JSON.stringify(report, null, 2));
}, [
closeCommands,
async () => {
await commands.close();
commandsClosed = true;
},
async () => {
if (commandsClosed && root !== undefined)
await rm(root, { recursive: true, force: true });
await rootFixture?.release();
},
async () => {
process.off("SIGINT", interrupt);
+14 -12
View File
@@ -4,11 +4,11 @@
* C++ compiler or no readelf.
*/
import assert from "node:assert/strict";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { VerifierFixture, onceConfirmed } from "./lib/verifier-fixture.mjs";
/**
* Every probe, compiler driver and inspection runs as an owned process tree,
@@ -178,10 +178,11 @@ const inspectedStarts = async (path) => {
}
};
// The root holds every compiled image. Remove it only after the owned
// commands have settled, and keep it when their cleanup failed.
// The root holds every compiled image. The fixture removes it only after the
// owned commands have settled, and keeps it when their cleanup failed.
const closeCommands = onceConfirmed(() => commands.close());
let rootFixture;
let root;
let commandsClosed = false;
let unavailable = false;
await withVerifierCleanup(async () => {
const compiler = await firstAvailable(["zig", "clang++", "g++"]);
@@ -203,7 +204,12 @@ await withVerifierCleanup(async () => {
unavailable = true;
return;
}
root = await mkdtemp(join(tmpdir(), "rea-elf-unwind-"));
rootFixture = await VerifierFixture.open({
prefix: "rea-elf-unwind-",
private: false,
});
rootFixture.releaseAfter(closeCommands);
root = rootFixture.path;
const source = join(root, "ranges.cpp");
const unstripped = join(root, "ranges.unstripped");
const stripped = join(root, "ranges.stripped");
@@ -227,13 +233,9 @@ await withVerifierCleanup(async () => {
}),
);
}, [
closeCommands,
async () => {
await commands.close();
commandsClosed = true;
},
async () => {
if (commandsClosed && root !== undefined)
await rm(root, { recursive: true, force: true });
await rootFixture?.release();
},
async () => {
process.off("SIGINT", interrupt);
+161 -161
View File
@@ -1,19 +1,19 @@
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdtemp, readdir, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import { readdir, readFile } from "node:fs/promises";
import { resolve } from "node:path";
import { promisify } from "node:util";
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
import { toolContract } from "../dist/contracts/toolContracts.js";
import { ArtifactResourceScope } from "../dist/artifacts/ArtifactResourceScope.js";
import { requireMcpOutput } from "./lib/mcp-verifier-results.mjs";
import {
closeVerifierResources,
withVerifierCleanup,
} from "./lib/verifier-cleanup.mjs";
import { closeVerifierResources } from "./lib/verifier-cleanup.mjs";
import { hashVerifierFile } from "./lib/verifier-file-resources.mjs";
import {
VerifierFixture,
withVerifierFixture,
} from "./lib/verifier-fixture.mjs";
const options = parseArguments(process.argv.slice(2));
if (options.help) {
@@ -33,7 +33,11 @@ const expectations =
? null
: JSON.parse(await readFile(options.expectations, "utf8"));
// This is a shared test parent, not a leased provider-owned Windows runtime.
const root = await mkdtemp(join(tmpdir(), "rea-flutter-verifier-"));
const rootFixture = await VerifierFixture.open({
prefix: "rea-flutter-verifier-",
private: false,
});
const root = rootFixture.path;
const resources = new ArtifactResourceScope();
const entrypoint = resolve("scripts/rea.mjs");
const environment = Object.fromEntries(
@@ -52,169 +56,165 @@ const transport = new StdioClientTransport({
stderr: "pipe",
});
const execute = promisify(execFile);
await withVerifierCleanup(
async () => {
await client.connect(transport);
const apk = resolve(options.apk);
const identity = await hashVerifierFile(apk, resources);
const identified = await run("identify_flutter_build", { path: apk });
assert.deepEqual(identified.target, { path: apk, ...identity });
assert.equal(identified.flutter_detected, true);
assert.equal(identified.coverage, "complete");
const abis = identified.abis.filter((abi) => abi.libapp.present);
assert.ok(abis.length > 0);
const hashes = new Set();
// Server shutdown retries retained provider cleanup and settles before the
// fixture removes the root; snapshots left under it fail the run and keep it.
rootFixture.releaseAfter(async () => {
await closeVerifierResources([
() => client.close(),
() => transport.close(),
() => resources.close(),
]);
assert.deepEqual(
await readdir(root),
[],
`Provider snapshots remain under ${root}`,
);
});
await withVerifierFixture(rootFixture, async () => {
await client.connect(transport);
const apk = resolve(options.apk);
const identity = await hashVerifierFile(apk, resources);
const identified = await run("identify_flutter_build", { path: apk });
assert.deepEqual(identified.target, { path: apk, ...identity });
assert.equal(identified.flutter_detected, true);
assert.equal(identified.coverage, "complete");
const abis = identified.abis.filter((abi) => abi.libapp.present);
assert.ok(abis.length > 0);
const hashes = new Set();
for (const abi of abis) {
assert.equal(abi.libapp.elf_header_valid, true);
assert.equal(abi.libapp.snapshot_hash_sources, 2);
assert.ok(abi.libapp.snapshot_hash);
hashes.add(abi.libapp.snapshot_hash);
assert.equal(abi.libflutter.present, true);
assert.match(abi.libflutter.build_id ?? "", /^(?:[0-9a-f]{2}){4,64}$/u);
assert.deepEqual(abi.libflutter.build_id_candidates, [
abi.libflutter.build_id,
]);
}
assert.equal(hashes.size, 1, "Every ABI must agree on the snapshot hash");
if (expectations !== null) {
assert.equal(identity.sha256, expectations.target_sha256);
assert.deepEqual([...hashes], [expectations.snapshot_hash]);
assert.deepEqual(
abis.map((abi) => abi.abi).sort(),
Object.keys(expectations.engines).sort(),
);
for (const abi of abis) {
assert.equal(abi.libapp.elf_header_valid, true);
assert.equal(abi.libapp.snapshot_hash_sources, 2);
assert.ok(abi.libapp.snapshot_hash);
hashes.add(abi.libapp.snapshot_hash);
assert.equal(abi.libflutter.present, true);
assert.match(abi.libflutter.build_id ?? "", /^(?:[0-9a-f]{2}){4,64}$/u);
assert.deepEqual(abi.libflutter.build_id_candidates, [
abi.libflutter.build_id,
]);
}
assert.equal(hashes.size, 1, "Every ABI must agree on the snapshot hash");
if (expectations !== null) {
assert.equal(identity.sha256, expectations.target_sha256);
assert.deepEqual([...hashes], [expectations.snapshot_hash]);
assert.deepEqual(
abis.map((abi) => abi.abi).sort(),
Object.keys(expectations.engines).sort(),
{
dart_version: abi.libflutter.dart_version,
toolchain_lines: abi.libflutter.toolchain_lines,
},
expectations.engines[abi.abi],
);
for (const abi of abis) {
assert.deepEqual(
{
dart_version: abi.libflutter.dart_version,
toolchain_lines: abi.libflutter.toolchain_lines,
},
expectations.engines[abi.abi],
);
assert.equal(abi.libflutter.dart_version_capped, false);
assert.equal(abi.libflutter.toolchain_capped, false);
}
assert.equal(abi.libflutter.dart_version_capped, false);
assert.equal(abi.libflutter.toolchain_capped, false);
}
process.stdout.write(
"[ok] Exact per-ABI engine labels match digest-bound expectations\n",
);
} else {
process.stdout.write(
"[unverified] Exact engine labels and their absence need --expectations JSON\n",
);
}
// The same checks apply to the default selection and each remaining ABI.
const preferred = await run("inspect_dart_aot", { path: apk });
assert.ok(
abis.some((abi) => abi.abi === preferred.abi),
"Default AOT selection must be one of the identified ABIs",
);
for (const abi of abis) {
const aot =
abi.abi === preferred.abi
? preferred
: await run("inspect_dart_aot", { path: apk, abi: abi.abi });
assert.equal(aot.abi, abi.abi);
assert.equal(
aot.libapp.coverage,
"complete",
`Snapshot decoding must be complete on ${abi.abi}`,
);
assert.equal(aot.coverage, aot.string_pool.coverage);
if (aot.coverage !== "complete") {
process.stdout.write(
"[ok] Exact per-ABI engine labels match digest-bound expectations\n",
`[unverified] ${abi.abi}: full string-pool projection (returned pool is bounded and partial)\n`,
);
}
assert.deepEqual(aot.target, identified.target);
assert.equal(aot.libapp.sha256, abi.libapp.sha256);
assert.equal(aot.libapp.bytes, abi.libapp.bytes);
assert.equal(aot.libapp.snapshot_hash_sources, 2);
assert.equal(aot.libapp.snapshot_hash, abi.libapp.snapshot_hash);
assert.deepEqual(
aot.libapp.sections.map((section) => section.name).sort(),
[
"_kDartVmSnapshotData",
"_kDartVmSnapshotInstructions",
"_kDartIsolateSnapshotData",
"_kDartIsolateSnapshotInstructions",
].sort(),
);
for (const section of aot.libapp.sections) {
assert.ok(section.offset + section.size <= aot.libapp.bytes);
if (!section.name.endsWith("Data")) continue;
assert.equal(section.magic_valid, true);
assert.equal(
section.kind,
3,
"This verifier requires an AOT app snapshot",
);
assert.ok(
section.header_length >= 48 &&
section.header_length + 4 <= section.size,
`Snapshot extent must fit ${section.name} on ${abi.abi}`,
);
}
assert.ok(aot.string_pool.package_uri_count_at_least > 0);
assert.ok(aot.string_pool.dart_uri_count_at_least > 0);
if (expectations?.string_pools !== undefined) {
const expected = expectations.string_pools[abi.abi];
assert.ok(
expected,
`Pinned string-pool counts are required on ${abi.abi}`,
);
assert.equal(
aot.string_pool.package_uri_count_at_least,
expected.package_uri_count_at_least,
);
assert.equal(
aot.string_pool.dart_uri_count_at_least,
expected.dart_uri_count_at_least,
);
process.stdout.write(
`[ok] ${abi.abi}: exact pinned package and Dart URI counts\n`,
);
} else {
process.stdout.write(
"[unverified] Exact engine labels and their absence need --expectations JSON\n",
`[unverified] ${abi.abi}: exact string-pool counts need --expectations JSON\n`,
);
}
// The same checks apply to the default selection and each remaining ABI.
const preferred = await run("inspect_dart_aot", { path: apk });
assert.ok(
abis.some((abi) => abi.abi === preferred.abi),
"Default AOT selection must be one of the identified ABIs",
process.stdout.write(
`[ok] ${abi.abi}: four symbols, bounded AOT headers, agreeing hashes and string pool\n`,
);
for (const abi of abis) {
const aot =
abi.abi === preferred.abi
? preferred
: await run("inspect_dart_aot", { path: apk, abi: abi.abi });
assert.equal(aot.abi, abi.abi);
assert.equal(
aot.libapp.coverage,
"complete",
`Snapshot decoding must be complete on ${abi.abi}`,
);
assert.equal(aot.coverage, aot.string_pool.coverage);
if (aot.coverage !== "complete") {
process.stdout.write(
`[unverified] ${abi.abi}: full string-pool projection (returned pool is bounded and partial)\n`,
);
}
assert.deepEqual(aot.target, identified.target);
assert.equal(aot.libapp.sha256, abi.libapp.sha256);
assert.equal(aot.libapp.bytes, abi.libapp.bytes);
assert.equal(aot.libapp.snapshot_hash_sources, 2);
assert.equal(aot.libapp.snapshot_hash, abi.libapp.snapshot_hash);
assert.deepEqual(
aot.libapp.sections.map((section) => section.name).sort(),
[
"_kDartVmSnapshotData",
"_kDartVmSnapshotInstructions",
"_kDartIsolateSnapshotData",
"_kDartIsolateSnapshotInstructions",
].sort(),
);
for (const section of aot.libapp.sections) {
assert.ok(section.offset + section.size <= aot.libapp.bytes);
if (!section.name.endsWith("Data")) continue;
assert.equal(section.magic_valid, true);
assert.equal(
section.kind,
3,
"This verifier requires an AOT app snapshot",
);
assert.ok(
section.header_length >= 48 &&
section.header_length + 4 <= section.size,
`Snapshot extent must fit ${section.name} on ${abi.abi}`,
);
}
assert.ok(aot.string_pool.package_uri_count_at_least > 0);
assert.ok(aot.string_pool.dart_uri_count_at_least > 0);
if (expectations?.string_pools !== undefined) {
const expected = expectations.string_pools[abi.abi];
assert.ok(
expected,
`Pinned string-pool counts are required on ${abi.abi}`,
);
assert.equal(
aot.string_pool.package_uri_count_at_least,
expected.package_uri_count_at_least,
);
assert.equal(
aot.string_pool.dart_uri_count_at_least,
expected.dart_uri_count_at_least,
);
process.stdout.write(
`[ok] ${abi.abi}: exact pinned package and Dart URI counts\n`,
);
} else {
process.stdout.write(
`[unverified] ${abi.abi}: exact string-pool counts need --expectations JSON\n`,
);
}
process.stdout.write(
`[ok] ${abi.abi}: four symbols, bounded AOT headers, agreeing hashes and string pool\n`,
);
}
if (options.plainApk !== null) {
const plain = resolve(options.plainApk);
const negative = await run("identify_flutter_build", { path: plain });
assert.deepEqual(negative.target, {
path: plain,
...(await hashVerifierFile(plain, resources)),
});
assert.equal(negative.flutter_detected, false);
assert.equal(negative.coverage, "complete");
}
assert.deepEqual(
await hashVerifierFile(apk, resources),
identity,
"Verification must preserve its input",
);
},
// Server shutdown retries retained provider cleanup and settles before success.
[
async () => {
await closeVerifierResources([
() => client.close(),
() => transport.close(),
() => resources.close(),
]);
assert.deepEqual(
await readdir(root),
[],
`Provider snapshots remain under ${root}`,
);
await rm(root, { recursive: true, force: true });
},
],
);
}
if (options.plainApk !== null) {
const plain = resolve(options.plainApk);
const negative = await run("identify_flutter_build", { path: plain });
assert.deepEqual(negative.target, {
path: plain,
...(await hashVerifierFile(plain, resources)),
});
assert.equal(negative.flutter_detected, false);
assert.equal(negative.coverage, "complete");
}
assert.deepEqual(
await hashVerifierFile(apk, resources),
identity,
"Verification must preserve its input",
);
});
process.stdout.write(
"all asserted Flutter CLI/MCP checks passed; unverified facets are reported above\n",
);
+15 -9
View File
@@ -1,12 +1,12 @@
import { execFile } from "node:child_process";
import { mkdtemp, writeFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
import { JebAnalysisService } from "../dist/application/jeb/JebAnalysisService.js";
import { createJebAnalysisProvider } from "../dist/composition/jeb.js";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
const run = promisify(execFile);
@@ -26,10 +26,15 @@ if (options.help) {
const provider = createJebAnalysisProvider(process.env);
const service = new JebAnalysisService(provider);
let fixture;
let fixtureDirectory;
try {
const report = await withVerifierCleanup(async () => {
fixtureDirectory = await mkdtemp(join(tmpdir(), "rea-jeb-"));
fixture = await VerifierFixture.open({
prefix: "rea-jeb-",
private: false,
});
fixtureDirectory = fixture.path;
const client = await service.execute("inspect_jeb_client", {});
if (!client.ok) throw new Error(client.error.message);
const engine = client.value.normalized_result.engine;
@@ -89,18 +94,19 @@ try {
};
}, [
async () => {
// The fixture is removed only after the provider confirms it closed.
await provider.close();
if (fixtureDirectory !== undefined) {
await rm(fixtureDirectory, { recursive: true, force: true });
fixtureDirectory = undefined;
}
await fixture?.release();
},
]);
process.stdout.write(`${JSON.stringify(report)}\n`);
} catch (cause) {
if (fixtureDirectory !== undefined)
if (fixture !== undefined && !fixture.released)
process.stderr.write(`JEB fixture retained at ${fixtureDirectory}\n`);
const causes = cause instanceof AggregateError ? cause.errors : [cause];
// Fixture and cleanup failures nest AggregateErrors; report each leaf reason.
const leaves = (reason) =>
reason instanceof AggregateError ? reason.errors.flatMap(leaves) : [reason];
const causes = leaves(cause);
process.stderr.write(
`JEB real-provider verification failed: ${causes.map((reason) => (reason instanceof Error ? reason.message : String(reason))).join("; ")}\n`,
);
+12 -7
View File
@@ -1,8 +1,7 @@
import { requireMcpToolError } from "./lib/mcp-verifier-results.mjs";
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { writeFile } from "node:fs/promises";
import { basename, join } from "node:path";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
@@ -14,6 +13,10 @@ import {
artifactMcpCall,
withArtifactMcp,
} from "./lib/artifact-e2e.mjs";
import {
VerifierFixture,
withVerifierFixture,
} from "./lib/verifier-fixture.mjs";
const exec = promisify(execFile);
@@ -264,8 +267,12 @@ const checkHardenedRuntime = async (directory, binary) => {
assert.equal(traced.process.exit_status, 0);
};
const directory = await mkdtemp(join(tmpdir(), "rea-native-calls-"));
try {
const directoryFixture = await VerifierFixture.open({
prefix: "rea-native-calls-",
private: false,
});
const directory = directoryFixture.path;
await withVerifierFixture(directoryFixture, async () => {
const binary = join(directory, "ReaCalls");
await exec("/usr/bin/xcrun", [
"clang",
@@ -346,6 +353,4 @@ try {
},
}),
);
} finally {
await rm(directory, { recursive: true, force: true });
}
});
+9 -10
View File
@@ -1,5 +1,5 @@
import assert from "node:assert/strict";
import { readFile, rm } from "node:fs/promises";
import { readFile } from "node:fs/promises";
import { isAbsolute, join } from "node:path";
import { fileURLToPath } from "node:url";
import { createPackageVerifierCommands } from "./lib/verify-package-commands.mjs";
@@ -10,7 +10,7 @@ import {
artifactMcpResult,
withArtifactMcp,
} from "./lib/artifact-e2e.mjs";
import { createCanonicalTemporaryDirectory } from "./lib/canonical-temporary-directory.mjs";
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
const cancellation = new AbortController();
let shutdownSignal;
@@ -47,15 +47,14 @@ const callerLines = new Set(
return matches[0];
}),
);
const allocatedDirectory =
await createCanonicalTemporaryDirectory("rea-pascal-calls-");
let directory = allocatedDirectory.path;
const directoryFixture = await VerifierFixture.open({
prefix: "rea-pascal-calls-",
private: false,
});
let directory = directoryFixture.path;
// The package command owner releases the fixture after its commands close.
const commands = await createPackageVerifierCommands({
workspace: {
path: allocatedDirectory.allocatedPath,
close: () =>
rm(allocatedDirectory.allocatedPath, { recursive: true, force: true }),
},
workspace: { path: directory, close: () => directoryFixture.release() },
});
const execute = (command, arguments_, { timeout }) =>
commands.exec(command, arguments_, {
+8 -4
View File
@@ -1,7 +1,6 @@
import { execFile, spawn } from "node:child_process";
import assert from "node:assert/strict";
import { mkdtemp, mkdir, writeFile, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { mkdir, writeFile, readFile } from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
@@ -10,12 +9,17 @@ import { observeNativeUi } from "../dist/native/NativeUiObservation.js";
import { NATIVE_UI_HELPER_MAX_BUFFER } from "../dist/native/NativeUiOutputBudget.js";
import { artifactMcpResult, withArtifactMcp } from "./lib/artifact-e2e.mjs";
import { observeProcessStartIdentity } from "../dist/process/ProcessOwnershipObservation.js";
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
if (process.platform !== "darwin")
throw new Error(
"Native UI verification requires macOS, an interactive desktop and Xcode command-line tools",
);
const root = await mkdtemp(join(tmpdir(), "rea-ui-fixture-"));
const rootFixture = await VerifierFixture.open({
prefix: "rea-ui-fixture-",
private: false,
});
const root = rootFixture.path;
let child;
let childExit;
let fixturePid;
@@ -294,7 +298,7 @@ try {
}
const fixtureExited =
child === undefined || (await openExitedWithFixture(child, childExit));
if (fixtureExited) await rm(root, { recursive: true, force: true });
if (fixtureExited) await rootFixture.release();
else {
// The app may have been reparented away from `open`; stopping `open`
// does not prove the fixture exited, so its root stays in place.
+12 -7
View File
@@ -1,16 +1,23 @@
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { readFile, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import {
VerifierFixture,
withVerifierFixture,
} from "./lib/verifier-fixture.mjs";
// Requires a running Docker daemon, network access for the pinned fixture
// producer, and `npm run build:cached`. Never executes the injected application.
const root = await mkdtemp(join(tmpdir(), "rea-node-sea-real-"));
const rootFixture = await VerifierFixture.open({
prefix: "rea-node-sea-real-",
private: false,
});
const root = rootFixture.path;
const image = "node:24.10.0-bookworm";
const script =
'throw new Error("SEA verification must not execute this application");\n';
try {
await withVerifierFixture(rootFixture, async () => {
await writeFile(join(root, "main.js"), script);
await writeFile(join(root, "asset.txt"), "real SEA asset\n");
await writeFile(
@@ -76,6 +83,4 @@ try {
process.stdout.write(
`${JSON.stringify({ producer: image, metadata, verified: ["ELF inventory", "code cache", "fuse", "script extraction", "asset extraction"] }, null, 2)}\n`,
);
} finally {
await rm(root, { recursive: true, force: true });
}
});
+12 -7
View File
@@ -1,13 +1,20 @@
/** Build real PE TLS samples with Zig, then inspect through the public CLI. */
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdtemp, writeFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import {
VerifierFixture,
withVerifierFixture,
} from "./lib/verifier-fixture.mjs";
const zig = process.env.REA_ZIG ?? "zig";
const root = await mkdtemp(join(tmpdir(), "rea-pe-load-config-"));
try {
const rootFixture = await VerifierFixture.open({
prefix: "rea-pe-load-config-",
private: false,
});
const root = rootFixture.path;
await withVerifierFixture(rootFixture, async () => {
const source = join(root, "tls.c");
await writeFile(
source,
@@ -77,6 +84,4 @@ void entry(void) {}
}),
);
}
} finally {
await rm(root, { recursive: true, force: true });
}
});
+9 -14
View File
@@ -8,18 +8,11 @@ import assert from "node:assert/strict";
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { createPackageVerifierCommands } from "./lib/verify-package-commands.mjs";
import { createHash, randomUUID } from "node:crypto";
import {
access,
constants,
mkdtemp,
readFile,
rm,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { access, constants, readFile, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { createServer } from "../dist/server/createServer.js";
import { VerifierFixture } from "./lib/verifier-fixture.mjs";
const cli = resolve("scripts/rea.mjs");
const runCli = async (...arguments_) => {
@@ -58,12 +51,14 @@ if (process.env.EXPECTED_PLATFORM !== undefined) {
"Cutter runner did not match its declared platform.",
);
}
const projectRoot = await mkdtemp(join(tmpdir(), "rea-cutter-smoke-"));
const projectFixture = await VerifierFixture.open({
prefix: "rea-cutter-smoke-",
private: false,
});
const projectRoot = projectFixture.path;
// The package command owner releases the fixture after its commands close.
const commands = await createPackageVerifierCommands({
workspace: {
path: projectRoot,
close: () => rm(projectRoot, { recursive: true, force: true }),
},
workspace: { path: projectRoot, close: () => projectFixture.release() },
});
const projectPath = join(projectRoot, "smoke.rzdb");
await withVerifierCleanup(async () => {
@@ -375,17 +375,6 @@
"src/sqlite/SqliteDatabaseProvider.ts": 1
},
"verifier-fixture-root": {
"scripts/verify-adb.mjs": 3,
"scripts/verify-binary-hardening.mjs": 1,
"scripts/verify-elf-unwind-ranges.mjs": 1,
"scripts/verify-flutter.mjs": 1,
"scripts/verify-jeb.mjs": 1,
"scripts/verify-native-calls.mjs": 1,
"scripts/verify-native-pascal-calls.mjs": 1,
"scripts/verify-native-ui.mjs": 1,
"scripts/verify-node-sea.mjs": 1,
"scripts/verify-pe-load-config.mjs": 1,
"scripts/verify-real-cutter.mjs": 1,
"scripts/verify-test-temp-hygiene.mjs": 1,
"scripts/verify-windows-native.mjs": 1
},
@@ -37,12 +37,19 @@ const runVerifier = async (
join(root, "scripts", "verify-adb.mjs"),
await readFile(new URL("../../../scripts/verify-adb.mjs", import.meta.url)),
);
await writeFile(
join(root, "scripts", "lib", "verifier-cleanup.mjs"),
await readFile(
new URL("../../../scripts/lib/verifier-cleanup.mjs", import.meta.url),
),
);
// The verifier's cleanup and fixture owners, with the fixture's imports.
for (const helper of [
"verifier-cleanup.mjs",
"verifier-fixture.mjs",
"canonical-temporary-directory.mjs",
"verifier-source-loader.mjs",
])
await writeFile(
join(root, "scripts", "lib", helper),
await readFile(
new URL(`../../../scripts/lib/${helper}`, import.meta.url),
),
);
// The simulated device directory stands in for /data/local/tmp; the fake
// adb client records its argv and removes only the named probe.
const device = join(root, "device");