From 7bcefead69bf97b45225f8cfc1ce57ce9e6903ec Mon Sep 17 00:00:00 2001
From: morluto <76467478+morluto@users.noreply.github.com>
Date: Mon, 2 Nov 2026 02:13:32 +0800
Subject: [PATCH] test: strengthen and prune audited test coverage (#8573)
* test: strengthen and prune audited test coverage
* test: require delivered DeepSeek skill instructions
* test: keep schema fixture types private
* test: verify Gemini receives skill instructions
* test: bind Qwen skill evidence to its tool result
* test: report NativeAOT verifier checks precisely
* fix: verify Ghidra cleanup paths reliably
* fix: verify Command Code skill activation
* test: tighten cleanup and fixture checks
* test: verify packet capture evidence is recorded
* fix: report HTTP3 capture provenance accurately
* test: preserve resource coverage through MCP
* test: prune repeated assertions and retain cancellation identity
* fix: validate client verifier fixture paths
* test: skip Copilot verifier cases on Windows
* test: keep verifier setup target relative
---
docs/adb-device-analysis.md | 8 +-
docs/testing.md | 10 +-
scripts/lib/test-discovery.d.mts | 5 +
scripts/lib/test-discovery.mjs | 9 ++
scripts/test-website.py | 6 +-
scripts/verify-adb.mjs | 88 ++--------
scripts/verify-bun-standalone.mjs | 5 +-
scripts/verify-claude-client.mjs | 7 +-
scripts/verify-commandcode-client.mjs | 39 ++++-
scripts/verify-copilot-client.mjs | 5 +-
scripts/verify-deepseek-client.mjs | 46 ++++--
scripts/verify-flutter.mjs | 4 +
scripts/verify-frida.mjs | 6 +-
scripts/verify-gemini-client.mjs | 68 +++++---
scripts/verify-grok-client.mjs | 5 +-
scripts/verify-http3-network-captures.mjs | 6 +-
scripts/verify-il2cpp-metadata.mjs | 8 +-
scripts/verify-jeb.mjs | 10 +-
scripts/verify-omp-client.mjs | 7 +-
scripts/verify-opencode-client.mjs | 22 +--
scripts/verify-package.mjs | 1 -
scripts/verify-qwen-client.mjs | 39 +++--
scripts/verify-real-cutter.mjs | 9 +-
scripts/verify-real-electron.mjs | 6 +-
scripts/verify-real-ghidra-assertions.mjs | 9 +-
scripts/verify-real-ghidra-function.mjs | 6 +-
scripts/verify-real-ghidra-nativeaot.mjs | 7 +-
scripts/verify-test-discovery.mjs | 3 +-
.../javascript/application-workflows.mjs | 10 +-
.../verify/javascript/runtime-observation.mjs | 64 +++++++-
.../BrowserScenarioCaptureService.test.ts | 32 ++++
src/application/WebRuntimeService.test.ts | 7 +
.../WebSourceLocationService.test.ts | 25 ++-
.../electron/ElectronFuseService.test.ts | 14 +-
.../ElectronObservationService.test.ts | 17 +-
.../JavaScriptAnalysisControl.test.ts | 33 +++-
.../JavaScriptRecoveryService.test.ts | 13 +-
.../ManagedReconstructionService.test.ts | 34 +---
src/artifacts/ArtifactPaths.test.ts | 2 +-
.../BundleResourceArtifactClient.test.ts | 60 -------
src/artifacts/FitArtifactReader.test.ts | 35 ++++
src/artifacts/FitArtifactReader.ts | 1 +
src/artifacts/GodotPckArtifactReader.test.ts | 15 --
.../UImageArtifactReader.boundaries.test.ts | 28 +++-
src/artifacts/pyinstaller/CArchive.fixture.ts | 7 +-
.../PyInstallerArtifactReader.test.ts | 61 -------
src/browser/BrowserScenario.test.ts | 3 -
.../PlaywrightElectronActiveActions.test.ts | 2 -
src/config.test.ts | 6 +
src/domain/bundleComparison.test.ts | 33 ----
src/domain/changedBehavior.test.ts | 8 -
src/domain/ghidraValues.fixture.ts | 2 +-
.../managedNativeVerificationSource.test.ts | 2 +-
src/domain/native/peImports.test.ts | 44 -----
src/dotnet/ManagedArtifactInspector.test.ts | 17 --
src/dotnet/ManagedCilDecoding.test.ts | 8 -
src/dotnet/ManagedFieldConstants.test.ts | 11 +-
src/dotnet/ManagedMemberInspector.test.ts | 11 +-
.../ManagedNativeBoundaryInspector.test.ts | 9 +-
src/dotnet/ManagedSignatureResolution.test.ts | 2 +-
src/electron/ElectronFuseProvider.test.ts | 12 +-
src/flutter/FlutterPayloadScan.test.ts | 8 +-
src/ghidra/GhidraFunctionValues.test.ts | 11 ++
src/ida/IdaContainment.test.ts | 10 +-
src/ida/IdaOperationFailures.test.ts | 1 +
src/kuna/KunaProjectCache.ts | 14 +-
src/kuna/KunaTargetCommands.ts | 20 ++-
src/native/elf/KernelModule.fixture.ts | 10 +-
.../ProcessOwnership.nativeExit.test.ts | 5 +-
src/process/RegexMatcher.test.ts | 3 -
src/reference/ReferenceSourceReader.test.ts | 2 +-
.../RustBinaryImage.machoAlignment.test.ts | 26 ---
src/server/BundleResourcesMcp.test.ts | 51 ++++--
src/server/runDerivedOperation.test.ts | 17 --
.../applications/electronBlankPathCli.test.ts | 2 +-
.../electronDynamicIpcHandlersCli.test.ts | 2 +-
.../asarSelectedCompanionCli.test.ts | 17 +-
tests/acceptance/bunStandaloneCli.test.ts | 2 +-
tests/acceptance/godotPck.test.ts | 2 +-
.../acceptance/sourcePathFailuresCli.test.ts | 2 +-
.../cli/ampRegistrationPreservation.test.ts | 2 +
.../boundary/cli/bundleComparisonCli.test.ts | 6 +-
.../cli/cliEvidenceCallerPath.test.ts | 9 +-
.../cli/cliInputSchemaRequired.test.ts | 6 +-
.../cli/cutterVerifierPlatform.test.ts | 81 ++++++++++
.../cli/evidenceBundleCommands.test.ts | 2 +-
tests/boundary/cli/pcapCli.test.ts | 9 --
.../cli/reverseEngineeringCommands.test.ts | 8 +-
.../evm/evmoleInterfaceProvider.test.ts | 16 +-
.../filesystem/asarSelectedCompanion.test.ts | 34 ----
.../filesystem/bufferDeepEqualityLint.test.ts | 8 -
.../filesystem/ciCacheRetention.test.ts | 46 +++++-
tests/boundary/filesystem/ciFeedback.test.ts | 12 --
.../filesystem/ciJobTimingsBatch.test.ts | 23 +--
tests/boundary/filesystem/ciPrHealth.test.ts | 56 ++++---
.../boundary/filesystem/ciTestHistory.test.ts | 43 ++---
.../filesystem/ghidraBridgeSources.test.ts | 6 +
.../ghidraInstallationProperties.test.ts | 1 +
.../ghidraLanguageCatalogRecovery.test.ts | 3 +-
...avascriptPackageRendererProvenance.test.ts | 7 -
tests/boundary/filesystem/pythonPyc.test.ts | 5 +-
.../boundary/filesystem/releaseNotes.test.ts | 5 -
.../boundary/go/goBinaryFinalization.test.ts | 1 +
tests/boundary/go/goBinaryImage.test.ts | 2 +
.../go/goBinaryP32PointerWidth.test.ts | 32 ----
tests/boundary/gpu/codeObjects.test.ts | 9 +-
.../boundary/il2cpp/il2cppBinaryFile.test.ts | 10 +-
.../mcp/cutterCancellationMcp.test.ts | 2 +-
.../mcp/enhancedTools.swiftTypes.test.ts | 17 +-
tests/boundary/mcp/flutterMcp.test.ts | 9 ++
.../javascriptRuntimeObservationMcp.test.ts | 9 ++
tests/boundary/mcp/managedMcp.test.ts | 10 ++
...> modelArtifactPartialReadFailure.test.ts} | 10 +-
tests/boundary/mcp/pcapMcp.test.ts | 7 +
tests/boundary/mcp/promptMcp.test.ts | 11 +-
tests/boundary/mcp/toolResult.test.ts | 3 +-
tests/boundary/mcp/universalSliceMcp.test.ts | 1 +
tests/boundary/model/modelArtifact.test.ts | 5 +-
.../process/adbVerifierCleanup.test.ts | 26 ++-
.../applicationWorkflowVerifier.test.ts | 64 +++++++-
.../bunVerifierOwnerInitialization.test.ts | 80 ++++++++++
.../claudeVerifierSetupTargets.test.ts | 94 +++++++++++
.../clientVerifierSetupTargets.test.ts | 99 ++++++++++++
.../commandcodeVerifierSkillBody.test.ts | 138 ++++++++++++++++
.../process/deepseekVerifierSkillBody.test.ts | 82 ++++++++++
.../process/flutterVerifierDefaultAbi.test.ts | 28 ++++
tests/boundary/process/fridaVerifier.test.ts | 70 ++++++++
.../process/geminiVerifierSkillBody.test.ts | 76 +++++++++
.../process/ghidraJavaLifecycle.test.ts | 3 +
.../process/ghidraVerifierAssertions.test.ts | 45 ++++++
.../javascriptVerifierBoundedEvidence.test.ts | 150 ++++++++++++++++++
tests/boundary/process/jebVerifier.test.ts | 65 ++++++++
.../process/qwenVerifierSkillBody.test.ts | 58 +++++++
.../RizinDebugSessionCoverage.part1.test.ts | 22 ---
.../providers/auxiliaryDeclarations.test.ts | 8 +-
.../providers/cutterBridgeProducer.test.ts | 8 +-
.../providers/jeb/failureEnvelopes.test.ts | 1 -
.../kuna/kunaCommandFailures.test.ts | 97 ++++++++++-
.../providers/kuna/kunaProjectCache.test.ts | 38 ++++-
.../managed/managedHashCancellation.test.ts | 1 +
...anagedMemberComparisonFromMetadata.test.ts | 95 +++++------
.../managed/managedStaticProvider.test.ts | 32 ++--
tests/composition/idaProvider.test.ts | 4 +
.../ghidra/realGhidraWindowsWorkflow.test.ts | 11 ++
.../managed/managedNativeVerification.test.ts | 15 --
.../evidenceJsonPreadmissionRule.test.ts | 8 -
.../model-evals/agentEvaluationReport.test.ts | 6 -
tests/evaluation/testDiscovery.test.ts | 18 ++-
tests/fixtures/android/jniElf.ts | 2 +-
tests/fixtures/binaryDiagnostics/appleIps.ts | 2 +-
.../binaryDiagnostics/nativeExports.ts | 6 +-
tests/fixtures/binaryDiagnostics/peImports.ts | 4 +-
tests/fixtures/cutter_bridge_protocol_test.py | 45 ++++--
tests/fixtures/electron/fuseImage.ts | 23 +--
.../fixtures/environmentStateDerivedValues.ts | 2 +-
tests/fixtures/environmentStateItemWrites.ts | 2 +-
tests/fixtures/environmentStateWrites.ts | 6 +-
tests/fixtures/fakeCdpBrowserEvents.ts | 2 +-
tests/fixtures/fakeCdpBrowserTypes.ts | 1 -
tests/fixtures/flutterVerifierPreload.mjs | 34 ++++
tests/fixtures/il2cpp/metadata.ts | 6 +-
tests/fixtures/mcpAdvertisedSchemaValidity.ts | 2 +-
tests/fixtures/sqlite/database.ts | 2 +-
tests/fixtures/uimage.ts | 9 +-
tests/fixtures/unityfs.ts | 4 +-
.../ghidraLaunchRollback.test.ts | 7 +-
tests/process-global/shortFileReads.test.ts | 4 +-
167 files changed, 2396 insertions(+), 1012 deletions(-)
delete mode 100644 src/artifacts/BundleResourceArtifactClient.test.ts
delete mode 100644 src/domain/native/peImports.test.ts
delete mode 100644 src/rust/RustBinaryImage.machoAlignment.test.ts
create mode 100644 tests/boundary/cli/cutterVerifierPlatform.test.ts
delete mode 100644 tests/boundary/go/goBinaryP32PointerWidth.test.ts
rename tests/boundary/mcp/{modelArtifactPartialCancellation.test.ts => modelArtifactPartialReadFailure.test.ts} (95%)
create mode 100644 tests/boundary/process/bunVerifierOwnerInitialization.test.ts
create mode 100644 tests/boundary/process/claudeVerifierSetupTargets.test.ts
create mode 100644 tests/boundary/process/clientVerifierSetupTargets.test.ts
create mode 100644 tests/boundary/process/commandcodeVerifierSkillBody.test.ts
create mode 100644 tests/boundary/process/deepseekVerifierSkillBody.test.ts
create mode 100644 tests/boundary/process/flutterVerifierDefaultAbi.test.ts
create mode 100644 tests/boundary/process/fridaVerifier.test.ts
create mode 100644 tests/boundary/process/geminiVerifierSkillBody.test.ts
create mode 100644 tests/boundary/process/javascriptVerifierBoundedEvidence.test.ts
create mode 100644 tests/boundary/process/jebVerifier.test.ts
create mode 100644 tests/boundary/process/qwenVerifierSkillBody.test.ts
create mode 100644 tests/fixtures/flutterVerifierPreload.mjs
diff --git a/docs/adb-device-analysis.md b/docs/adb-device-analysis.md
index 634a004b0a..1dfcb826da 100644
--- a/docs/adb-device-analysis.md
+++ b/docs/adb-device-analysis.md
@@ -257,12 +257,12 @@ beyond already-connected devices (`adb connect`) are not exposed yet.
## Real verification
-`npm run verify:adb` exercises every operation against a live device. It
+`npm run verify:adb` exercises observation and transfer operations against a live device. It
requires `adb` (or `REA_ADB_PATH`) and any attached emulator or phone;
`--serial` selects one when several are attached, `--pull PACKAGE` pulls a
-real package and verifies the returned digests against the files on disk,
-and `--install-apk PATH` drives a full install → resolve → uninstall
-lifecycle with a lane-owned probe.
+real package and verifies the returned digests against the files on disk.
+The optional `--install-apk` lifecycle is unavailable until the selected APK
+identity and device cleanup ownership can be established safely.
Record: verified against adb 34.0.5 on Linux against an Android 14
(API 34) x86_64 emulator — all operations above, a 224-package inventory,
diff --git a/docs/testing.md b/docs/testing.md
index d619d375c3..19e3c60d5e 100644
--- a/docs/testing.md
+++ b/docs/testing.md
@@ -1423,12 +1423,12 @@ budgets.
## ADB device acquisition
-`npm run verify:adb` exercises every ADB operation against a live device or
+`npm run verify:adb` exercises ADB observation and transfer operations against a live device or
emulator through the caller's adb binary (`REA_ADB_PATH` or PATH). No SDK
-installation or emulator management is involved; the device-mutating tools
-run only in the explicit lifecycle section (`--install-apk` drives a
-lane-owned install → resolve → start → observe → force-stop → uninstall
-probe). `--pull` acquires a real package and re-digests the pulled files on
+installation or emulator management is involved. `--install-apk` is unavailable
+until the selected APK identity and device cleanup ownership can be established
+safely. The transfer probe creates and removes a temporary device file. `--pull`
+acquires a real package and re-digests the pulled files on
disk against the returned SHA-256 values; `--serial` selects a device when
several are attached.
diff --git a/scripts/lib/test-discovery.d.mts b/scripts/lib/test-discovery.d.mts
index 259a21fbb8..54b6d1f3ee 100644
--- a/scripts/lib/test-discovery.d.mts
+++ b/scripts/lib/test-discovery.d.mts
@@ -10,5 +10,10 @@ export function compareTestDiscovery(
readonly file: string;
readonly projects: readonly string[];
}[];
+ readonly wrongProjects: readonly {
+ readonly file: string;
+ readonly expected: string;
+ readonly actual: string;
+ }[];
readonly discovered: number;
};
diff --git a/scripts/lib/test-discovery.mjs b/scripts/lib/test-discovery.mjs
index dbcafb220a..99af5bc6b7 100644
--- a/scripts/lib/test-discovery.mjs
+++ b/scripts/lib/test-discovery.mjs
@@ -1,4 +1,5 @@
import { relative, resolve } from "node:path";
+import { projectForTest } from "./test-projects.mjs";
/** Compare actual Vitest discovery with repository-owned test paths. */
export const compareTestDiscovery = (expectedPaths, discovery, root) => {
@@ -36,6 +37,14 @@ export const compareTestDiscovery = (expectedPaths, discovery, root) => {
const projects = projectsByFile.get(file);
return projects.length > 1 ? [{ file, projects: sorted(projects) }] : [];
}),
+ wrongProjects: sorted(expected).flatMap((file) => {
+ const projects = projectsByFile.get(file);
+ if (!projects || projects.length !== 1) return [];
+ const expectedProject = projectForTest(file).name;
+ return projects[0] === expectedProject
+ ? []
+ : [{ file, expected: expectedProject, actual: projects[0] }];
+ }),
discovered: projectsByFile.size,
};
};
diff --git a/scripts/test-website.py b/scripts/test-website.py
index 54b4679585..227dd4b122 100644
--- a/scripts/test-website.py
+++ b/scripts/test-website.py
@@ -539,11 +539,13 @@ class WebsiteMaintenanceChecks(unittest.TestCase):
self.assertIn(b"color: black", response.read())
with self.assertRaises(HTTPError) as error:
urlopen(base + prefix + "missing")
- self.assertEqual(error.exception.code, 404)
+ with contextlib.closing(error.exception) as response:
+ self.assertEqual(response.code, 404)
if prefix != "/":
with self.assertRaises(HTTPError) as error:
urlopen(base + "/guide/")
- self.assertEqual(error.exception.code, 404)
+ with contextlib.closing(error.exception) as response:
+ self.assertEqual(response.code, 404)
finally:
server.shutdown()
worker.join()
diff --git a/scripts/verify-adb.mjs b/scripts/verify-adb.mjs
index 58183f04a1..8d0685c908 100644
--- a/scripts/verify-adb.mjs
+++ b/scripts/verify-adb.mjs
@@ -15,8 +15,10 @@ if (options.help) {
process.stdout.write(
"Usage: npm run verify:adb [-- --serial SERIAL --pull PACKAGE]\n" +
"Requires a caller-selected adb binary (REA_ADB_PATH or PATH) and a\n" +
- "connected device or emulator. Verifies all five operations against\n" +
- "the live device; --pull acquires a real package and re-digests the\n" +
+ "connected device or emulator. Verifies observation and transfer operations\n" +
+ "against the live device. --install-apk is unavailable until APK identity\n" +
+ "and device cleanup ownership can be established safely.\n" +
+ "--pull acquires a real package and re-digests the\n" +
"files on disk against the returned SHA-256 values.\n",
);
process.exit(0);
@@ -356,79 +358,7 @@ try {
`versionCode=${String(details.version_code)}`,
);
}
- if (options.installApk !== null && options.installApk !== undefined) {
- const probePackage = "com.rea.adb.probe";
- const installedProbe = await run("install_adb_package", {
- serial,
- apk_path: options.installApk,
- replace: false,
- });
- if (installedProbe !== null) {
- check(
- "install reports the APK digest",
- typeof installedProbe.sha256 === "string" &&
- installedProbe.sha256.length === 64,
- `${installedProbe.bytes} bytes`,
- );
- const resolved = await run("resolve_adb_packages", {
- serial,
- query: "rea.adb.probe",
- });
- if (resolved !== null)
- check(
- "resolve finds the installed probe uniquely",
- resolved.matches.length === 1 &&
- resolved.matches[0]?.package_name === probePackage,
- `${resolved.matches.length} match(es)`,
- );
- const started = await run("start_adb_app", {
- serial,
- package: probePackage,
- });
- if (started !== null)
- check(
- "app start resolves and launches the launcher activity",
- typeof started.component === "string" &&
- started.component.startsWith(probePackage),
- String(started.component),
- );
- const observedProcesses = await run("list_adb_processes", { serial });
- if (observedProcesses !== null)
- check(
- "started app appears in the process listing",
- observedProcesses.processes.some(
- (process) => process.name === probePackage,
- ),
- );
- const stopped = await run("stop_adb_app", {
- serial,
- package: probePackage,
- });
- if (stopped !== null)
- check(
- "force-stop completes the dynamic-analysis run",
- stopped.package_name === probePackage,
- );
- const removed = await run("uninstall_adb_package", {
- serial,
- package: probePackage,
- });
- if (removed !== null)
- check(
- "uninstall completes the lifecycle",
- removed.package_name === probePackage,
- );
- const afterRemoval = await run("resolve_adb_packages", {
- serial,
- query: "rea.adb.probe",
- });
- if (afterRemoval !== null)
- check(
- "resolve reports zero matches after removal",
- afterRemoval.matches.length === 0,
- );
- }
- }
+
} finally {
await rm(transferRoot, { recursive: true, force: true });
}
@@ -459,7 +389,7 @@ if (failures > 0) {
}
function parseArguments(argv) {
- const parsed = { help: false, serial: null, pull: null, installApk: null };
+ const parsed = { help: false, serial: null, pull: null };
for (let index = 0; index < argv.length; index += 1) {
const argument = argv[index];
if (argument === "--help" || argument === "-h") parsed.help = true;
@@ -470,8 +400,10 @@ function parseArguments(argv) {
parsed.pull = argv[index + 1] ?? null;
index += 1;
} else if (argument === "--install-apk") {
- parsed.installApk = argv[index + 1] ?? null;
- index += 1;
+ process.stderr.write(
+ "--install-apk is unavailable: APK identity and device cleanup ownership cannot be established safely\n",
+ );
+ process.exit(1);
} else {
process.stderr.write(`unknown argument: ${argument}\n`);
process.exit(2);
diff --git a/scripts/verify-bun-standalone.mjs b/scripts/verify-bun-standalone.mjs
index 19d8e0024c..82b6f7edda 100644
--- a/scripts/verify-bun-standalone.mjs
+++ b/scripts/verify-bun-standalone.mjs
@@ -8,7 +8,7 @@ import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
const root = await PrivateRuntimeRoot.create({ prefix: "rea-bun-verifier-" });
-const commands = await createVerifierCommands();
+let commands;
const run = (command, args, options = {}) =>
commands.exec(command, args, {
timeout: 120_000,
@@ -19,6 +19,7 @@ const run = (command, args, options = {}) =>
// only after every owned command family has settled.
let commandsClosed = false;
await withVerifierCleanup(async () => {
+ commands = await createVerifierCommands();
const source = join(root.path, "hello.ts");
await writeFile(source, 'console.log("REA_BUN_VERIFICATION");\n');
const docker = process.argv.includes("--docker");
@@ -104,7 +105,7 @@ await withVerifierCleanup(async () => {
);
}, [
async () => {
- await commands.close();
+ if (commands !== undefined) await commands.close();
commandsClosed = true;
},
async () => {
diff --git a/scripts/verify-claude-client.mjs b/scripts/verify-claude-client.mjs
index 4ed2a7356d..94a4366bb5 100644
--- a/scripts/verify-claude-client.mjs
+++ b/scripts/verify-claude-client.mjs
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
-import { join } from "node:path";
+import { isAbsolute, join } from "node:path";
import { fileURLToPath } from "node:url";
import Ajv2020 from "ajv/dist/2020.js";
import { createCatalogIdentity } from "../dist/catalogIdentity.js";
@@ -15,6 +15,7 @@ import {
TOOL_CONTRACTS,
toolContract,
} from "../dist/contracts/toolContracts.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
@@ -306,7 +307,9 @@ await withVerifierCleanup(async () => {
assert(
parsed.plannedActions.every(
(a) =>
- a.target === configPath || a.target.startsWith(skillDirectory),
+ a.target === configPath ||
+ (isAbsolute(a.target) &&
+ isPathWithinRoot(skillDirectory, a.target)),
),
);
}
diff --git a/scripts/verify-commandcode-client.mjs b/scripts/verify-commandcode-client.mjs
index e88fa3ee9f..70d6f5f565 100644
--- a/scripts/verify-commandcode-client.mjs
+++ b/scripts/verify-commandcode-client.mjs
@@ -6,6 +6,7 @@ import { isAbsolute, join, relative } from "node:path";
import { fileURLToPath } from "node:url";
import Ajv2020 from "ajv/dist/2020.js";
import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
@@ -54,6 +55,7 @@ const expectedNames = TOOL_CONTRACTS.map(
).sort();
let clientVersion = null;
let expectedSkill;
+let skillCallId;
let inventoryChecked = false;
let catalogSize = null;
let skillLoaded = false;
@@ -180,10 +182,24 @@ await withVerifierCleanup(async () => {
finalSeen = true;
return { role: "assistant", content: "REA_CLIENT_COMPATIBILITY_OK" };
}
- if (stage === 0)
- return call("activate_skill", { name: "reverse-engineer-anything" });
+ if (stage === 0) {
+ const request = call("activate_skill", {
+ name: "reverse-engineer-anything",
+ });
+ skillCallId = request.tool_calls[0].id;
+ return request;
+ }
assert(
- strings.some((text) => text.includes(expectedSkill)),
+ skillCallId !== undefined &&
+ expectedSkill !== undefined &&
+ body.messages.some(
+ (message) =>
+ message.role === "tool" &&
+ message.tool_call_id === skillCallId &&
+ textValues(message.content).some((text) =>
+ text.includes(expectedSkill),
+ ),
+ ),
"The model must receive the complete activated skill body",
);
skillLoaded = true;
@@ -322,8 +338,8 @@ await withVerifierCleanup(async () => {
result.plannedActions.every(
(action) =>
action.target === configPath ||
- action.target === skillDirectory ||
- action.target.startsWith(skillDirectory + "/"),
+ (isAbsolute(action.target) &&
+ isPathWithinRoot(skillDirectory, action.target)),
),
"Refuse setup writes outside the disposable account's configuration and skill",
);
@@ -342,9 +358,16 @@ await withVerifierCleanup(async () => {
assert.deepEqual(repeated.appliedActions, []);
assert.equal(await readFile(configPath, "utf8"), configured);
assert.equal(await readFile(`${configPath}.rea.backup`, "utf8"), original);
- expectedSkill = (await readFile(join(skillDirectory, "SKILL.md"), "utf8"))
- .replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, "")
- .trim();
+ const installedSkill = await readFile(
+ join(skillDirectory, "SKILL.md"),
+ "utf8",
+ );
+ const frontmatter = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/u.exec(
+ installedSkill,
+ );
+ assert(frontmatter, "Installed skill must have authored frontmatter");
+ expectedSkill = installedSkill.slice(frontmatter[0].length).trim();
+ assert(expectedSkill.length > 0, "Installed skill body must not be empty");
const response = await saveVerifierCommandOutput(
() =>
commands.exec(
diff --git a/scripts/verify-copilot-client.mjs b/scripts/verify-copilot-client.mjs
index acf9f9eba3..3f61f89d2a 100644
--- a/scripts/verify-copilot-client.mjs
+++ b/scripts/verify-copilot-client.mjs
@@ -12,6 +12,7 @@ import {
import { advertisedInputJsonSchema } from "../dist/contracts/toolSchemaMetadata.js";
import { presentAdvertisedInputSchema } from "../dist/contracts/compactInputSchema.js";
import { compactPresentationForMcpInputSchemaProfile } from "../dist/config/mcpInputSchemaProfile.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
@@ -300,8 +301,8 @@ await withVerifierCleanup(async () => {
parsed.plannedActions.every(
(a) =>
a.target === configPath ||
- a.target === skillDirectory ||
- a.target.startsWith(skillDirectory + "/"),
+ (isAbsolute(a.target) &&
+ isPathWithinRoot(skillDirectory, a.target)),
),
);
}
diff --git a/scripts/verify-deepseek-client.mjs b/scripts/verify-deepseek-client.mjs
index 9b800422f9..1d960a0ec0 100644
--- a/scripts/verify-deepseek-client.mjs
+++ b/scripts/verify-deepseek-client.mjs
@@ -56,6 +56,7 @@ let catalog;
let patternCount = 0;
let skillRequested = false;
let skillLoaded = false;
+let expectedSkillBody;
let evidenceSeen = false;
let finalSeen = false;
let artifactDigest;
@@ -169,11 +170,34 @@ await withVerifierCleanup(async () => {
const toolMessages = (body.messages ?? []).filter(
(message) => message.role === "tool",
);
- const serialized = JSON.stringify(toolMessages);
- skillLoaded ||=
- serialized.includes(
- '',
- ) && serialized.includes(dirname(skillPath));
+ skillLoaded ||= toolMessages.some((message) => {
+ if (
+ typeof message.content !== "string" ||
+ expectedSkillBody === undefined
+ )
+ return false;
+ const open =
+ '\n\n';
+ const start = message.content.indexOf(open);
+ if (start < 0) return false;
+ const resourcesStart = start + open.length;
+ const instructions = `\n\n\n\n${expectedSkillBody}\n\n`;
+ const resourcesEnd = message.content.indexOf(
+ instructions,
+ resourcesStart,
+ );
+ if (resourcesEnd < 0) return false;
+ const expectedPath = dirname(skillPath)
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">");
+ const resources = message.content.slice(resourcesStart, resourcesEnd);
+ return (
+ !resources.includes("") &&
+ !resources.includes("") &&
+ resources.includes(expectedPath)
+ );
+ });
for (const message of toolMessages) {
const found = findClientResult(
message.content,
@@ -281,11 +305,15 @@ await withVerifierCleanup(async () => {
const configured = await readFile(configPath, "utf8");
assert.deepEqual(withoutRea(configured), withoutRea(original));
assert(configured.includes("!!js process.cwd()"));
- assert(
- (await readFile(skillPath, "utf8")).includes(
- "name: reverse-engineer-anything",
- ),
+ const installedSkill = await readFile(skillPath, "utf8");
+ assert(installedSkill.includes("name: reverse-engineer-anything"));
+ const frontmatter = /^---\r?\n[\s\S]*?^---(?:\r?\n|$)/mu.exec(
+ installedSkill,
);
+ assert(frontmatter, "Installed skill must have its authored frontmatter");
+ expectedSkillBody = installedSkill.slice(frontmatter[0].length).trim();
+ assert(expectedSkillBody.length > 0);
+
lifecycle.push("setup");
const repeated = await runRea(
["setup", "--client", "dsh", "--yes"],
diff --git a/scripts/verify-flutter.mjs b/scripts/verify-flutter.mjs
index b20d76d72b..0425711fda 100644
--- a/scripts/verify-flutter.mjs
+++ b/scripts/verify-flutter.mjs
@@ -104,6 +104,10 @@ await withVerifierCleanup(
}
// 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
diff --git a/scripts/verify-frida.mjs b/scripts/verify-frida.mjs
index e42bd4a805..396ddf4f88 100644
--- a/scripts/verify-frida.mjs
+++ b/scripts/verify-frida.mjs
@@ -2,7 +2,7 @@ import { basename } from "node:path";
import { FridaInstrumentationService } from "../dist/application/frida/FridaInstrumentationService.js";
import { FridaInstrumentationManager } from "../dist/frida/FridaInstrumentationManager.js";
-import { isValidFridaRemoteAddress } from "../dist/contracts/fridaRemoteAddress.js";
+import { isValidFridaRemoteAddress } from "../dist/domain/fridaRemoteAddress.js";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
const options = parseArguments(process.argv.slice(2));
@@ -80,6 +80,10 @@ try {
!Array.isArray(observed.messages)
)
throw new Error("Frida returned no message observation");
+ if (!Number.isSafeInteger(observed.pid) || observed.pid <= 0)
+ throw new Error("Frida returned no valid target PID");
+ if (remote !== undefined && observed.pid !== options.pid)
+ throw new Error("Frida observed a different target PID");
const messageObserved = observed.messages.some(
(message) =>
typeof message === "object" &&
diff --git a/scripts/verify-gemini-client.mjs b/scripts/verify-gemini-client.mjs
index 9837ad53dd..eab017d6b4 100644
--- a/scripts/verify-gemini-client.mjs
+++ b/scripts/verify-gemini-client.mjs
@@ -2,13 +2,14 @@ import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
-import { join, resolve, sep } from "node:path";
+import { isAbsolute, join, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import Ajv2020 from "ajv/dist/2020.js";
import {
TOOL_CONTRACTS,
toolContract,
} from "../dist/contracts/toolContracts.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
@@ -65,6 +66,7 @@ let fixture;
let passed = false;
let evidenceSeen = false;
let skillLoaded = false;
+let expectedSkillBody;
let skillRequested = false;
let finalSeen = false;
let catalogSize = null;
@@ -150,13 +152,21 @@ await withVerifierCleanup(async () => {
if (args.includes("--dry-run")) {
assert(parsed.plannedActions.some((a) => a.target === configPath));
assert(
- parsed.plannedActions.some((a) =>
- a.target.startsWith(join(profile, ".agents", "skills") + sep),
- ),
+ parsed.plannedActions.some((a) => {
+ const skills = join(profile, ".agents", "skills");
+ return (
+ isAbsolute(a.target) &&
+ relative(skills, a.target) !== "" &&
+ isPathWithinRoot(skills, a.target)
+ );
+ }),
);
assert(
- parsed.plannedActions.every((a) =>
- a.target.startsWith(profile + sep),
+ parsed.plannedActions.every(
+ (a) =>
+ isAbsolute(a.target) &&
+ relative(profile, a.target) !== "" &&
+ isPathWithinRoot(profile, a.target),
),
);
}
@@ -189,11 +199,15 @@ await withVerifierCleanup(async () => {
assert.deepEqual(JSON.parse(repeated.stdout).appliedActions, []);
assert.equal(await readFile(configPath, "utf8"), configured);
assert.equal(await readFile(`${configPath}.rea.backup`, "utf8"), original);
- assert(
- (await readFile(skillPath, "utf8")).includes(
- "name: reverse-engineer-anything",
- ),
+ const installedSkill = await readFile(skillPath, "utf8");
+ assert(installedSkill.includes("name: reverse-engineer-anything"));
+ const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n([\s\S]*))?/u.exec(
+ installedSkill,
);
+ assert(frontmatter, "Installed skill must have authored frontmatter");
+ expectedSkillBody = (frontmatter[2] ?? "").trim();
+ assert(expectedSkillBody.length > 0);
+
const target = join(lab, "fixture α测试");
await mkdir(target);
await writeFile(join(target, "app.js"), CLIENT_JAVASCRIPT_FIXTURE_SOURCE);
@@ -268,16 +282,32 @@ await withVerifierCleanup(async () => {
.flatMap((c) => c.parts ?? [])
.filter((p) => p.functionResponse)
.map((p) => p.functionResponse);
- skillLoaded ||= responses.some(
- (r) =>
- r.name === "activate_skill" &&
- r.response?.output?.includes(
- ``,
- ) &&
- r.response.output.includes(
+ skillLoaded ||= responses.some((response) => {
+ const output = response.response?.output;
+ if (
+ response.name !== "activate_skill" ||
+ typeof output !== "string" ||
+ expectedSkillBody === undefined
+ )
+ return false;
+ const start = `\n \n ${expectedSkillBody}\n \n\n \n `;
+ const at = output.indexOf(start);
+ if (at < 0) return false;
+ const resourcesStart = at + start.length;
+ const resourcesEnd = output.indexOf(
+ "\n \n",
+ resourcesStart,
+ );
+ if (resourcesEnd < 0) return false;
+ const resources = output.slice(resourcesStart, resourcesEnd);
+ return (
+ !resources.includes("") &&
+ !resources.includes("") &&
+ resources.includes(
join(profile, ".agents", "skills", "reverse-engineer-anything"),
- ),
- );
+ )
+ );
+ });
const observed = findClientResult(
responses,
isClientJavaScriptEvidence,
diff --git a/scripts/verify-grok-client.mjs b/scripts/verify-grok-client.mjs
index 753c8ae998..0ea587e45f 100644
--- a/scripts/verify-grok-client.mjs
+++ b/scripts/verify-grok-client.mjs
@@ -6,6 +6,7 @@ import { isAbsolute, join, relative } from "node:path";
import { fileURLToPath } from "node:url";
import Ajv2020 from "ajv/dist/2020.js";
import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
@@ -402,8 +403,8 @@ enabled = false
parsed.plannedActions.every(
(action) =>
action.target === configPath ||
- action.target === skillDirectory ||
- action.target.startsWith(skillDirectory + "/"),
+ (isAbsolute(action.target) &&
+ isPathWithinRoot(skillDirectory, action.target)),
),
"Refuse writes outside the owned profile/skill",
);
diff --git a/scripts/verify-http3-network-captures.mjs b/scripts/verify-http3-network-captures.mjs
index 55997a95dc..130a55802b 100644
--- a/scripts/verify-http3-network-captures.mjs
+++ b/scripts/verify-http3-network-captures.mjs
@@ -373,6 +373,7 @@ try {
}
const report = {
run_id: run.run_id,
+ input_mode: inspectExisting ? "existing-captures" : "producer-attempt",
status: primaryError || cleanupFailures.length ? "failed" : "passed",
finished_at: new Date().toISOString(),
...(primaryError
@@ -386,8 +387,11 @@ const report = {
verifier,
producer_audit: producerAudit,
scope:
- "Real Linux reverse HTTP/3, mitmproxy 12.2.3, aioquic 1.2.0 and guest cURL",
+ "Linux reverse HTTP/3 capture verification for mitmproxy 12.2.3, aioquic 1.2.0 and guest cURL",
limitations: [
+ ...(inspectExisting
+ ? ["Existing capture producer provenance was not authenticated by this attempt."]
+ : []),
"No local/WireGuard, browser, QUIC v2, migration, 0-RTT, mTLS or replay claim.",
"No HAR, interruption, certificate-failure or body-completeness coverage in this profile.",
],
diff --git a/scripts/verify-il2cpp-metadata.mjs b/scripts/verify-il2cpp-metadata.mjs
index 5bc7d1d6f8..362208cd09 100644
--- a/scripts/verify-il2cpp-metadata.mjs
+++ b/scripts/verify-il2cpp-metadata.mjs
@@ -17,7 +17,7 @@ import { hashVerifierFile } from "./lib/verifier-file-resources.mjs";
const args = process.argv.slice(2);
if (args.includes("--help") || args.includes("-h")) {
console.log(
- "Usage: npm run verify:il2cpp:metadata -- [--metadata PATH]\nPATH is a caller-owned, unencrypted global-metadata.dat (version 24, 27, 29, 31 or 39). Without --metadata, only the advertised contract is verified.",
+ "Usage: npm run verify:il2cpp:metadata -- [--metadata PATH]\nPATH is a caller-owned, unencrypted global-metadata.dat (version 24, 27, 29, 31 or 39). Without --metadata, only the MCP tool name is checked.",
);
process.exit(0);
}
@@ -178,4 +178,8 @@ await withVerifierCleanup(async () => {
);
}
}, [() => client.close(), () => transport.close(), () => resources.close()]);
-console.log("All asserted IL2CPP metadata CLI/MCP checks passed");
+console.log(
+ path === null
+ ? "IL2CPP metadata MCP tool presence check passed"
+ : "All asserted IL2CPP metadata CLI/MCP checks passed",
+);
diff --git a/scripts/verify-jeb.mjs b/scripts/verify-jeb.mjs
index 812917d73c..6abd439a5d 100644
--- a/scripts/verify-jeb.mjs
+++ b/scripts/verify-jeb.mjs
@@ -68,7 +68,9 @@ try {
});
if (!decompiled.ok) throw new Error(decompiled.error.message);
const text = decompiled.value.normalized_result.text;
- if (!text.includes(target.marker))
+ if (text.trim().length === 0)
+ throw new Error("Decompiled pseudo-code was empty");
+ if (target.marker !== undefined && !text.includes(target.marker))
throw new Error(
"Decompiled pseudo-code did not contain the fixture marker",
);
@@ -83,7 +85,7 @@ try {
open_project_observed: openRefusal === null,
...(openRefusal === null ? {} : { open_project_refusal: openRefusal }),
unit_count: units.value.normalized_result.units.length,
- decompiled_marker_observed: true,
+ decompiled_marker_observed: target.marker !== undefined,
};
}, [
async () => {
@@ -110,7 +112,7 @@ async function resolveTarget(selected, directory) {
return {
path: "/engine-side/target",
itemAddress: selected.itemAddress,
- marker: selected.marker ?? "",
+ marker: selected.marker,
};
await writeFile(
join(directory, "Hello.java"),
@@ -153,6 +155,8 @@ function parseArguments(args) {
values.set(flag, value);
index += 1;
}
+ if (values.get("--marker") === "")
+ throw new Error("--marker must not be empty");
return {
help: false,
...(values.has("--item-address")
diff --git a/scripts/verify-omp-client.mjs b/scripts/verify-omp-client.mjs
index bb2599e828..0cd3d0227b 100644
--- a/scripts/verify-omp-client.mjs
+++ b/scripts/verify-omp-client.mjs
@@ -2,9 +2,10 @@ import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
import { homedir, tmpdir } from "node:os";
-import { join, relative } from "node:path";
+import { isAbsolute, join, relative } from "node:path";
import { fileURLToPath } from "node:url";
import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
@@ -314,8 +315,8 @@ await withVerifierCleanup(async () => {
parsed.plannedActions.every(
(action) =>
action.target === configPath ||
- action.target === skillDirectory ||
- action.target.startsWith(skillDirectory + "/"),
+ (isAbsolute(action.target) &&
+ isPathWithinRoot(skillDirectory, action.target)),
),
"Refuse setup writes outside the owned config/skill",
);
diff --git a/scripts/verify-opencode-client.mjs b/scripts/verify-opencode-client.mjs
index acf39a2494..8877b4664d 100644
--- a/scripts/verify-opencode-client.mjs
+++ b/scripts/verify-opencode-client.mjs
@@ -2,10 +2,11 @@ import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
-import { isAbsolute, join, relative, sep } from "node:path";
+import { isAbsolute, join } from "node:path";
import { fileURLToPath } from "node:url";
import Ajv2020 from "ajv/dist/2020.js";
import { TOOL_CONTRACTS } from "../dist/contracts/toolContracts.js";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
@@ -49,19 +50,15 @@ const skillDirectory = join(
"skills",
"reverse-engineer-anything",
);
-const isManagedSkillTarget = (target) => {
- const value = relative(skillDirectory, target);
- return (
- value === "" ||
- (value !== ".." && !value.startsWith(`..${sep}`) && !isAbsolute(value))
- );
-};
assert.equal(
- isManagedSkillTarget(`${skillDirectory}-sibling/AGENTS.md`),
+ isPathWithinRoot(skillDirectory, `${skillDirectory}-sibling/AGENTS.md`),
false,
);
assert.equal(
- isManagedSkillTarget(join(skillDirectory, "..", "outside", "AGENTS.md")),
+ isPathWithinRoot(
+ skillDirectory,
+ join(skillDirectory, "..", "outside", "AGENTS.md"),
+ ),
false,
);
let clientVersion = null;
@@ -271,7 +268,10 @@ await withVerifierCleanup(async () => {
);
assert(
parsed.plannedActions.every(
- (a) => a.target === configPath || isManagedSkillTarget(a.target),
+ (a) =>
+ a.target === configPath ||
+ (isAbsolute(a.target) &&
+ isPathWithinRoot(skillDirectory, a.target)),
),
);
}
diff --git a/scripts/verify-package.mjs b/scripts/verify-package.mjs
index 847a092667..0e7bbf41a1 100644
--- a/scripts/verify-package.mjs
+++ b/scripts/verify-package.mjs
@@ -266,7 +266,6 @@ await withVerifierCleanup(async () => {
extractedPluginMcp: true,
targetFree: true,
targetLifecycle: true,
- boundedRegexBridge: true,
update,
mcpStartup,
mcpModuleLoading,
diff --git a/scripts/verify-qwen-client.mjs b/scripts/verify-qwen-client.mjs
index a47e0d6373..6011c6d711 100644
--- a/scripts/verify-qwen-client.mjs
+++ b/scripts/verify-qwen-client.mjs
@@ -9,9 +9,10 @@ import {
symlink,
} from "node:fs/promises";
import { tmpdir } from "node:os";
-import { join, resolve, sep } from "node:path";
+import { isAbsolute, join, relative, resolve, sep } from "node:path";
import { fileURLToPath } from "node:url";
import { createHash } from "node:crypto";
+import { isPathWithinRoot } from "../dist/domain/localPath.js";
import { createVerifierCommands } from "./lib/verify-commands.mjs";
import { saveVerifierCommandOutput } from "./lib/verifier-command-output.mjs";
import { withVerifierCleanup } from "./lib/verifier-cleanup.mjs";
@@ -58,9 +59,10 @@ let clientVersion = null;
let fixture;
let passed = false;
let evidenceSeen = false;
-let skillSeen = false;
let finalSeen = false;
let skillRequested = false;
+let skillCallId;
+let expectedSkillBody;
let searchCallId;
let analysisCallId;
let artifactReadByAgent = false;
@@ -133,8 +135,11 @@ await withVerifierCleanup(async () => {
assert(
result.plannedActions.every(
(a) =>
- a.target.startsWith(profile + sep) ||
- a.target.startsWith(sharedSkills + sep),
+ isAbsolute(a.target) &&
+ ((relative(profile, a.target) !== "" &&
+ isPathWithinRoot(profile, a.target)) ||
+ (relative(sharedSkills, a.target) !== "" &&
+ isPathWithinRoot(sharedSkills, a.target))),
),
);
await writeFile(
@@ -162,6 +167,20 @@ await withVerifierCleanup(async () => {
command: "unrelated-server",
disabled: true,
});
+ const skillFile = join(
+ sharedSkills,
+ "reverse-engineer-anything",
+ "SKILL.md",
+ );
+ const normalizedSkill = (await readFile(skillFile, "utf8"))
+ .replace(/^\uFEFF/u, "")
+ .replace(/\r\n|\r/gu, "\n");
+ const frontmatter = /^---\n([\s\S]*?)\n---(?:\n|$)([\s\S]*)$/u.exec(
+ normalizedSkill,
+ );
+ assert(frontmatter, "Installed skill must have authored frontmatter");
+ expectedSkillBody = frontmatter[2].trim();
+ assert(expectedSkillBody.length > 0);
clientPath = baseEnvironment.PATH;
if (reducedPath) {
assert.equal(
@@ -200,9 +219,6 @@ await withVerifierCleanup(async () => {
directory: lab,
prefix: `${client}-${mode}`,
onRequest: async ({ body, tools, requestIndex }) => {
- skillSeen ||= JSON.stringify(body.messages ?? []).includes(
- "reverse-engineer-anything",
- );
const messages = (body.messages ?? []).map((message) => ({
role: message.role,
callId: message.tool_call_id,
@@ -213,14 +229,14 @@ await withVerifierCleanup(async () => {
.map((part) => part.text ?? "")
.join("\n"),
}));
- const messageText = messages.map((message) => message.text).join("\n");
const toolResponseText = (callId) =>
messages.find(
(message) => message.role === "tool" && message.callId === callId,
)?.text ?? "";
- selectedSkillLoaded ||= messageText.includes(
- join(sharedSkills, "reverse-engineer-anything"),
- );
+ const expectedSkill = `Base directory for this skill: ${join(sharedSkills, "reverse-engineer-anything")}\nImportant: ALWAYS resolve absolute paths from this base directory when working with skills.\n\n${expectedSkillBody}\n`;
+ selectedSkillLoaded ||=
+ skillCallId !== undefined &&
+ toolResponseText(skillCallId).includes(expectedSkill);
const toolText = JSON.stringify(
(body.messages ?? []).filter((m) => m.role === "tool"),
);
@@ -298,6 +314,7 @@ await withVerifierCleanup(async () => {
} else if (skill && !skillRequested) {
skillRequested = true;
message = call(skill.name, { skill: "reverse-engineer-anything" });
+ skillCallId = message.tool_calls[0].id;
} else if (persisted && shell) {
artifactPath = persisted[1];
assert(
diff --git a/scripts/verify-real-cutter.mjs b/scripts/verify-real-cutter.mjs
index 705bd902d2..aa7ee19bab 100644
--- a/scripts/verify-real-cutter.mjs
+++ b/scripts/verify-real-cutter.mjs
@@ -32,8 +32,6 @@ const runCli = async (...arguments_) => {
return JSON.parse(stdout);
};
-const projectRoot = await mkdtemp(join(tmpdir(), "rea-cutter-smoke-"));
-const projectPath = join(projectRoot, "smoke.rzdb");
const rizinQuote = (value) =>
`"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
const unavailableAnalysis = {
@@ -44,16 +42,21 @@ const unavailableAnalysis = {
},
};
const expectedPlatform = {
+ linux: "linux",
Linux: "linux",
macOS: "darwin",
Windows: "win32",
}[process.env.EXPECTED_PLATFORM];
-if (expectedPlatform !== undefined)
+if (process.env.EXPECTED_PLATFORM !== undefined) {
+ assert.ok(expectedPlatform, "Unrecognized Cutter runner platform.");
assert.equal(
process.platform,
expectedPlatform,
"Cutter runner did not match its declared platform.",
);
+}
+const projectRoot = await mkdtemp(join(tmpdir(), "rea-cutter-smoke-"));
+const projectPath = join(projectRoot, "smoke.rzdb");
try {
const discovery = await runCli("list-cutter-sessions");
assert.equal(
diff --git a/scripts/verify-real-electron.mjs b/scripts/verify-real-electron.mjs
index 45306de604..192b9d3805 100644
--- a/scripts/verify-real-electron.mjs
+++ b/scripts/verify-real-electron.mjs
@@ -79,7 +79,11 @@ const output = {
windows: capture.windows,
verified:
capture.coverage.status === "partial_attach" &&
- capture.actions.every(({ status }) => status === "completed") &&
+ capture.actions.length === input.actions.length &&
+ capture.actions.every(
+ ({ step_id, status }, index) =>
+ step_id === input.actions[index].step_id && status === "completed",
+ ) &&
capture.actions.some(
({ kind, window_index }) =>
kind === "renderer-reload" && window_index === 1,
diff --git a/scripts/verify-real-ghidra-assertions.mjs b/scripts/verify-real-ghidra-assertions.mjs
index f79f287df9..c5fed71b0a 100644
--- a/scripts/verify-real-ghidra-assertions.mjs
+++ b/scripts/verify-real-ghidra-assertions.mjs
@@ -1,6 +1,6 @@
import { hasTypedSwitchEvidence } from "./verify-real-ghidra-switch-assertions.mjs";
-import { access } from "node:fs/promises";
+import { lstat } from "node:fs/promises";
import { parseBinaryTarget } from "../dist/application/BinaryTargetResolver.js";
import { SUPPORTED_GHIDRA_VERSION } from "../dist/ghidra/GhidraReleasePolicy.js";
@@ -437,10 +437,11 @@ export function summary(observed) {
async function exists(path) {
try {
- await access(path);
+ await lstat(path);
return true;
- } catch {
- return false;
+ } catch (cause) {
+ if (cause?.code === "ENOENT") return false;
+ throw cause;
}
}
diff --git a/scripts/verify-real-ghidra-function.mjs b/scripts/verify-real-ghidra-function.mjs
index dbf4e77b7f..1e4f2c2cf9 100644
--- a/scripts/verify-real-ghidra-function.mjs
+++ b/scripts/verify-real-ghidra-function.mjs
@@ -415,7 +415,7 @@ async function verifyRequestCancellationAndTimeout(client, entry) {
}
async function verifyConcurrentRequests(client, entry, leaf) {
- const concurrent = await Promise.all([
+ await Promise.all([
functionCall(client, "procedure_info", {
document: null,
procedure: entry.address,
@@ -425,9 +425,7 @@ async function verifyConcurrentRequests(client, entry, leaf) {
address: leaf.address,
}),
]);
- if (concurrent.length !== 2)
- throw new Error("Ghidra serial request queue lost a concurrent result");
- return "serialized-two-results";
+ return "two-concurrent-requests-completed";
}
/** Prove dense jump-table completeness on the optimized jump-table fixture. */
diff --git a/scripts/verify-real-ghidra-nativeaot.mjs b/scripts/verify-real-ghidra-nativeaot.mjs
index fb5064613f..6b0bb5851a 100644
--- a/scripts/verify-real-ghidra-nativeaot.mjs
+++ b/scripts/verify-real-ghidra-nativeaot.mjs
@@ -375,8 +375,13 @@ try {
JSON.stringify(report, null, 2) + "\n",
);
}
+ const outcome = report.typed_failure
+ ? "MCP refusal"
+ : mode === "default-native"
+ ? "native load image without metadata recovery"
+ : "MCP metadata";
console.log(
- `PASS real Ghidra NativeAOT ${oracle.runtime}/${mode}: MCP metadata, source identity and owned cleanup${report?.compute ? ", independent type/slot oracle and pseudocode" : ""}${report?.cli_metadata ? ", equivalent CLI" : ""}`,
+ `PASS real Ghidra NativeAOT ${oracle.runtime}/${mode}: ${outcome}, source unchanged and runtime directory empty${report?.compute ? ", independent type/slot oracle and pseudocode" : ""}${report?.cli_metadata ? ", equivalent CLI" : ""}`,
);
} catch (error) {
console.error(stderr);
diff --git a/scripts/verify-test-discovery.mjs b/scripts/verify-test-discovery.mjs
index 46a6aced87..5db6905852 100644
--- a/scripts/verify-test-discovery.mjs
+++ b/scripts/verify-test-discovery.mjs
@@ -55,7 +55,8 @@ try {
if (
report.missing.length ||
report.unexpected.length ||
- report.duplicates.length
+ report.duplicates.length ||
+ report.wrongProjects.length
) {
console.error(JSON.stringify(report, null, 2));
process.exitCode = 1;
diff --git a/scripts/verify/javascript/application-workflows.mjs b/scripts/verify/javascript/application-workflows.mjs
index 725e48a9ab..95b861b039 100644
--- a/scripts/verify/javascript/application-workflows.mjs
+++ b/scripts/verify/javascript/application-workflows.mjs
@@ -41,10 +41,18 @@ const [leftPath, rightPath] = await Promise.all([
]);
if (leftPath === rightPath)
throw new Error("--left and --right must resolve to distinct paths");
-const [left, right] = await Promise.all([
+const analyses = await Promise.allSettled([
analyze(options.left),
analyze(options.right),
]);
+const failures = analyses.filter((result) => result.status === "rejected");
+if (failures.length === 1) throw failures[0].reason;
+if (failures.length > 1)
+ throw new AggregateError(
+ failures.map((result) => result.reason),
+ "Application analyses failed",
+ );
+const [left, right] = analyses.map((result) => result.value);
const comparison = compareApplicationVersionsEvidence({ left, right });
if (!comparison.ok) throw comparison.error;
const comparisonResult = comparison.value.result;
diff --git a/scripts/verify/javascript/runtime-observation.mjs b/scripts/verify/javascript/runtime-observation.mjs
index 8587e5341e..bd1781ca52 100644
--- a/scripts/verify/javascript/runtime-observation.mjs
+++ b/scripts/verify/javascript/runtime-observation.mjs
@@ -1,8 +1,17 @@
#!/usr/bin/env node
-import { readFile, realpath } from "node:fs/promises";
+import { realpath } from "node:fs/promises";
import { parseArgs } from "node:util";
+import { readStableArtifact } from "../../../dist/artifacts/readStableArtifact.js";
+import { ArtifactReaderFailure } from "../../../dist/artifacts/ArtifactReader.js";
+import { ArtifactResourceScope } from "../../../dist/artifacts/ArtifactResourceScope.js";
+import {
+ ArtifactFileCleanupFailure,
+ artifactFileCompletion,
+ artifactFilePrimaryFacts,
+} from "../../../dist/artifacts/ArtifactFileOperation.js";
+
import { reconcileJavaScriptRuntimeEvidence } from "../../../dist/application/javascript/JavaScriptRuntimeReconciliationService.js";
import { analyzeJavaScriptApplicationWithOwnedScope } from "../../lib/javascript-application-analysis.mjs";
import {
@@ -52,9 +61,11 @@ for (const encoded of options.mapping) {
const mapping = parseMapping(encoded, staticLayers.length);
staticLayers[mapping.layer].runtime_mappings.push(mapping.value);
}
-const runtimeObservations = (
- await Promise.all(options["runtime-evidence"].map(readEvidenceFile))
-).flat();
+const runtimeObservations = [];
+for (const path of options["runtime-evidence"]) {
+ const observations = await readEvidenceFile(path);
+ for (const observation of observations) runtimeObservations.push(observation);
+}
const reconciled = reconcileJavaScriptRuntimeEvidence({
static_layers: staticLayers,
runtime_observations: runtimeObservations,
@@ -95,10 +106,47 @@ process.stdout.write(
);
async function readEvidenceFile(path) {
- const bytes = await readFile(await realpath(path));
- if (bytes.byteLength > 64 * 1024 * 1024)
- throw new Error(`Runtime Evidence exceeds 64 MiB: ${path}`);
- const value = JSON.parse(bytes.toString("utf8"));
+ const scope = new ArtifactResourceScope();
+ let outcome;
+ try {
+ outcome = {
+ ok: true,
+ value: await readStableArtifact(
+ await realpath(path),
+ 64 * 1024 * 1024,
+ undefined,
+ undefined,
+ scope,
+ ),
+ };
+ } catch (cause) {
+ outcome = { ok: false, cause };
+ }
+ try {
+ await scope.close();
+ } catch (cleanupCause) {
+ if (!outcome.ok)
+ throw new AggregateError(
+ [outcome.cause, cleanupCause],
+ "Verifier cleanup failed",
+ { cause: outcome.cause },
+ );
+ throw cleanupCause;
+ }
+ if (!outcome.ok && outcome.cause instanceof ArtifactFileCleanupFailure) {
+ const completion = artifactFileCompletion(outcome.cause);
+ outcome =
+ completion === undefined
+ ? { ok: false, cause: artifactFilePrimaryFacts(outcome.cause).cause }
+ : { ok: true, value: completion.value };
+ }
+ if (!outcome.ok) {
+ const cause = outcome.cause;
+ if (cause instanceof ArtifactReaderFailure && cause.reason === "limit")
+ throw new Error(`Runtime Evidence exceeds 64 MiB: ${path}`, { cause });
+ throw cause;
+ }
+ const value = JSON.parse(outcome.value.bytes.toString("utf8"));
return Array.isArray(value) ? value : [value];
}
diff --git a/src/application/BrowserScenarioCaptureService.test.ts b/src/application/BrowserScenarioCaptureService.test.ts
index 34a3c588cb..c370e77ffa 100644
--- a/src/application/BrowserScenarioCaptureService.test.ts
+++ b/src/application/BrowserScenarioCaptureService.test.ts
@@ -114,6 +114,38 @@ it.each([
},
);
+it("retains completed scenario Evidence when cancellation arrives during capture", async () => {
+ const caller = new AbortController();
+ const reason = { requested: "stop after capture" };
+ const provider: BrowserScenarioCapturePort = {
+ identity: () => scenarioIdentity,
+ captureScenario: async (received, options) => {
+ expect(received).toBe(scenario);
+ expect(options?.signal).toBe(caller.signal);
+ caller.abort(reason);
+ return ok(capture);
+ },
+ };
+ const result = await captureBrowserScenario(provider, scenario, {
+ signal: caller.signal,
+ });
+ if (result.ok) throw new Error("Expected late cancellation");
+ expect(result.error).toBeInstanceOf(AnalysisCancelledError);
+ expect(result.error.cause).toBe(reason);
+ expect(parseEvidence(result.error.partialObservation)).toMatchObject({
+ operation: "capture_browser_scenario",
+ provider: scenarioIdentity,
+ confidence: "observed",
+ authority: "controlled-replay",
+ parameters: {
+ browser: scenario.browser,
+ start_url: scenario.start_url,
+ actions: scenario.actions,
+ },
+ normalized_result: capture,
+ });
+});
+
it("keeps startup cancellation and its incomplete capture", async () => {
const reason = { requested: "stop during initial navigation" };
const completed = scriptScenarioFixture();
diff --git a/src/application/WebRuntimeService.test.ts b/src/application/WebRuntimeService.test.ts
index 63fe30f8c2..600b64aa7d 100644
--- a/src/application/WebRuntimeService.test.ts
+++ b/src/application/WebRuntimeService.test.ts
@@ -139,6 +139,13 @@ it("retains completed execution Evidence on late abort and keeps invalid output
expect(completed.error.cause).toBe(cancellationReason);
expect(parseEvidence(completed.error.partialObservation)).toMatchObject({
operation: "observe_web_execution",
+ provider: { id: "web-runtime", name: "Runtime fixture", version: "1" },
+ parameters: input,
+ confidence: "observed",
+ authority: "external-service",
+ limitations: expect.arrayContaining(
+ webExecutionFixture(input.target_id, input.observation_ms).limitations,
+ ),
normalized_result: webExecutionFixture(
input.target_id,
input.observation_ms,
diff --git a/src/application/WebSourceLocationService.test.ts b/src/application/WebSourceLocationService.test.ts
index 7faa175c3a..86f436a855 100644
--- a/src/application/WebSourceLocationService.test.ts
+++ b/src/application/WebSourceLocationService.test.ts
@@ -220,7 +220,8 @@ it("honors cancellation both before acquisition and across decoder completion",
if (!response.ok) expect(response.error.cause).toBe(firstReason);
const controller = new AbortController();
const lateReason = { caller: "after source-map provider completion" };
- const late = await service(undefined, {
+ const fixture = webSourceLocationFixture();
+ const late = await service(fixture, {
trace: (input) => {
controller.abort(lateReason);
return decoder.trace(input);
@@ -232,6 +233,28 @@ it("honors cancellation both before acquisition and across decoder completion",
expect(parseEvidence(late.error.partialObservation)).toMatchObject({
operation: "trace_web_source_location",
confidence: "derived",
+ authority: "historical-reference",
+ subject: {
+ local_path: fixture.sourceFile.path,
+ digest: { sha256: fixture.sourceFile.sha256 },
+ },
+ parameters: args,
+ raw_result: { source_map_text: fixture.sourceMap.text },
+ normalized_result: {
+ source_map: {
+ ...fixture.sourceMap.file,
+ url: args.source_map.url,
+ association: "caller-selected",
+ },
+ lookup: { requested: args.generated_position },
+ source_authenticity: "unknown",
+ execution: "unknown",
+ },
+ locations: [
+ fixture.sourceFile.path,
+ fixture.manifestFile.path,
+ fixture.sourceMap.file.path,
+ ].map((path) => ({ kind: "artifact-path", path })),
});
const malformedDecoder: WebSourceMapPort = {
diff --git a/src/application/electron/ElectronFuseService.test.ts b/src/application/electron/ElectronFuseService.test.ts
index 1a501fee62..aba6d285ac 100644
--- a/src/application/electron/ElectronFuseService.test.ts
+++ b/src/application/electron/ElectronFuseService.test.ts
@@ -30,11 +30,12 @@ const report: ElectronFuseReport = {
it("retains completed fuse Evidence when the provider completes after abort", async () => {
const controller = new AbortController();
+ const reason = { requested: "stop after fuse inspection" };
const result = await new ElectronFuseService({
identity,
close: async () => {},
inspect: async () => {
- controller.abort();
+ controller.abort(reason);
return ok(report);
},
}).inspect(
@@ -44,8 +45,19 @@ it("retains completed fuse Evidence when the provider completes after abort", as
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBe(reason);
expect(parseEvidence(result.error.partialObservation)).toMatchObject({
operation: "inspect_electron_fuses",
+ provider: identity,
+ subject: {
+ local_path: report.artifact.resolved_path,
+ digest: { sha256: report.artifact.sha256 },
+ format: report.artifact.format,
+ },
+ parameters: { path: report.artifact.selected_path },
+ confidence: "observed",
+ limitations: expect.arrayContaining(report.limitations),
+ locations: [{ kind: "artifact-path", path: report.artifact.selected_path }],
normalized_result: report,
});
}
diff --git a/src/application/javascript/ElectronObservationService.test.ts b/src/application/javascript/ElectronObservationService.test.ts
index 01e9e8c0e2..5393957b0c 100644
--- a/src/application/javascript/ElectronObservationService.test.ts
+++ b/src/application/javascript/ElectronObservationService.test.ts
@@ -150,6 +150,7 @@ it("returns a typed output error for malformed Electron target output after abor
it("retains completed target facts when cancellation arrives before Evidence publication", async () => {
const controller = new AbortController();
+ const reason = { requested: "stop after listing targets" };
const targets = electronTargetListSchema.parse({
browser: inspection.browser,
targets: [],
@@ -159,7 +160,7 @@ it("retains completed target facts when cancellation arrives before Evidence pub
const provider: ElectronObservationPort = {
identity: () => identity,
listTargets: async () => {
- controller.abort();
+ controller.abort(reason);
return ok(targets);
},
inspectPage: async () =>
@@ -173,8 +174,22 @@ it("retains completed target facts when cancellation arrives before Evidence pub
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error).toBeInstanceOf(AnalysisCancelledError);
+ expect(result.error.cause).toBe(reason);
expect(parseEvidence(result.error.partialObservation)).toMatchObject({
operation: "list_electron_targets",
+ provider: identity,
+ parameters: { cdp_endpoint: input.cdp_endpoint },
+ confidence: "observed",
+ authority: "external-service",
+ environment: {
+ id: `${inspection.browser.product}@${inspection.browser.revision}`,
+ platform: "unknown",
+ architecture: "unknown",
+ isolation: "none",
+ },
+ limitations: expect.arrayContaining([
+ "Browser host platform and architecture were not observed.",
+ ]),
normalized_result: targets,
});
}
diff --git a/src/application/javascript/JavaScriptAnalysisControl.test.ts b/src/application/javascript/JavaScriptAnalysisControl.test.ts
index a16892ef9a..0dc60c78a0 100644
--- a/src/application/javascript/JavaScriptAnalysisControl.test.ts
+++ b/src/application/javascript/JavaScriptAnalysisControl.test.ts
@@ -1,5 +1,6 @@
import { setImmediate } from "node:timers/promises";
import { describe, expect, it } from "vitest";
+import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
import { completeJavaScriptAnalysisSteps } from "./JavaScriptAnalysisControl.js";
describe("JavaScript cooperative computation lifecycle", () => {
@@ -15,9 +16,19 @@ describe("JavaScript cooperative computation lifecycle", () => {
}
}
const cancellation = setImmediate().then(() => controller.abort(reason));
- await expect(
- completeJavaScriptAnalysisSteps(work(), controller.signal),
- ).rejects.toMatchObject({ reason: "cancelled", cause: reason });
+ const failure = await completeJavaScriptAnalysisSteps(
+ work(),
+ controller.signal,
+ ).then(
+ () => {
+ throw new Error("Expected cancellation");
+ },
+ (cause: unknown) => cause,
+ );
+ expect(failure).toBeInstanceOf(ArtifactReaderFailure);
+ if (!(failure instanceof ArtifactReaderFailure)) throw failure;
+ expect(failure.reason).toBe("cancelled");
+ expect(failure.cause).toBe(reason);
await cancellation;
expect(released).toBe(true);
});
@@ -32,9 +43,19 @@ describe("JavaScript cooperative computation lifecycle", () => {
yield;
return 42;
}
- await expect(
- completeJavaScriptAnalysisSteps(work(), controller.signal),
- ).rejects.toMatchObject({ reason: "cancelled", cause: reason });
+ const failure = await completeJavaScriptAnalysisSteps(
+ work(),
+ controller.signal,
+ ).then(
+ () => {
+ throw new Error("Expected cancellation");
+ },
+ (cause: unknown) => cause,
+ );
+ expect(failure).toBeInstanceOf(ArtifactReaderFailure);
+ if (!(failure instanceof ArtifactReaderFailure)) throw failure;
+ expect(failure.reason).toBe("cancelled");
+ expect(failure.cause).toBe(reason);
expect(started).toBe(false);
expect(await completeJavaScriptAnalysisSteps(work())).toBe(42);
});
diff --git a/src/application/javascript/JavaScriptRecoveryService.test.ts b/src/application/javascript/JavaScriptRecoveryService.test.ts
index fbd6ae9a60..1977b6031b 100644
--- a/src/application/javascript/JavaScriptRecoveryService.test.ts
+++ b/src/application/javascript/JavaScriptRecoveryService.test.ts
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
import { err, ok } from "../../domain/result.js";
+import { parseEvidence } from "../../domain/evidence.js";
import type { JavaScriptRecoveryResult } from "../../domain/javascript/javascriptRecovery.js";
import { createAnalysisExecution } from "../AnalysisProvider.js";
import { JavaScriptRecoveryService } from "./JavaScriptRecoveryService.js";
@@ -179,7 +180,17 @@ it("returns cancellation with the validated Evidence when the caller aborts afte
if (result.ok) throw new Error("expected cancellation");
expect(result.error._tag).toBe("AnalysisCancelledError");
expect(result.error.cause).toBe(reason);
- expect(result.error.partialObservation).toMatchObject({
+ expect(parseEvidence(result.error.partialObservation)).toMatchObject({
operation: "recover_javascript_sources",
+ provider: providerIdentity,
+ parameters: input,
+ subject: {
+ local_path: artifact.path,
+ digest: { sha256: artifact.sha256 },
+ format: "javascript",
+ },
+ confidence: "derived",
+ authority: "shipped-artifact",
+ normalized_result: recoveryResult(),
});
});
diff --git a/src/application/managed/ManagedReconstructionService.test.ts b/src/application/managed/ManagedReconstructionService.test.ts
index cf489058d4..81a3786238 100644
--- a/src/application/managed/ManagedReconstructionService.test.ts
+++ b/src/application/managed/ManagedReconstructionService.test.ts
@@ -41,36 +41,6 @@ it("managed reconstruction reports UTF-8 byte totals while preserving UTF-16 tex
});
});
-it("managed reconstruction rejects text hash drift", () => {
- const rejected = resolveManagedReconstructionImport({
- ...exampleInput(),
- methods: [
- {
- ...exampleMethod(),
- reconstruction: {
- ...exampleMethod().reconstruction,
- text_sha256: "0".repeat(64),
- },
- },
- ],
- });
- expect(rejected).toMatchObject({
- ok: false,
- error: {
- _tag: "AnalysisInputError",
- operation: "import_managed_reconstruction",
- issues: [
- {
- path: ["methods", 0, "reconstruction", "text_sha256"],
- reason: "invalid_value",
- message: expect.stringContaining("Reconstruction text hash mismatch"),
- },
- ],
- },
- });
- if (!rejected.ok) expect(rejected.error).toBeInstanceOf(AnalysisInputError);
-});
-
it("managed reconstruction rejects stale method locks", () => {
const staleInput = {
...exampleInput(),
@@ -234,13 +204,15 @@ describe("managed reconstruction input diagnostics", () => {
});
expect(result.ok).toBe(false);
if (result.ok) return;
+ expect(result.error).toBeInstanceOf(AnalysisInputError);
expect(result.error).toMatchObject({
_tag: "AnalysisInputError",
+ operation: "import_managed_reconstruction",
issues: [
{
path: ["methods", 0, "reconstruction", "text_sha256"],
reason: "invalid_value",
- message: expect.stringMatching(/text hash mismatch/u),
+ message: expect.stringContaining("Reconstruction text hash mismatch"),
},
],
});
diff --git a/src/artifacts/ArtifactPaths.test.ts b/src/artifacts/ArtifactPaths.test.ts
index 26c4814d01..6a203ee234 100644
--- a/src/artifacts/ArtifactPaths.test.ts
+++ b/src/artifacts/ArtifactPaths.test.ts
@@ -181,7 +181,7 @@ it("retains both source spellings and the native failure in a destination collis
expect(collision?.cause).toBe(cause);
});
-it.each([["app.js"], ["app.js", "App.js"], ["other.js"]])(
+it.each([["app.js", "App.js"], ["other.js"]])(
"does not invent a destination alias from listing %j",
(...names) => {
expect(destinationCaseCollision("res/app.js", names)).toBeUndefined();
diff --git a/src/artifacts/BundleResourceArtifactClient.test.ts b/src/artifacts/BundleResourceArtifactClient.test.ts
deleted file mode 100644
index 90fd7ef12a..0000000000
--- a/src/artifacts/BundleResourceArtifactClient.test.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
-import { tmpdir } from "node:os";
-import { join } from "node:path";
-import { build } from "plist";
-import { afterEach, expect, it } from "vitest";
-
-import { ArtifactProvider } from "./ArtifactProvider.js";
-import type { ResolvedAppBundleResourceRoot } from "../application/AppBundleExecutable.js";
-
-const temporaryDirectories: string[] = [];
-
-afterEach(async () => {
- await Promise.all(
- temporaryDirectories
- .splice(0)
- .map((path) => rm(path, { recursive: true, force: true })),
- );
-});
-
-it("returns keyed archive evidence with root provenance and unknown executable identity", async () => {
- const bundlePath = await mkdtemp(join(tmpdir(), "rea-resource-reader-"));
- temporaryDirectories.push(bundlePath);
- await mkdir(join(bundlePath, "Resources"));
- await writeFile(
- join(bundlePath, "Info.plist"),
- '',
- );
- const archive = build({
- $archiver: "NSKeyedArchiver",
- $version: 100000,
- $objects: ["$null", "sample"],
- $top: { root: { UID: 1 } },
- });
- await writeFile(join(bundlePath, "Resources", "Archive.plist"), archive);
- const root: ResolvedAppBundleResourceRoot = {
- callerPath: bundlePath,
- canonicalPath: bundlePath,
- infoPlistPath: join(bundlePath, "Info.plist"),
- layout: "root",
- executableSha256: null,
- };
- const provider = new ArtifactProvider({}, "linux");
- const client = provider.createBundleResourceClient(root);
- const execution = await client.execute("inspect_keyed_archive", {
- path: "Resources/Archive.plist",
- });
- expect(execution.ok).toBe(true);
- if (execution.ok) {
- expect(execution.value.result).toMatchObject({
- target_sha256: null,
- resource_root: {
- caller_path: bundlePath,
- canonical_path: bundlePath,
- executable_sha256: null,
- },
- archive_path: "Resources/Archive.plist",
- });
- }
- expect((await client.close()).ok).toBe(true);
-});
diff --git a/src/artifacts/FitArtifactReader.test.ts b/src/artifacts/FitArtifactReader.test.ts
index 2090ecc960..10c44f41e5 100644
--- a/src/artifacts/FitArtifactReader.test.ts
+++ b/src/artifacts/FitArtifactReader.test.ts
@@ -55,6 +55,41 @@ const firstEntry = async (reader: FitArtifactReader) => {
return entry;
};
+it.each(["close", "cancel"] as const)(
+ "refuses to finish a paused FIT inventory after %s",
+ async (action) => {
+ const reader = new FitArtifactReader(
+ await writeFit("paused-inventory.itb", FIT_EXTERNAL),
+ );
+ const controller = new AbortController();
+ const reason = { stage: "after final entry" };
+ const iterator = reader.entries(controller.signal)[Symbol.asyncIterator]();
+ try {
+ expect((await iterator.next()).done).toBe(false);
+ expect((await iterator.next()).done).toBe(false);
+ if (action === "close") await reader.close();
+ else controller.abort(reason);
+ const failure: unknown = await iterator.next().then(
+ () => {
+ throw new Error("Expected the paused inventory to fail");
+ },
+ (cause: unknown) => cause,
+ );
+ expect(failure).toMatchObject(
+ action === "close"
+ ? { reason: "unavailable" }
+ : { reason: "cancelled" },
+ );
+ if (action === "cancel") {
+ if (!(failure instanceof ArtifactReaderFailure)) throw failure;
+ expect(failure.cause).toBe(reason);
+ }
+ } finally {
+ await reader.close();
+ }
+ },
+);
+
it.each([
["embedded", FIT_EMBEDDED, "embedded"],
["external", FIT_EXTERNAL, "data-offset"],
diff --git a/src/artifacts/FitArtifactReader.ts b/src/artifacts/FitArtifactReader.ts
index 1dfb0931ae..e3dea26293 100644
--- a/src/artifacts/FitArtifactReader.ts
+++ b/src/artifacts/FitArtifactReader.ts
@@ -82,6 +82,7 @@ export class FitArtifactReader implements ArtifactReader {
this.#assertOpen(signal);
yield copyArtifactEntry(entry);
}
+ this.#assertOpen(signal);
}
async open(entry: ArtifactEntry, signal?: AbortSignal): Promise {
diff --git a/src/artifacts/GodotPckArtifactReader.test.ts b/src/artifacts/GodotPckArtifactReader.test.ts
index 4340130faf..b7a9a81a15 100644
--- a/src/artifacts/GodotPckArtifactReader.test.ts
+++ b/src/artifacts/GodotPckArtifactReader.test.ts
@@ -184,21 +184,6 @@ describe("GodotPckArtifactReader", () => {
},
);
- it("preserves declared MD5 for the shared inventory integrity verifier", async () => {
- const bytes = buildGodotPck(3, [
- { path: "a.gd", data: "real", md5: Buffer.alloc(16, 1) },
- ]);
- await withReader(bytes, async (reader) => {
- const [entry] = await list(reader);
- if (entry === undefined) throw new Error("expected one entry");
- expect(entry.declaredIntegrity).toEqual({
- algorithm: "md5",
- digest: "01".repeat(16),
- });
- expect(await text(await reader.open(entry))).toBe("real");
- });
- });
-
it("reports encrypted members without reading them", async () => {
const bytes = buildGodotPck(3, [
{ path: "secret.gd", data: "x", flags: 1 },
diff --git a/src/artifacts/UImageArtifactReader.boundaries.test.ts b/src/artifacts/UImageArtifactReader.boundaries.test.ts
index d4a711dbc3..74de505d2a 100644
--- a/src/artifacts/UImageArtifactReader.boundaries.test.ts
+++ b/src/artifacts/UImageArtifactReader.boundaries.test.ts
@@ -10,6 +10,8 @@ import { buildUImage, buildMultiPayload } from "../../tests/fixtures/uimage.js";
import {
parseUImageHeaderFields,
parseMultiImageTable,
+ UIMAGE_HEADER_SIZE,
+ UIMAGE_MULTI_TABLE_WINDOW,
} from "../domain/uimageFormat.js";
const fixture = async (bytes: Buffer): Promise => {
@@ -110,7 +112,31 @@ it("admits a multi-image count before scanning the remaining payload", async ()
reason: "limit",
boundary: "capacity",
});
- expect(reads).toHaveBeenCalledTimes(2); // header and bounded table, no payload scan
+ expect(reads.mock.calls.length).toBeGreaterThan(0);
+ for (const call of reads.mock.calls) {
+ const [, , length, position] = call as unknown as [
+ Buffer,
+ number,
+ number,
+ number,
+ ];
+ expect(Number.isSafeInteger(position)).toBe(true);
+ expect(Number.isSafeInteger(length)).toBe(true);
+ expect(position).toBeGreaterThanOrEqual(0);
+ expect(length).toBeGreaterThanOrEqual(0);
+ if (length > 0)
+ expect(position + length).toBeLessThanOrEqual(
+ UIMAGE_HEADER_SIZE + UIMAGE_MULTI_TABLE_WINDOW,
+ );
+ }
+ const results = await Promise.all(
+ reads.mock.results.map(
+ ({ value }) => value as Promise<{ bytesRead: number }>,
+ ),
+ );
+ expect(
+ results.reduce((sum, result) => sum + result.bytesRead, 0),
+ ).toBeLessThanOrEqual(UIMAGE_HEADER_SIZE + UIMAGE_MULTI_TABLE_WINDOW);
} finally {
await reader.close();
reads.mockRestore();
diff --git a/src/artifacts/pyinstaller/CArchive.fixture.ts b/src/artifacts/pyinstaller/CArchive.fixture.ts
index 2732420858..481eb82cf1 100644
--- a/src/artifacts/pyinstaller/CArchive.fixture.ts
+++ b/src/artifacts/pyinstaller/CArchive.fixture.ts
@@ -5,7 +5,8 @@ import {
pythonPycHeader,
} from "../../python/PythonPyc.fixture.js";
-import { PYINSTALLER_COOKIE_MAGIC } from "./CArchiveLayout.js";
+// PyInstaller CArchiveWriter's on-disk cookie signature, independent of REA's reader.
+const CARCHIVE_COOKIE_MAGIC = Buffer.from("4d45490c0b0a0b0e", "hex");
/** Final CPython 3.9 bytecode magic, little-endian with the CR LF trailer. */
export const PYTHON_39_MAGIC = Buffer.from("610d0d0a", "hex");
@@ -172,7 +173,7 @@ export const cArchiveBytecodeExecutable = () => {
/** Cookie whose package range starts before the file. */
export const cookieRangeOutsideFile = (): Buffer => {
const cookie = Buffer.alloc(88);
- PYINSTALLER_COOKIE_MAGIC.copy(cookie, 0);
+ CARCHIVE_COOKIE_MAGIC.copy(cookie, 0);
cookie.writeUInt32BE(200, 8);
cookie.writeUInt32BE(80, 12);
cookie.writeUInt32BE(32, 16);
@@ -255,7 +256,7 @@ const cookieBytes = (input: {
}): Buffer => {
const size = input.layout === "2.1" ? 88 : 24;
const bytes = Buffer.alloc(size);
- PYINSTALLER_COOKIE_MAGIC.copy(bytes, 0);
+ CARCHIVE_COOKIE_MAGIC.copy(bytes, 0);
bytes.writeUInt32BE(input.tocOffset + input.tocLength + size, 8);
bytes.writeUInt32BE(input.tocOffset, 12);
bytes.writeUInt32BE(input.tocLength, 16);
diff --git a/src/artifacts/pyinstaller/PyInstallerArtifactReader.test.ts b/src/artifacts/pyinstaller/PyInstallerArtifactReader.test.ts
index a92b2e2a52..221255522f 100644
--- a/src/artifacts/pyinstaller/PyInstallerArtifactReader.test.ts
+++ b/src/artifacts/pyinstaller/PyInstallerArtifactReader.test.ts
@@ -909,67 +909,6 @@ it("retains the descriptor owner when admission cleanup fails", async () => {
}
});
-it("inventories and extracts a Windows member name under its canonical path", async () => {
- const storedName = String.raw`pkg\data.bin`;
- const pyzName = String.raw`res\icon.bin`;
- const payload = Buffer.from("nested-bytes");
- const icon = Buffer.from("icon-bytes");
- const path = await writeArchive(
- "windows",
- cArchiveExecutable({
- carrier: "pe",
- layout: "2.1",
- pythonVersion: 309,
- pythonLibrary: "python39.dll",
- members: [
- { name: storedName, typeCode: "x", payload, compress: false },
- {
- name: "PYZ.pyz",
- typeCode: "z",
- payload: pyzArchive({
- magic: PYTHON_39_MAGIC,
- modules: [{ name: pyzName, typeCode: 2, body: icon }],
- }),
- compress: false,
- },
- ],
- }),
- );
- const snapshot = await scanCanonicalArtifactInventory(path);
- const member = snapshot.occurrences.find(
- (occurrence) => occurrence.logical_path === "pkg/data.bin",
- );
- const resource = snapshot.occurrences.find(
- (occurrence) => occurrence.logical_path === "PYZ.pyz/res/icon.bin",
- );
- expect(member?.format_metadata).toMatchObject({ source_name: storedName });
- expect(resource?.format_metadata).toMatchObject({ source_name: pyzName });
- expect(member?.source_path).toBe(storedName);
- expect(resource?.source_path).toBe(pyzName);
- const directory = await createTestTempDirectory("rea-pyinstaller-out-");
- const output = join(directory, "extracted");
- await materializeArtifactInventory(
- {
- inputPath: path,
- inputFormat: "pe",
- outputRoot: output,
- environment: process.env,
- integrityPolicy: "fail",
- },
- path,
- snapshot,
- );
- expect(
- Buffer.compare(await readFile(join(output, "pkg", "data.bin")), payload),
- ).toBe(0);
- expect(
- Buffer.compare(
- await readFile(join(output, "PYZ.pyz", "res", "icon.bin")),
- icon,
- ),
- ).toBe(0);
-});
-
const posixPathFixture = async () => {
const backslashName = String.raw`a\b.txt`;
const slashName = "a/b.txt";
diff --git a/src/browser/BrowserScenario.test.ts b/src/browser/BrowserScenario.test.ts
index 16a7b00293..9684839ffb 100644
--- a/src/browser/BrowserScenario.test.ts
+++ b/src/browser/BrowserScenario.test.ts
@@ -227,9 +227,6 @@ describe("browserScenarioSchema", () => {
at_end: ["dom", "storage"],
events: ["console", "page-errors", "network", "websockets"],
});
- expect(parsed.capture.limits).toEqual(
- DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS,
- );
});
it("allows callers to choose visible browsers and service workers", () => {
diff --git a/src/browser/PlaywrightElectronActiveActions.test.ts b/src/browser/PlaywrightElectronActiveActions.test.ts
index 16618377db..c9c4ec8302 100644
--- a/src/browser/PlaywrightElectronActiveActions.test.ts
+++ b/src/browser/PlaywrightElectronActiveActions.test.ts
@@ -188,8 +188,6 @@ it("preserves local Playwright action diagnostics", async () => {
status: "failed",
error: `locator ${selector} failed with token=raw-secret`,
});
- expect(result[0]?.error).toContain(selector);
- expect(result[0]?.error).toContain("raw-secret");
});
it("retains complete action errors and Electron window text", async () => {
diff --git a/src/config.test.ts b/src/config.test.ts
index 7abcf113eb..5b6264bd97 100644
--- a/src/config.test.ts
+++ b/src/config.test.ts
@@ -359,6 +359,12 @@ describe("configuration failure diagnostics", () => {
it.each(["1", "90000", "2147483647"])(
"accepts Swift compile deadline %s without changing Hopper's deadline",
(value) => {
+ expect(
+ parseEnvironmentValues({ REA_SWIFTC_COMPILE_TIMEOUT_MS: value }),
+ ).toMatchObject({
+ ok: true,
+ value: { REA_SWIFTC_COMPILE_TIMEOUT_MS: Number(value) },
+ });
expect(
parseConfig({ REA_SWIFTC_COMPILE_TIMEOUT_MS: value }),
).toMatchObject({
diff --git a/src/domain/bundleComparison.test.ts b/src/domain/bundleComparison.test.ts
index f91aff856e..406389608d 100644
--- a/src/domain/bundleComparison.test.ts
+++ b/src/domain/bundleComparison.test.ts
@@ -77,39 +77,6 @@ describe("bundle comparison explicit cross-pairs", () => {
});
describe("bundle comparison", () => {
- it("does not report display-only bundle differences as unexplained changes", () => {
- const target = {
- path: "/left/artifact.elf",
- sha256: "a".repeat(64),
- format: "elf" as const,
- architecture: "x86_64" as const,
- };
- const record = createEvidence(target, PROVIDER, {
- operation: "observe",
- parameters: {},
- result: { observed: true },
- confidence: "observed",
- authority: "shipped-artifact",
- });
- const left = createEvidenceBundle([record]);
- const rightRecord = {
- ...record,
- subject: {
- ...record.subject!,
- name: "renamed.elf",
- local_path: "/right/renamed.elf",
- },
- };
- const right = { ...left, records: [rightRecord] };
- const result = compareBundles(left, right);
- expect(result).toMatchObject({
- status: "unchanged",
- summary: { records_unchanged: 1, unresolved: 0 },
- changes: [],
- });
- expect(result.left_bundle_sha256).not.toBe(result.right_bundle_sha256);
- });
-
it("accepts long caller-selected bundle paths", () => {
const path = `/${"deep/".repeat(1_000)}bundle.json`;
expect(
diff --git a/src/domain/changedBehavior.test.ts b/src/domain/changedBehavior.test.ts
index 4142623361..07c31f4852 100644
--- a/src/domain/changedBehavior.test.ts
+++ b/src/domain/changedBehavior.test.ts
@@ -229,14 +229,6 @@ describe("changed behavior", () => {
expect(aggregate([changed, unknown]).result).toEqual(result);
});
- it("uses complete inline artifact deltas as static candidates", () => {
- const complete = comparison("compare_artifacts", artifactResult());
- expect(aggregate([complete]).result.findings.items).toEqual(
- expect.arrayContaining([
- expect.objectContaining({ dimension: "artifact:main.js" }),
- ]),
- );
- });
});
describe("changed-behavior input and Evidence validation", () => {
diff --git a/src/domain/ghidraValues.fixture.ts b/src/domain/ghidraValues.fixture.ts
index 255947a1f4..904de4e462 100644
--- a/src/domain/ghidraValues.fixture.ts
+++ b/src/domain/ghidraValues.fixture.ts
@@ -6,7 +6,7 @@ export const ghidraFunctionClassification = () => ({
});
/** Wire-boundary fixture, not evidence that a real Ghidra run was performed. */
-export const ghidraFunctionBody = () => ({
+const ghidraFunctionBody = () => ({
available: true as const,
provenance: "ghidra-function-body-address-set",
ranges: [{ start: "0x401000", end: "0x401005" }],
diff --git a/src/domain/managed/managedNativeVerificationSource.test.ts b/src/domain/managed/managedNativeVerificationSource.test.ts
index 05889d68e6..e7489739b7 100644
--- a/src/domain/managed/managedNativeVerificationSource.test.ts
+++ b/src/domain/managed/managedNativeVerificationSource.test.ts
@@ -31,7 +31,7 @@ describe("managed/native verification source", () => {
const [observation] = source.value.nativeObservations;
expect(observation?.supported).toBe(true);
expect(observation?.symbols.map(({ name }) => name)).toEqual(
- legacy.exports.items.map(({ name }) => name),
+ ["open_native"],
);
});
});
diff --git a/src/domain/native/peImports.test.ts b/src/domain/native/peImports.test.ts
deleted file mode 100644
index ffdbc7786e..0000000000
--- a/src/domain/native/peImports.test.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { expect, it } from "vitest";
-import { inspectPeImportsInputSchema, peImportsSchema } from "./peImports.js";
-
-it("rejects extra caller arguments and admits an empty import inventory", () => {
- expect(
- inspectPeImportsInputSchema.safeParse({
- path: "/artifacts/app.exe",
- extra: true,
- }).success,
- ).toBe(false);
- const report = peImportsSchema.parse({
- artifact: {
- path: "/artifacts/app.exe",
- sha256: "a".repeat(64),
- bytes: 512,
- },
- format: "pe32-plus",
- machine: 0x8664,
- bits: 64,
- architecture: "amd64",
- import_directory: null,
- delay_import_directory: null,
- imports: [],
- delay_imports: [],
- imphash: {
- algorithm: "pefile",
- md5: null,
- reason: "IMAGE_DIRECTORY_ENTRY_IMPORT is absent.",
- },
- coverage: {
- status: "complete",
- reason: null,
- examined_dlls: 0,
- imports: 0,
- delay_imports: 0,
- },
- issues: [],
- limitations: [
- "IMAGE_DIRECTORY_ENTRY_IMPORT is absent. That is not proof the image never imported APIs through another table or overlay.",
- ],
- });
- expect(report.imports).toEqual([]);
- expect(report.imphash.md5).toBeNull();
-});
diff --git a/src/dotnet/ManagedArtifactInspector.test.ts b/src/dotnet/ManagedArtifactInspector.test.ts
index 249fc507af..d66ab29c08 100644
--- a/src/dotnet/ManagedArtifactInspector.test.ts
+++ b/src/dotnet/ManagedArtifactInspector.test.ts
@@ -613,23 +613,6 @@ it.each([false, true])(
);
describe("managed artifact reference inventory", () => {
- it("qualifies local custom-attribute names with their enclosing types", () => {
- const bytes = buildManagedPeFixture({
- additionalEmptyTypes: 1,
- customAttributeTypeRaw: (1 << 3) | 2,
- nestedTypes: [[2, 1]],
- typeName: "InnerAttribute",
- typeNamespace: "",
- });
- const result = inspectManagedArtifactBytes(
- bytes,
- managedPeFixtureTarget(bytes),
- );
-
- expect(result.attributes[0]?.type_name).toBe("Empty0+InnerAttribute");
- expect(result.coverage).toEqual({ state: "complete", issues: [] });
- });
-
it("qualifies referenced custom-attribute names from TypeRef scopes", () => {
const bytes = buildManagedPeFixture({
customAttributeTypeRaw: (1 << 3) | 3,
diff --git a/src/dotnet/ManagedCilDecoding.test.ts b/src/dotnet/ManagedCilDecoding.test.ts
index eb2e283170..ade7734cc5 100644
--- a/src/dotnet/ManagedCilDecoding.test.ts
+++ b/src/dotnet/ManagedCilDecoding.test.ts
@@ -473,14 +473,6 @@ describe("managed complete operand decoding", () => {
});
});
- it("reports a switch whose target count is itself truncated", () => {
- expect(fatBody(Buffer.from([0x45, 0x02]))).toMatchObject({
- status: "malformed",
- decoded_instruction_count: 0,
- issue: "Instruction switch at IL offset 0 leaves method body",
- });
- });
-
it("preserves instructions decoded before a truncated operand", () => {
expect(fatBody(Buffer.from([0x00, 0x20]))).toMatchObject({
status: "malformed",
diff --git a/src/dotnet/ManagedFieldConstants.test.ts b/src/dotnet/ManagedFieldConstants.test.ts
index cbce7aab96..902c6a6efb 100644
--- a/src/dotnet/ManagedFieldConstants.test.ts
+++ b/src/dotnet/ManagedFieldConstants.test.ts
@@ -192,9 +192,12 @@ it("does not invent an inspected constant on historical member Evidence", () =>
expect(historical.fields[0]).not.toHaveProperty("constant");
});
-it.each([7, 8])(
- "retains the common coded-index diagnostic for invalid parent %s",
- (parentRaw) => {
+it.each([
+ { parentRaw: 7, reason: "tag 3" },
+ { parentRaw: 8, reason: "row 2" },
+])(
+ "retains the coded-index diagnostic for invalid parent $parentRaw",
+ ({ parentRaw, reason }) => {
const bytes = buildManagedPeFixture({
fields: [{ name: "Default", flags: 0x8056 }],
constants: [
@@ -226,7 +229,7 @@ it.each([7, 8])(
expect.objectContaining({
code: "invalid-row",
scope: "metadata.Constant",
- detail: parent.reason,
+ detail: expect.stringContaining(reason),
}),
]),
);
diff --git a/src/dotnet/ManagedMemberInspector.test.ts b/src/dotnet/ManagedMemberInspector.test.ts
index bd1045a837..43807fc523 100644
--- a/src/dotnet/ManagedMemberInspector.test.ts
+++ b/src/dotnet/ManagedMemberInspector.test.ts
@@ -101,14 +101,6 @@ it.each([
);
describe("managed compressed integer framing", () => {
- it.each([[0x80], [0xc0], [0xc0, 1], [0xc0, 1, 2]])(
- "keeps an incomplete width %j distinct from a reserved prefix",
- (...value) => {
- expect(() => readCompressed(Buffer.from(value), 0)).toThrow(
- "truncated compressed integer",
- );
- },
- );
it("preserves complete widths and rejects reserved leading bits", () => {
expect(readCompressed(Buffer.from([0x80, 1]), 0)).toEqual({
value: 1,
@@ -2418,6 +2410,9 @@ it.each([
it.each([
[[], "truncated compressed integer"],
[[0x80], "truncated compressed integer"],
+ [[0xc0], "truncated compressed integer"],
+ [[0xc0, 1], "truncated compressed integer"],
+ [[0xc0, 1, 2], "truncated compressed integer"],
[[0xc0, 0, 0], "truncated compressed integer"],
[[0xe0], "reserved compressed integer"],
] as const)(
diff --git a/src/dotnet/ManagedNativeBoundaryInspector.test.ts b/src/dotnet/ManagedNativeBoundaryInspector.test.ts
index 9788ef5eab..adce48d8ad 100644
--- a/src/dotnet/ManagedNativeBoundaryInspector.test.ts
+++ b/src/dotnet/ManagedNativeBoundaryInspector.test.ts
@@ -228,14 +228,7 @@ it("reports field imports as declarations without inventing method implementatio
});
describe("managed native boundary inspection", () => {
- it("returns complete member inventories inline and reports unavailable metadata", () => {
- const bytes = buildManagedPeFixture();
- const paged = inspectManagedMembersBytes(
- bytes,
- managedPeFixtureTarget(bytes),
- );
- expect(paged.methods).toHaveLength(1);
-
+ it("reports absent or malformed member metadata", () => {
const nativeBytes = buildNativePeFixture();
const native = inspectManagedMembersBytes(
nativeBytes,
diff --git a/src/dotnet/ManagedSignatureResolution.test.ts b/src/dotnet/ManagedSignatureResolution.test.ts
index d33066ba91..21dfbc45b8 100644
--- a/src/dotnet/ManagedSignatureResolution.test.ts
+++ b/src/dotnet/ManagedSignatureResolution.test.ts
@@ -610,7 +610,7 @@ describe("signature display name validity", () => {
const result = inspectDisplayFixture({ fieldSignature: blob });
expect(result.fields[0]?.signature.parse_status).toBe(status);
expect(result.fields[0]?.signature.raw_sha256).toBe(
- signature(blob).raw_sha256,
+ createHash("sha256").update(blob).digest("hex"),
);
});
});
diff --git a/src/electron/ElectronFuseProvider.test.ts b/src/electron/ElectronFuseProvider.test.ts
index af36e1696c..774f2ec3ad 100644
--- a/src/electron/ElectronFuseProvider.test.ts
+++ b/src/electron/ElectronFuseProvider.test.ts
@@ -266,11 +266,11 @@ describe("ELF embedded ASAR integrity applicability", () => {
it("preserves an enabled ASAR integrity fuse without claiming enforcement on ELF", async () => {
const root = await createTestTempDirectory("rea-electron-fuses-elf-asar-");
const fuses = [
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.enabled,
+ 0x30,
+ 0x30,
+ 0x30,
+ 0x30,
+ 0x31,
];
const image = elfFuseImage(fuses);
const path = join(root, "electron");
@@ -281,7 +281,7 @@ describe("ELF embedded ASAR integrity applicability", () => {
index: 4,
name: "EnableEmbeddedAsarIntegrityValidation",
state: "enabled",
- raw_byte: ELECTRON_FUSE_STATE_BYTES.enabled,
+ raw_byte: 0x31,
});
expect(
report.runtime_implications.find(
diff --git a/src/flutter/FlutterPayloadScan.test.ts b/src/flutter/FlutterPayloadScan.test.ts
index 13bb4f743f..4e36d78efa 100644
--- a/src/flutter/FlutterPayloadScan.test.ts
+++ b/src/flutter/FlutterPayloadScan.test.ts
@@ -136,7 +136,7 @@ describe("LabeledStringScanner", () => {
};
it("collects a full clang line within the 500-character bound", () => {
assertSingleToolchainLine(
- "Android (5900059 based on r365631c1) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 207d7abc1a2abf3ef8d4301736d6a7ebc224a290) (based on LLVM 9.0.8svn)",
+ "Android (5900059 based on r365631c) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 207d7abc1a2abf3ef8d4301736d6a7ebc224a290) (based on LLVM 9.0.8svn)",
);
});
@@ -155,12 +155,6 @@ describe("LabeledStringScanner", () => {
);
});
- it("collects the labeled Android clang line", () => {
- assertSingleToolchainLine(
- "Android (5900059 based on r365631c) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 207d7abc) (based on LLVM 9.0.8svn)",
- );
- });
-
it("does not claim a toolchain cap for unrelated overlong strings", () => {
const scanner = new LabeledStringScanner();
const license = `Apache License Version 2.0 ${"x".repeat(700)}`;
diff --git a/src/ghidra/GhidraFunctionValues.test.ts b/src/ghidra/GhidraFunctionValues.test.ts
index 9c33de190a..e711c2461a 100644
--- a/src/ghidra/GhidraFunctionValues.test.ts
+++ b/src/ghidra/GhidraFunctionValues.test.ts
@@ -803,6 +803,15 @@ const malformedOutputs = (): Array<
length: 1,
signature: null,
locals: [],
+ body: {
+ available: true,
+ provenance: "ghidra-function-body-address-set",
+ ranges: [{ start: "0x401000", end: "0x401000" }],
+ total_bytes: 1,
+ span_bytes: 1,
+ non_contiguous: false,
+ contains_entry: true,
+ },
},
],
[
@@ -814,6 +823,8 @@ const malformedOutputs = (): Array<
references: [
{ ...edge, kind: { available: false, reason: "unknown" } },
],
+ reference_kinds_available: true,
+ unresolved_calls: [],
},
],
[
diff --git a/src/ida/IdaContainment.test.ts b/src/ida/IdaContainment.test.ts
index 045df2e778..7562afda45 100644
--- a/src/ida/IdaContainment.test.ts
+++ b/src/ida/IdaContainment.test.ts
@@ -458,7 +458,10 @@ describe("headless IDA containment lookup failures", () => {
});
expect(result.ok).toBe(false);
- if (!result.ok) expect(result.error._tag).toBe("AnalysisCancelledError");
+ if (!result.ok) {
+ expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBe(controller.signal.reason);
+ }
expect(
producer.calls.some(({ name }) => name === "survey_binary"),
"nothing is dispatched after cancellation",
@@ -606,7 +609,10 @@ describe("headless IDA document identity", () => {
);
expect(result.ok).toBe(false);
- if (!result.ok) expect(result.error._tag).toBe("AnalysisCancelledError");
+ if (!result.ok) {
+ expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBe(controller.signal.reason);
+ }
expect(producer.calls).toEqual([]);
} finally {
expect((await client.close()).ok).toBe(true);
diff --git a/src/ida/IdaOperationFailures.test.ts b/src/ida/IdaOperationFailures.test.ts
index 350af553cd..e107c4b622 100644
--- a/src/ida/IdaOperationFailures.test.ts
+++ b/src/ida/IdaOperationFailures.test.ts
@@ -302,6 +302,7 @@ describe("headless IDA partial operation evidence", () => {
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBe(controller.signal.reason);
expect(result.error.partialObservation).toMatchObject({
analysis_profile: null,
normalized_result: {
diff --git a/src/kuna/KunaProjectCache.ts b/src/kuna/KunaProjectCache.ts
index 2070c2ff5a..673c82125c 100644
--- a/src/kuna/KunaProjectCache.ts
+++ b/src/kuna/KunaProjectCache.ts
@@ -556,7 +556,11 @@ export class KunaProjectCache {
request: KunaProjectRequest,
): Promise> {
if (request.signal?.aborted === true)
- return err(new AnalysisCancelledError(KUNA_EXPORT_OPERATION));
+ return err(
+ new AnalysisCancelledError(KUNA_EXPORT_OPERATION, {
+ cause: request.signal.reason,
+ }),
+ );
const key = kunaProjectKey({
targetSha256: request.targetSha256,
targetBasename: basename(request.targetPath),
@@ -878,7 +882,13 @@ export class KunaProjectCache {
settled = true;
leave();
if (entry.waiters === 0) entry.controller.abort();
- resolve(err(new AnalysisCancelledError(KUNA_EXPORT_OPERATION)));
+ resolve(
+ err(
+ new AnalysisCancelledError(KUNA_EXPORT_OPERATION, {
+ cause: request.signal?.reason,
+ }),
+ ),
+ );
};
request.signal?.addEventListener("abort", onAbort, { once: true });
void entry.promise.then((result) => {
diff --git a/src/kuna/KunaTargetCommands.ts b/src/kuna/KunaTargetCommands.ts
index 14306dbc59..c151dde167 100644
--- a/src/kuna/KunaTargetCommands.ts
+++ b/src/kuna/KunaTargetCommands.ts
@@ -97,7 +97,14 @@ export class KunaTargetCommands {
if (this.#closing || request.signal.aborted) {
request.releaseRun?.();
return Promise.resolve(
- err(new AnalysisCancelledError(request.operation)),
+ err(
+ new AnalysisCancelledError(
+ request.operation,
+ request.signal.aborted
+ ? { cause: request.signal.reason }
+ : undefined,
+ ),
+ ),
);
}
return this.#run(request);
@@ -106,7 +113,16 @@ export class KunaTargetCommands {
/** Establish the immutable input before waiting for a foreground run slot. */
prepare(): Promise> {
if (this.#closing || this.lifetime.signal.aborted)
- return Promise.resolve(err(new AnalysisCancelledError("kuna:workspace")));
+ return Promise.resolve(
+ err(
+ new AnalysisCancelledError(
+ "kuna:workspace",
+ this.lifetime.signal.aborted
+ ? { cause: this.lifetime.signal.reason }
+ : undefined,
+ ),
+ ),
+ );
return this.#admit("kuna:workspace", () =>
this.#ensureWorkspace().then((workspace) =>
workspace.ok ? ok(null) : workspace,
diff --git a/src/native/elf/KernelModule.fixture.ts b/src/native/elf/KernelModule.fixture.ts
index d3b35a60a3..9c34b8a103 100644
--- a/src/native/elf/KernelModule.fixture.ts
+++ b/src/native/elf/KernelModule.fixture.ts
@@ -1,5 +1,3 @@
-import { MODULE_SIGNATURE_MAGIC } from "../../domain/native/kernelModule.js";
-
const concat = (...parts: readonly Buffer[]): Buffer => Buffer.concat(parts);
const write16 = (
@@ -75,7 +73,13 @@ export const moduleSignatureTrailer = (
const info = Buffer.alloc(12);
info[2] = 2;
info.writeUInt32BE(sigLen >>> 0, 8);
- return concat(pkcs7, info, Buffer.from(MODULE_SIGNATURE_MAGIC, "latin1"));
+ // Linux MODULE_SIG_STRING includes the final newline:
+ // https://code.googlesource.com/linux/torvalds/linux/+/78273df7f646f8daf2604ec714bea0897cd03aae/include/linux/module_signature.h
+ return concat(
+ pkcs7,
+ info,
+ Buffer.from("~Module signature appended~\n", "latin1"),
+ );
};
export interface KernelModuleFixtureOptions {
diff --git a/src/process/ProcessOwnership.nativeExit.test.ts b/src/process/ProcessOwnership.nativeExit.test.ts
index 115e520ba4..6d691ada0e 100644
--- a/src/process/ProcessOwnership.nativeExit.test.ts
+++ b/src/process/ProcessOwnership.nativeExit.test.ts
@@ -551,13 +551,14 @@ it("honors cancellation during token-open exit settlement", async () => {
lifecycle: { state: "observed", lifecycle: "non-zombie" },
};
const controller = new AbortController();
+ const reason = new Error("cancelled");
const host: ProcessOwnershipHost = {
platform: "linux",
listProcesses: async () => [row],
environment: async () => ({}),
signalGroup: vi.fn(),
processIdentities: async () => {
- controller.abort(new Error("cancelled"));
+ controller.abort(reason);
return new Map([[row.pid, identity]]);
},
};
@@ -576,7 +577,7 @@ it("honors cancellation during token-open exit settlement", async () => {
{ deadline: undefined },
controller.signal,
),
- ).rejects.toThrow("cancelled");
+ ).rejects.toBe(reason);
});
it("does not signal a stale group after its last member exits during revalidation", async () => {
diff --git a/src/process/RegexMatcher.test.ts b/src/process/RegexMatcher.test.ts
index 3fe5c8eb5d..26e2c60fca 100644
--- a/src/process/RegexMatcher.test.ts
+++ b/src/process/RegexMatcher.test.ts
@@ -416,9 +416,6 @@ it("describes the effective heap and the configurable matching deadline", () =>
regexWorkerHeapRequestRecovery(DEFAULT_REGEX_WORKER_HEAP_REQUEST),
);
if (heap.kind === "unknown") {
- expect(projected.remediation.action).toContain(
- "--max-old-space-size-percentage",
- );
expect(projected.remediation.action).toContain(
"--experimental-config-file",
);
diff --git a/src/reference/ReferenceSourceReader.test.ts b/src/reference/ReferenceSourceReader.test.ts
index 8cb73cae9b..27cf4c7a4b 100644
--- a/src/reference/ReferenceSourceReader.test.ts
+++ b/src/reference/ReferenceSourceReader.test.ts
@@ -57,7 +57,7 @@ describe("unobserved internal symlink reconciliation", () => {
]);
});
- it("retains unreadable targets below the nearest failed directory", () => {
+ it("retains unreadable targets below a failed directory", () => {
const entries: ReferenceSourceEntry[] = [
internalLink("alias.txt", "hidden/target.txt"),
failedDirectory("hidden", "io"),
diff --git a/src/rust/RustBinaryImage.machoAlignment.test.ts b/src/rust/RustBinaryImage.machoAlignment.test.ts
deleted file mode 100644
index 35ca20844d..0000000000
--- a/src/rust/RustBinaryImage.machoAlignment.test.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { expect, it } from "vitest";
-import { machoImageWithUnknownCommand } from "../artifacts/apple/MachoImage.fixture.js";
-import { readRustBinaryImage } from "./RustBinaryImage.js";
-import { RustAuditableFormatFailure } from "./RustAuditableReader.js";
-
-it("maps malformed 64-bit Mach-O load-command alignment to Rust input failure", () => {
- expect(() =>
- readRustBinaryImage(Buffer.from(machoImageWithUnknownCommand(true, 12))),
- ).toThrow(RustAuditableFormatFailure);
- expect(() =>
- readRustBinaryImage(Buffer.from(machoImageWithUnknownCommand(true, 12))),
- ).toThrow(expect.objectContaining({ kind: "malformed" }));
-});
-
-it.each([
- { wide: true, size: 16 },
- { wide: false, size: 12 },
-])(
- "accepts $size-byte Rust Mach-O command for wide=$wide",
- ({ wide, size }) => {
- expect(
- readRustBinaryImage(Buffer.from(machoImageWithUnknownCommand(wide, size)))
- .format,
- ).toBe("macho");
- },
-);
diff --git a/src/server/BundleResourcesMcp.test.ts b/src/server/BundleResourcesMcp.test.ts
index 377cb71d02..1da3c2d37f 100644
--- a/src/server/BundleResourcesMcp.test.ts
+++ b/src/server/BundleResourcesMcp.test.ts
@@ -2,7 +2,7 @@ import type { Client } from "@modelcontextprotocol/client";
import { Ajv2020 } from "ajv/dist/2020.js";
import type { AnySchema } from "ajv";
import { expect, it } from "vitest";
-import { mkdir, writeFile } from "node:fs/promises";
+import { mkdir, realpath, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { z } from "zod";
@@ -178,7 +178,8 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
const parent = await createTestTempDirectory(
"rea-bundle-resource-production-mcp-",
);
- const bundle = join(parent, "Fixture.app");
+ const bundle = join(parent, "Fixture");
+ const alias = join(parent, "Caller");
const resourceDirectory = join(bundle, "Resources");
await mkdir(resourceDirectory, { recursive: true });
await writeFile(join(bundle, "Info.plist"), "");
@@ -192,6 +193,9 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
}),
);
+ await symlink(bundle, alias, "junction");
+ const canonical = await realpath(bundle);
+
const session = await createArtifactBinarySession({}, process.platform);
const { client } = await createApplicationMcpHarness({
session,
@@ -200,7 +204,7 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
const opened = await client.callTool({
name: "open_bundle_resources",
- arguments: { path: bundle },
+ arguments: { path: alias },
});
expect(opened.isError).not.toBe(true);
expect(
@@ -208,7 +212,11 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
opened.structuredContent,
),
).toMatchObject({
- result: { canonical_path: bundle, executable_sha256: null },
+ result: {
+ caller_path: alias,
+ canonical_path: canonical,
+ executable_sha256: null,
+ },
});
const decoded = await client.callTool({
@@ -223,7 +231,11 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
subject: null,
normalized_result: {
target_sha256: null,
- resource_root: { canonical_path: bundle, executable_sha256: null },
+ resource_root: {
+ caller_path: alias,
+ canonical_path: canonical,
+ executable_sha256: null,
+ },
},
});
const decodedEvidenceId = z
@@ -252,10 +264,10 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
),
).toMatchObject({
normalized_result: {
- artifact: { path: bundle, sha256: null },
+ artifact: { path: canonical, sha256: null },
resource_root: {
- caller_path: bundle,
- canonical_path: bundle,
+ caller_path: alias,
+ canonical_path: canonical,
executable_sha256: null,
},
},
@@ -275,7 +287,11 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
normalized_result: {
archive_path: "Resources/Archive.plist",
target_sha256: null,
- resource_root: { canonical_path: bundle, executable_sha256: null },
+ resource_root: {
+ caller_path: alias,
+ canonical_path: canonical,
+ executable_sha256: null,
+ },
objects: expect.arrayContaining([
expect.objectContaining({ value: "resource-only-value" }),
]),
@@ -288,9 +304,24 @@ it("exposes the production resource session through the MCP SDK for a keyless bu
subject: null,
operation: "inspect_keyed_archive",
normalized_result: {
- resource_root: { canonical_path: bundle, executable_sha256: null },
+ resource_root: {
+ caller_path: alias,
+ canonical_path: canonical,
+ executable_sha256: null,
+ },
},
});
+ const closed = await client.callTool({ name: "close_binary", arguments: {} });
+ expect(closed.isError).not.toBe(true);
+ const statusAfterClose = await client.callTool({
+ name: "binary_session",
+ arguments: {},
+ });
+ expect(
+ toolContract("binary_session").outputSchema.parse(
+ statusAfterClose.structuredContent,
+ ),
+ ).toMatchObject({ result: { open: false } });
});
const expectResourceSchemaBranches = async (client: Client): Promise => {
diff --git a/src/server/runDerivedOperation.test.ts b/src/server/runDerivedOperation.test.ts
index 152c70752e..e6bb67dcd0 100644
--- a/src/server/runDerivedOperation.test.ts
+++ b/src/server/runDerivedOperation.test.ts
@@ -125,23 +125,6 @@ describe("derived MCP operation progress and cancellation", () => {
expect(result.ok ? undefined : result.error.cause).toBe(reason);
});
- it("lets cancellation win immediately before result publication", async () => {
- const controller = new AbortController();
- const result = await runDerivedOperation(
- context(controller),
- "compare",
- () => {
- controller.abort();
- return "must-not-publish";
- },
- );
-
- expect(result).toMatchObject({
- ok: false,
- error: { _tag: "AnalysisCancelledError" },
- });
- });
-
it("lets cancellation win while terminal progress delivery is pending", async () => {
const controller = new AbortController();
let terminalReached = false;
diff --git a/tests/acceptance/applications/electronBlankPathCli.test.ts b/tests/acceptance/applications/electronBlankPathCli.test.ts
index a03968ca11..a485add76c 100644
--- a/tests/acceptance/applications/electronBlankPathCli.test.ts
+++ b/tests/acceptance/applications/electronBlankPathCli.test.ts
@@ -3,7 +3,7 @@ import { expect } from "vitest";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest.for(["", " \t "])(
- "rejects blank Electron application_root (%j) before filesystem or provider work",
+ "rejects blank Electron application_root (%j) as invalid input",
async (applicationRoot, { cli }) => {
const response = await cli.run({
arguments: [
diff --git a/tests/acceptance/applications/electronDynamicIpcHandlersCli.test.ts b/tests/acceptance/applications/electronDynamicIpcHandlersCli.test.ts
index d9b9005998..5d013fa275 100644
--- a/tests/acceptance/applications/electronDynamicIpcHandlersCli.test.ts
+++ b/tests/acceptance/applications/electronDynamicIpcHandlersCli.test.ts
@@ -79,7 +79,7 @@ ipcRenderer.send("app:log", 1);`,
for (const surface of ["CLI", "stdio MCP"] as const)
cliTest.for(cases)(
- `keeps literal sends unknown beside $shape through ${surface}`,
+ `classifies literal sends beside $shape through ${surface}`,
async ({ main, preload, pairing }, { cli }) => {
const root = await createTestTempDirectory("rea-electron-dynamic-ipc-");
await writeFixtureFiles(root, {
diff --git a/tests/acceptance/asarSelectedCompanionCli.test.ts b/tests/acceptance/asarSelectedCompanionCli.test.ts
index 0026292553..a31d60d31b 100644
--- a/tests/acceptance/asarSelectedCompanionCli.test.ts
+++ b/tests/acceptance/asarSelectedCompanionCli.test.ts
@@ -6,6 +6,7 @@ import {
symlink,
writeFile,
} from "node:fs/promises";
+import { createHash } from "node:crypto";
import { join } from "node:path";
import { createPackageWithOptions, extractFile } from "@electron/asar";
import { expect, onTestFinished } from "vitest";
@@ -28,6 +29,7 @@ cliTest.skipIf(process.platform === "win32")(
const bytes = Buffer.from("selected native companion");
await mkdir(source);
await writeFile(join(source, "native.node"), bytes);
+ await writeFile(join(source, "packed.txt"), "packed bytes");
await createPackageWithOptions(source, selected, { unpack: "*.node" });
await rename(selected, canonical);
await symlink(canonical, selected);
@@ -54,11 +56,15 @@ cliTest.skipIf(process.platform === "win32")(
const inventory = artifactInventoryResultSchema.parse(
inventoryEvidence.normalized_result,
);
+ const occurrence = inventory.occurrences.find(
+ ({ logical_path }) => logical_path === "native.node",
+ );
+ expect(occurrence?.hash_status).toBe("verified");
expect(
- inventory.occurrences.find(
- ({ logical_path }) => logical_path === "native.node",
- )?.hash_status,
- ).toBe("verified");
+ inventory.nodes.find(
+ ({ artifact_id }) => artifact_id === occurrence?.artifact_id,
+ )?.sha256,
+ ).toBe(createHash("sha256").update(bytes).digest("hex"));
const extracted = await cli.run({
arguments: ["extract-artifact", selected, "--json"],
@@ -74,5 +80,8 @@ cliTest.skipIf(process.platform === "win32")(
expect(
(await readFile(join(result.output_root, "native.node"))).equals(bytes),
).toBe(true);
+ expect(await readFile(join(result.output_root, "packed.txt"), "utf8")).toBe(
+ "packed bytes",
+ );
},
);
diff --git a/tests/acceptance/bunStandaloneCli.test.ts b/tests/acceptance/bunStandaloneCli.test.ts
index 78d0f8a4fc..763b815043 100644
--- a/tests/acceptance/bunStandaloneCli.test.ts
+++ b/tests/acceptance/bunStandaloneCli.test.ts
@@ -16,7 +16,7 @@ import {
} from "../../src/domain/artifactGraph.js";
cliTest(
- "inventories and extracts Bun source without executing its carrier",
+ "inventories and extracts Bun source from its carrier",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-bun-cli-");
const source = join(root, "app");
diff --git a/tests/acceptance/godotPck.test.ts b/tests/acceptance/godotPck.test.ts
index 24a58416fd..d16d4b86b2 100644
--- a/tests/acceptance/godotPck.test.ts
+++ b/tests/acceptance/godotPck.test.ts
@@ -387,7 +387,7 @@ cliTest(
);
cliTest(
- "rejects repeated-range expansion before hashing members or creating extraction output",
+ "rejects repeated-range expansion without creating extraction output",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-pck-expansion-");
const source = join(root, "aliased.pck");
diff --git a/tests/acceptance/sourcePathFailuresCli.test.ts b/tests/acceptance/sourcePathFailuresCli.test.ts
index 1ae2d7c45c..6d894c6205 100644
--- a/tests/acceptance/sourcePathFailuresCli.test.ts
+++ b/tests/acceptance/sourcePathFailuresCli.test.ts
@@ -6,7 +6,7 @@ import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import { cliTest } from "../support/cli/cliFixture.js";
cliTest.skipIf(process.platform === "win32")(
- "reports unresolvable source and scenario selections without permission advice",
+ "reports unresolvable source and scenario selections with path-specific guidance",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-source-path-failures-");
await symlink("loop-b", join(root, "loop-a"));
diff --git a/tests/boundary/cli/ampRegistrationPreservation.test.ts b/tests/boundary/cli/ampRegistrationPreservation.test.ts
index 97d0842a10..507b8af71f 100644
--- a/tests/boundary/cli/ampRegistrationPreservation.test.ts
+++ b/tests/boundary/cli/ampRegistrationPreservation.test.ts
@@ -58,6 +58,7 @@ cliTest(
expect(await readFile(registrationBackupPath, "utf8")).toBe(original);
expect(refreshed.stderr).toContain(registrationBackupPath);
expect(after.theme).toBe("dark");
+ expect(after["amp.mcpServers"].other).toEqual({ command: "other" });
// The equals form --agent=amp is parsed as a spaced form before Incur sees
// it, so the Amp registration lands and keeps the environment map.
@@ -69,6 +70,7 @@ cliTest(
command: expect.any(String),
env: { KEEP_ME: "1" },
});
+ expect(afterEquals["amp.mcpServers"].other).toEqual({ command: "other" });
expect(await readFile(registrationBackupPath, "utf8")).toBe(original);
const recoveryBackupPath = equals.stderr.match(
/Amp MCP registration backup retained at (.+)/,
diff --git a/tests/boundary/cli/bundleComparisonCli.test.ts b/tests/boundary/cli/bundleComparisonCli.test.ts
index 809ae9b8aa..fcf164b79b 100644
--- a/tests/boundary/cli/bundleComparisonCli.test.ts
+++ b/tests/boundary/cli/bundleComparisonCli.test.ts
@@ -91,7 +91,11 @@ cliTest(
const display = await compare(displayPath);
expect(display.exitCode).toBe(0);
const displayResult = bundleComparisonResultSchema.parse(display.json);
- expect(displayResult).toMatchObject({ status: "unchanged", changes: [] });
+ expect(displayResult).toMatchObject({
+ status: "unchanged",
+ summary: { records_unchanged: 1, unresolved: 0 },
+ changes: [],
+ });
expect(displayResult.left_bundle_sha256).not.toBe(
displayResult.right_bundle_sha256,
);
diff --git a/tests/boundary/cli/cliEvidenceCallerPath.test.ts b/tests/boundary/cli/cliEvidenceCallerPath.test.ts
index 5c2754d63c..e2c1d08ad3 100644
--- a/tests/boundary/cli/cliEvidenceCallerPath.test.ts
+++ b/tests/boundary/cli/cliEvidenceCallerPath.test.ts
@@ -55,7 +55,12 @@ it("binds authenticated partial Evidence but preserves raw partial observations"
sha256: "a".repeat(64),
bytes: 1,
},
- { kind: "file-snapshot-hash", path: "/tmp/selected", bytes: 1 },
+ {
+ kind: "file-snapshot-hash",
+ path: "/tmp/selected",
+ sha256: "a".repeat(64),
+ bytes: 1,
+ },
],
] as const) {
const result = await finishCliEvidenceCommand(
@@ -74,5 +79,7 @@ it("binds authenticated partial Evidence but preserves raw partial observations"
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected cancellation");
expect(result.error.details?.partial_observation).toMatchObject(expected);
+ if ("kind" in expected)
+ expect(result.error.details?.partial_observation).toEqual(expected);
}
});
diff --git a/tests/boundary/cli/cliInputSchemaRequired.test.ts b/tests/boundary/cli/cliInputSchemaRequired.test.ts
index 1a65c77a51..37d3a0d407 100644
--- a/tests/boundary/cli/cliInputSchemaRequired.test.ts
+++ b/tests/boundary/cli/cliInputSchemaRequired.test.ts
@@ -85,7 +85,11 @@ const registerParserAdvertisementInventoryTests = (): void => {
it("require exactly the inputs whose omission the parser rejects", async () => {
const cli = createCli({});
const mismatches: string[] = [];
- for (const command of createCliInventory(cli).primary) {
+ const primary = createCliInventory(cli).primary;
+ expect(primary).toEqual(
+ expect.arrayContaining(["inspect-pcap-client", "inspect-pcap-capture"]),
+ );
+ for (const command of primary) {
const advertised = await advertisedSchema(cli, command);
for (const group of INPUT_GROUPS) {
const parser = parserSchema(cli, command, group);
diff --git a/tests/boundary/cli/cutterVerifierPlatform.test.ts b/tests/boundary/cli/cutterVerifierPlatform.test.ts
new file mode 100644
index 0000000000..1bef958449
--- /dev/null
+++ b/tests/boundary/cli/cutterVerifierPlatform.test.ts
@@ -0,0 +1,81 @@
+import { execFile } from "node:child_process";
+import { readFile, readdir, writeFile } from "node:fs/promises";
+import { join } from "node:path";
+import { promisify } from "node:util";
+import { expect, it } from "vitest";
+import { parse } from "yaml";
+import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
+
+const execute = promisify(execFile);
+
+it("enforces workflow platform labels before contacting Cutter", async () => {
+ const workflow = parse(
+ await readFile(".github/workflows/real-cutter.yml", "utf8"),
+ );
+ const labels = workflow.jobs["cutter-upstream"].strategy.matrix.include.map(
+ (entry: { platform: string }) => entry.platform,
+ );
+ expect(labels).toEqual(["linux", "macOS", "Windows"]);
+ const root = await createTestTempDirectory("rea-cutter-platform-");
+ const preload = join(root, "preload.mjs");
+ await writeFile(
+ preload,
+ `
+import childProcess from 'node:child_process';
+import { syncBuiltinESMExports } from 'node:module';
+Object.defineProperty(process, 'platform', { value: process.env.REA_PROBE_PLATFORM });
+childProcess.execFile = () => { throw new Error('fixture discovery reached'); };
+syncBuiltinESMExports();
+`,
+ );
+ const check = async (selected: string | undefined, actual: string) => {
+ const env: NodeJS.ProcessEnv = {
+ ...process.env,
+ TMPDIR: root,
+ TMP: root,
+ TEMP: root,
+ REA_PROBE_PLATFORM: actual,
+ };
+ if (selected === undefined) delete env.EXPECTED_PLATFORM;
+ else env.EXPECTED_PLATFORM = selected;
+ const result: unknown = await execute(
+ process.execPath,
+ ["--import", preload, "scripts/verify-real-cutter.mjs"],
+ { env, timeout: 10_000 },
+ ).then(
+ () => {
+ throw new Error("Fixture discovery should stop the verifier");
+ },
+ (error: unknown) => error,
+ );
+ if (
+ !(result instanceof Error) ||
+ !("stderr" in result) ||
+ typeof result.stderr !== "string"
+ )
+ throw new Error("Missing verifier diagnostics");
+ return result.stderr;
+ };
+ for (const [selected, actual] of [
+ ["linux", "linux"],
+ ["macOS", "darwin"],
+ ["Windows", "win32"],
+ ] as const)
+ expect(await check(selected, actual)).toContain(
+ "fixture discovery reached",
+ );
+ expect(await check("linux", "darwin")).toContain(
+ "Cutter runner did not match its declared platform",
+ );
+ expect(await check("unknown", "linux")).toContain(
+ "Unrecognized Cutter runner platform",
+ );
+ expect(await check(undefined, "linux")).toContain(
+ "fixture discovery reached",
+ );
+ expect(
+ (await readdir(root)).filter((name) =>
+ name.startsWith("rea-cutter-smoke-"),
+ ),
+ ).toEqual([]);
+});
diff --git a/tests/boundary/cli/evidenceBundleCommands.test.ts b/tests/boundary/cli/evidenceBundleCommands.test.ts
index d21424da9b..778f867692 100644
--- a/tests/boundary/cli/evidenceBundleCommands.test.ts
+++ b/tests/boundary/cli/evidenceBundleCommands.test.ts
@@ -475,7 +475,7 @@ cliTest(
);
cliTest(
- "diagnoses an obsolete explicit-null Evidence commitment without claiming the file was modified",
+ "diagnoses an obsolete explicit-null Evidence commitment",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-legacy-coverage-identity-");
const path = join(root, "legacy.json");
diff --git a/tests/boundary/cli/pcapCli.test.ts b/tests/boundary/cli/pcapCli.test.ts
index aa4986bd3b..e042f4985b 100644
--- a/tests/boundary/cli/pcapCli.test.ts
+++ b/tests/boundary/cli/pcapCli.test.ts
@@ -2,15 +2,6 @@ import { expect, it } from "vitest";
import { expectConfigurationRefusal, serveCli } from "./cliServeHarness.js";
-it.each(["inspect-pcap-client", "inspect-pcap-capture"])(
- "%s advertises a schema through the public CLI",
- async (command) => {
- const result = await serveCli([command, "--schema", "--json"]);
- expect(result.exitCode).toBe(0);
- expect(JSON.parse(result.stdout)).toBeTruthy();
- },
-);
-
it.each([
["inspect-pcap-client"],
["inspect-pcap-capture", "/nonexistent/capture.pcap"],
diff --git a/tests/boundary/cli/reverseEngineeringCommands.test.ts b/tests/boundary/cli/reverseEngineeringCommands.test.ts
index ee9a7d5eab..77a7ceef67 100644
--- a/tests/boundary/cli/reverseEngineeringCommands.test.ts
+++ b/tests/boundary/cli/reverseEngineeringCommands.test.ts
@@ -373,8 +373,9 @@ it("does not project cancellation cleanup as incomplete after a successful retry
});
it("returns cancellation with the completed observation when the caller interrupts service close", async () => {
+ const evidence = observation("complete");
const service = {
- inspectWithObjdump: vi.fn(async () => ok(observation("complete"))),
+ inspectWithObjdump: vi.fn(async () => ok(evidence)),
close: vi.fn(async () => {
process.emit("SIGINT");
}),
@@ -382,7 +383,10 @@ it("returns cancellation with the completed observation when the caller interrup
const result = await runObjdump(service);
- expect(result).toMatchObject({ code: "cancelled" });
+ expect(result).toMatchObject({
+ code: "cancelled",
+ details: { partial_observation: evidence },
+ });
expect(process.exitCode).toBe(130);
});
diff --git a/tests/boundary/evm/evmoleInterfaceProvider.test.ts b/tests/boundary/evm/evmoleInterfaceProvider.test.ts
index 1f79921ba6..9edd10309e 100644
--- a/tests/boundary/evm/evmoleInterfaceProvider.test.ts
+++ b/tests/boundary/evm/evmoleInterfaceProvider.test.ts
@@ -40,6 +40,7 @@ it.runIf(unsupportedHost)(
encoding: "hex",
});
if (result.ok) throw new Error("Expected a host refusal");
+ expect(result.error._tag).toBe("AnalysisCapabilityUnavailableError");
const projected = projectAnalysisError(result.error);
expect(projected).toMatchObject({ code: "capability_unavailable" });
expect(projected.message).toContain("Linux x64");
@@ -715,21 +716,6 @@ it.runIf(!unsupportedHost)(
},
);
-it.runIf(unsupportedHost)(
- "reports unverified host coverage before acquiring a provider",
- async () => {
- expect(
- await new EvmoleInterfaceProvider({}).inspect({
- path: "/selected.hex",
- encoding: "hex",
- }),
- ).toMatchObject({
- ok: false,
- error: { _tag: "AnalysisCapabilityUnavailableError" },
- });
- },
-);
-
it.runIf(!unsupportedHost)(
"preserves actual snapshot-write cancellation and root cleanup",
async () => {
diff --git a/tests/boundary/filesystem/asarSelectedCompanion.test.ts b/tests/boundary/filesystem/asarSelectedCompanion.test.ts
index 9fbcc0f3f2..4b500abdba 100644
--- a/tests/boundary/filesystem/asarSelectedCompanion.test.ts
+++ b/tests/boundary/filesystem/asarSelectedCompanion.test.ts
@@ -38,40 +38,6 @@ const fixture = async () => {
return { root, selected, canonical };
};
-it.skipIf(process.platform === "win32")(
- "inventories and extracts the same selected ASAR companion as Electron tooling",
- async () => {
- const { root, selected } = await fixture();
- expect(extractFile(selected, "native.node").equals(bytes)).toBe(true);
- const inventory = await inventoryArtifact(selected);
- const occurrence = inventory.occurrences.find(
- ({ logical_path }) => logical_path === "native.node",
- );
- expect(occurrence?.hash_status).toBe("verified");
- expect(
- inventory.nodes.find(
- ({ artifact_id }) => artifact_id === occurrence?.artifact_id,
- )?.sha256,
- ).toBe(createHash("sha256").update(bytes).digest("hex"));
- const result = await withArtifactResourceScope((resourceScope) =>
- extractArtifact({
- inputPath: selected,
- inputFormat: "asar",
- outputRoot: join(root, "output"),
- environment: {},
- integrityPolicy: "fail",
- resourceScope,
- }),
- );
- expect(
- (await readFile(join(result.output_root, "native.node"))).equals(bytes),
- ).toBe(true);
- expect(await readFile(join(result.output_root, "packed.txt"), "utf8")).toBe(
- "packed bytes",
- );
- },
-);
-
it.skipIf(process.platform === "win32")(
"does not substitute the canonical archive companion for an absent selected companion",
async () => {
diff --git a/tests/boundary/filesystem/bufferDeepEqualityLint.test.ts b/tests/boundary/filesystem/bufferDeepEqualityLint.test.ts
index 38c433b070..4637774b26 100644
--- a/tests/boundary/filesystem/bufferDeepEqualityLint.test.ts
+++ b/tests/boundary/filesystem/bufferDeepEqualityLint.test.ts
@@ -63,14 +63,6 @@ new RuleTester({
expect(bytes).toEqual(value);`,
],
invalid: [
- {
- // Exact pre-fix ELF test shape: readFile without an encoding returns Buffer.
- code: `import { readFile } from "node:fs/promises";
- import { expect } from "vitest";
- const before = await readFile(path);
- expect(await readFile(path)).toEqual(before);`,
- errors: [{ messageId: "nativeBytes" }],
- },
{
code: `import { readFileSync as read } from "node:fs";
import { expect } from "vitest";
diff --git a/tests/boundary/filesystem/ciCacheRetention.test.ts b/tests/boundary/filesystem/ciCacheRetention.test.ts
index d455b83500..571d05bd22 100644
--- a/tests/boundary/filesystem/ciCacheRetention.test.ts
+++ b/tests/boundary/filesystem/ciCacheRetention.test.ts
@@ -269,13 +269,20 @@ describe("retention orchestration", () => {
it("deletes nothing when a later list is incomplete", async () => {
const deleted: number[] = [];
- const page = Array.from({ length: 100 }, (_, index) =>
- cache(index + 1, `${prefix}${String(index)}`, "2026-10-20T01:00:00Z"),
- );
+ const requests: string[] = [];
+ const page = [
+ cache(1, `${prefix}old`, "2026-10-20T01:00:00Z"),
+ cache(2, `${prefix}mid`, "2026-10-20T02:00:00Z"),
+ cache(3, `${prefix}new`, "2026-10-20T03:00:00Z"),
+ ];
await expect(
retainCaches({
repository,
request: async (_method, endpoint) => {
+ requests.push(
+ new URL(endpoint, "https://example.test").searchParams.get("key") ??
+ "",
+ );
if (endpoint.includes("npm-download-"))
throw new Error("list failed after the first family");
return { actions_caches: page };
@@ -283,10 +290,39 @@ describe("retention orchestration", () => {
deleteCache: async (id) => {
deleted.push(id);
},
- families: [{ prefix, keepKey: `${prefix}0` }],
+ families: [{ prefix, keepKey: `${prefix}new` }],
dedupeNpmDownloads: true,
}),
- ).rejects.toThrow(/list failed|exceeded/u);
+ ).rejects.toThrow("list failed after the first family");
+ expect(requests).toEqual([prefix, "npm-download-"]);
+ expect(deleted).toEqual([]);
+ });
+});
+
+describe("cache listing and retention", () => {
+ const repository = "morluto/rea";
+ const prefix = "rea-static-v1-Linux-X64-";
+
+ it("deletes nothing when the cache listing reaches the page cap", async () => {
+ const deleted: number[] = [];
+ let requests = 0;
+ const page = Array.from({ length: 100 }, (_, index) =>
+ cache(index + 1, `${prefix}${String(index)}`, "2026-10-20T01:00:00Z"),
+ );
+ await expect(
+ retainCaches({
+ repository,
+ request: async () => {
+ requests += 1;
+ return { actions_caches: page };
+ },
+ deleteCache: async (id) => {
+ deleted.push(id);
+ },
+ families: [{ prefix, keepKey: `${prefix}0` }],
+ }),
+ ).rejects.toThrow(/exceeded.*pages/u);
+ expect(requests).toBe(10);
expect(deleted).toEqual([]);
});
diff --git a/tests/boundary/filesystem/ciFeedback.test.ts b/tests/boundary/filesystem/ciFeedback.test.ts
index d05c7c93d4..48530fd75f 100644
--- a/tests/boundary/filesystem/ciFeedback.test.ts
+++ b/tests/boundary/filesystem/ciFeedback.test.ts
@@ -12,7 +12,6 @@ import {
parseStaticTaskContext,
recordStaticTaskContext,
} from "../../../scripts/ci/static-task-context.mjs";
-import { createGhApiRequest } from "../../../scripts/ci/github-api.mjs";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const execute = promisify(execFile);
@@ -339,17 +338,6 @@ it("records the actual static task graph with explicit source identity and no am
expect(() => parseStaticTaskContext(invalid)).toThrow();
});
-it("rejects mutation methods at the shared GitHub transport before invoking the CLI", async () => {
- const request = createGhApiRequest({ env: { PATH: "" } });
- await expect(
- request("POST", "repos/owner/repo/actions/runs/1/rerun", {
- requests: 0,
- startedAt: Date.now(),
- limitMs: 1000,
- }),
- ).rejects.toThrow("read-only GET");
-});
-
it("collects basic CI telemetry before optional dependency installation can fail", async () => {
const { jobs } = z
.object({
diff --git a/tests/boundary/filesystem/ciJobTimingsBatch.test.ts b/tests/boundary/filesystem/ciJobTimingsBatch.test.ts
index e0dcecc824..c3ea01bb55 100644
--- a/tests/boundary/filesystem/ciJobTimingsBatch.test.ts
+++ b/tests/boundary/filesystem/ciJobTimingsBatch.test.ts
@@ -91,15 +91,20 @@ it("collects the latest attempt for recent completed CI and Release runs into a
headBranch: null,
},
]);
- expect(manifest.runs).toEqual(
- expect.arrayContaining([
- expect.objectContaining({
- status: "collected",
- rawPath: expect.any(String),
- reportPath: expect.any(String),
- }),
- ]),
- );
+ for (const { id, runAttempt, status, rawPath, reportPath } of manifest.runs) {
+ const directory = join(
+ fixture.outputDirectory,
+ "runs",
+ `${id}-${runAttempt}`,
+ );
+ expect({ status, rawPath, reportPath }).toEqual({
+ status: "collected",
+ rawPath: join(directory, "jobs.json"),
+ reportPath: join(directory, "report.json"),
+ });
+ await expect(readFile(rawPath, "utf8")).resolves.toBeTruthy();
+ await expect(readFile(reportPath, "utf8")).resolves.toBeTruthy();
+ }
expect(calls).toContainEqual([
"api",
"--paginate",
diff --git a/tests/boundary/filesystem/ciPrHealth.test.ts b/tests/boundary/filesystem/ciPrHealth.test.ts
index c9d7a968b4..ca1ace52aa 100644
--- a/tests/boundary/filesystem/ciPrHealth.test.ts
+++ b/tests/boundary/filesystem/ciPrHealth.test.ts
@@ -11,7 +11,6 @@ import {
matchRunToPullRequest,
writePrCiHealthReport,
} from "../../../scripts/ci/pr-ci-health.mjs";
-import { createGhApiRequest } from "../../../scripts/ci/github-api.mjs";
import type {
PrCiPullRequest,
PrCiWorkflowRun,
@@ -453,23 +452,44 @@ it("public CLI uses only GET and produces a report from fixture GitHub responses
it("rejects non-GET methods before launching the GitHub client", async () => {
const fixture = await createFixture();
- const request = createGhApiRequest({
- env: {
- ...process.env,
- PATH: `${fixture.fakeBin}${delimiter}${process.env.PATH ?? ""}`,
- CI_GH_CALLS: join(fixture.directory, "should-not-exist"),
- },
- });
- await expect(
- request("POST", "repos/owner/rea/pulls", {
- requests: 0,
- startedAt: observedAt,
- limitMs: 1_000,
- }),
- ).rejects.toThrow("read-only GET");
- await expect(
- readFile(join(fixture.directory, "should-not-exist")),
- ).rejects.toMatchObject({ code: "ENOENT" });
+ const marker = join(fixture.directory, "gh-invoked");
+ const preload = join(fixture.directory, "watch-gh.cjs");
+ await writeFile(
+ preload,
+ `const fs = require("node:fs");
+const util = require("node:util");
+const child = require("node:child_process");
+child.execFile = () => { throw new Error("Unexpected callback invocation"); };
+child.execFile[util.promisify.custom] = async () => {
+ fs.appendFileSync(process.env.CI_GH_CALLS, "called\\n");
+ return { stdout: "{}", stderr: "" };
+};
+require("node:module").syncBuiltinESMExports();
+`,
+ );
+ const transport = new URL(
+ "../../../scripts/ci/github-api.mjs",
+ import.meta.url,
+ ).href;
+ await executeWorkflowFixture(
+ process.execPath,
+ [
+ "--require",
+ preload,
+ "--input-type=module",
+ "-e",
+ `
+ import assert from "node:assert/strict";
+ import { createGhApiRequest } from ${JSON.stringify(transport)};
+ const request = createGhApiRequest();
+ const budget = { requests: 0, startedAt: Date.now(), limitMs: 10_000 };
+ await assert.rejects(request("POST", "repos/owner/rea/pulls", budget), /read-only GET/);
+ await request("GET", "repos/owner/rea/pulls", budget);
+ `,
+ ],
+ { cwd: fixture.directory, env: { ...process.env, CI_GH_CALLS: marker } },
+ );
+ expect(await readFile(marker, "utf8")).toBe("called\n");
});
function validPull(overrides: Partial = {}): PrCiPullRequest {
diff --git a/tests/boundary/filesystem/ciTestHistory.test.ts b/tests/boundary/filesystem/ciTestHistory.test.ts
index 0d2093f7cb..9cf82548cb 100644
--- a/tests/boundary/filesystem/ciTestHistory.test.ts
+++ b/tests/boundary/filesystem/ciTestHistory.test.ts
@@ -132,23 +132,23 @@ it("selects the latest trusted full run that actually published timing history",
expect(output).toBe("run-id=11\nartifact-name=test-timings-full\n");
expect(calls).toContain("name=test-timings-full");
expect(calls).toContain("per_page=100");
+ expect(calls).not.toContain("actions/runs/13");
expect(calls.match(/actions\/runs\//gu)).toHaveLength(3);
expect(calls).not.toContain("actions/workflows");
});
-it("rejects expired, foreign, old, and pull-request candidates", async () => {
+it("rejects expired, old, and pull-request candidates", async () => {
const { result, output } = await invoke(
[
artifact(15, { expired: true }),
- artifact(14, {
- workflow_run: { ...artifact(14).workflow_run, head_repository_id: 2 },
- }),
artifact(13, {
created_at: new Date(now - 31 * 24 * 60 * 60 * 1000).toISOString(),
}),
artifact(12),
],
{
+ 15: run(15),
+ 13: run(13),
12: run(12, { event: "pull_request" }),
},
{ tier: "full" },
@@ -197,22 +197,25 @@ it("bounds run lookups to five artifacts even when inventory has more", async ()
expect(calls.match(/actions\/runs\//gu)).toHaveLength(5);
});
-it("returns empty history without querying for an invalid repository identity", async () => {
- const { result, output, calls } = await invoke(
- [],
- {},
- {
- repository: "owner/repo?per_page=100",
- repositoryId: "not-an-id",
- },
- );
- expect(JSON.parse(result.stdout)).toEqual({
- run_id: "",
- artifact_name: "",
- });
- expect(output).toBe("run-id=\nartifact-name=\n");
- expect(calls).toBe("");
-});
+it.each([
+ { repository: "owner/repo?per_page=100", repositoryId: "1" },
+ { repository: "example/rea", repositoryId: "not-an-id" },
+])(
+ "returns empty history without querying for an invalid repository identity: %j",
+ async (identity) => {
+ const { result, output, calls } = await invoke(
+ [],
+ {},
+ { ...identity, tier: "full" },
+ );
+ expect(JSON.parse(result.stdout)).toEqual({
+ run_id: "",
+ artifact_name: "",
+ });
+ expect(output).toBe("run-id=\nartifact-name=\n");
+ expect(calls).toBe("");
+ },
+);
it("selects fast history without reading the full-tier artifact", async () => {
const { result, calls } = await invoke(
diff --git a/tests/boundary/filesystem/ghidraBridgeSources.test.ts b/tests/boundary/filesystem/ghidraBridgeSources.test.ts
index dc19ac0411..4ef89f268b 100644
--- a/tests/boundary/filesystem/ghidraBridgeSources.test.ts
+++ b/tests/boundary/filesystem/ghidraBridgeSources.test.ts
@@ -46,6 +46,7 @@ const installation = async (
javac,
[
"#!/bin/sh",
+ 'printf "invoked\\n" >> "$REA_JAVAC_MARKER"',
'if [ "$1" = "-version" ]; then echo "javac 21.0.12"; exit 0; fi',
...(compilerStatus === 0
? ["exit 0"]
@@ -60,8 +61,10 @@ const installation = async (
await mkdir(scratchParent);
return {
scratchParent,
+ javacMarker: join(root, "javac-invocations"),
environment: {
...process.env,
+ REA_JAVAC_MARKER: join(root, "javac-invocations"),
GHIDRA_INSTALL_DIR: install,
JAVA_HOME: javaHome,
TMPDIR: scratchParent,
@@ -193,6 +196,9 @@ it.skipIf(process.platform === "win32").each([
),
});
expect(await readdir(fixture.scratchParent)).toEqual([]);
+ await expect(readFile(fixture.javacMarker)).rejects.toMatchObject({
+ code: "ENOENT",
+ });
},
);
diff --git a/tests/boundary/filesystem/ghidraInstallationProperties.test.ts b/tests/boundary/filesystem/ghidraInstallationProperties.test.ts
index 97cf2a61da..5f8b147de0 100644
--- a/tests/boundary/filesystem/ghidraInstallationProperties.test.ts
+++ b/tests/boundary/filesystem/ghidraInstallationProperties.test.ts
@@ -277,6 +277,7 @@ it.each(["read", "capacity", "completed"] as const)(
},
},
});
+ expect(failure.cause).toBe(reason);
} else if (outcome === "capacity") {
expect(projectAnalysisError(failure).code).toBe("resource_constraint");
} else {
diff --git a/tests/boundary/filesystem/ghidraLanguageCatalogRecovery.test.ts b/tests/boundary/filesystem/ghidraLanguageCatalogRecovery.test.ts
index 632832d42d..31adbada80 100644
--- a/tests/boundary/filesystem/ghidraLanguageCatalogRecovery.test.ts
+++ b/tests/boundary/filesystem/ghidraLanguageCatalogRecovery.test.ts
@@ -218,6 +218,7 @@ it.each(["released", "still failing"] as const)(
cause: reason,
cleanupIncomplete: false,
});
+ expect(cancelled.error.cause).toBe(reason);
expect(first.error.cleanupIncomplete).toBe(false);
expect(registry.hasPendingOwnedResources()).toBe(false);
} else {
@@ -252,7 +253,7 @@ it("keeps the caller's reason and the catalog owner when cancellation lands duri
cleanupIncomplete: true,
cleanupResources: [definition],
});
- expect(JSON.stringify(resolved.error.cause)).toContain(reason.caller);
+ expect(resolved.error.cause).toBe(reason);
expect(provider.hasPendingOwnedResources()).toBe(true);
fault.deny = false;
fault.onClose = undefined;
diff --git a/tests/boundary/filesystem/javascript-applications/javascriptPackageRendererProvenance.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptPackageRendererProvenance.test.ts
index 07bb01a5e1..d35954b05c 100644
--- a/tests/boundary/filesystem/javascript-applications/javascriptPackageRendererProvenance.test.ts
+++ b/tests/boundary/filesystem/javascript-applications/javascriptPackageRendererProvenance.test.ts
@@ -39,13 +39,6 @@ it.each(["renderer", "browser", "module"] as const)(
}),
);
const metadata = graph.nodes.find(({ kind }) => kind === "package");
- expect(metadata?.observations).toContainEqual(
- expect.objectContaining({
- properties: expect.objectContaining({
- renderer_declarations: { [field]: "entry.js" },
- }),
- }),
- );
expect(metadata?.observations[0]?.properties).not.toHaveProperty(
"renderer",
);
diff --git a/tests/boundary/filesystem/pythonPyc.test.ts b/tests/boundary/filesystem/pythonPyc.test.ts
index 736db15458..25226f9f35 100644
--- a/tests/boundary/filesystem/pythonPyc.test.ts
+++ b/tests/boundary/filesystem/pythonPyc.test.ts
@@ -48,9 +48,6 @@ describe("Python pyc stable filesystem boundary", () => {
const tooSmall = await service.inspect({ path, max_file_bytes: 16 });
if (tooSmall.ok) throw new Error("Expected resource budget failure");
expect(tooSmall.error._tag).toBe("AnalysisResourceConstraintError");
- const tooFewObjects = await service.inspect({ path, max_objects: 1 });
- if (tooFewObjects.ok) throw new Error("Expected object budget failure");
- expect(tooFewObjects.error._tag).toBe("AnalysisResourceConstraintError");
for (const [field, selected] of [
["max_objects", 1],
["max_depth", 1],
@@ -58,6 +55,8 @@ describe("Python pyc stable filesystem boundary", () => {
] as const) {
const refused = await service.inspect({ path, [field]: selected });
if (refused.ok) throw new Error(`Expected ${field} refusal`);
+ if (field === "max_objects")
+ expect(refused.error._tag).toBe("AnalysisResourceConstraintError");
const projected = projectAnalysisError(refused.error);
expect(projected).toMatchObject({
code: "resource_constraint",
diff --git a/tests/boundary/filesystem/releaseNotes.test.ts b/tests/boundary/filesystem/releaseNotes.test.ts
index 95ea310305..38a601a19d 100644
--- a/tests/boundary/filesystem/releaseNotes.test.ts
+++ b/tests/boundary/filesystem/releaseNotes.test.ts
@@ -528,15 +528,10 @@ it("accepts Release Please lockfile refreshes without allowing product changes",
join(f.directory, "package-lock.json"),
'{"lockfileVersion":3}',
);
- await writeFile(
- join(f.directory, "package-lock.json"),
- '{"lockfileVersion":3}',
- );
await git(f.directory, [
"add",
"CHANGELOG.md",
"package-lock.json",
- "package-lock.json",
]);
await git(f.directory, ["commit", "-m", "chore: release lockfiles"]);
await f.invoke(["check", "--manifest", f.manifest, "--source", "HEAD"]);
diff --git a/tests/boundary/go/goBinaryFinalization.test.ts b/tests/boundary/go/goBinaryFinalization.test.ts
index 7522082264..8db9563eba 100644
--- a/tests/boundary/go/goBinaryFinalization.test.ts
+++ b/tests/boundary/go/goBinaryFinalization.test.ts
@@ -65,6 +65,7 @@ it.each(["control", "close-failure", "close-cancel", "close-both"] as const)(
_tag: "AnalysisCancelledError",
cause: reason,
});
+ expect(primary.cause).toBe(reason);
}
close.mockRestore();
await service.close();
diff --git a/tests/boundary/go/goBinaryImage.test.ts b/tests/boundary/go/goBinaryImage.test.ts
index 362abad5a0..07805f1c4a 100644
--- a/tests/boundary/go/goBinaryImage.test.ts
+++ b/tests/boundary/go/goBinaryImage.test.ts
@@ -119,6 +119,7 @@ it.each([
it("continues past an empty file-backed ELF data load", () => {
const fixture = createGoSplitElfFixture({ sectionless: true });
const expected = readGoBinaryImage(fixture.bytes).build_info;
+ expect(expected).not.toBeNull();
fixture.bytes.writeBigUInt64LE(0n, 128 + 32);
expect(readGoBinaryImage(fixture.bytes).build_info).toEqual(expected);
});
@@ -135,6 +136,7 @@ it.each([4, 5, 7])(
it("prefers the named ELF section to an earlier writable-load marker", () => {
const fixture = createGoSplitElfFixture();
const expected = readGoBinaryImage(fixture.bytes).build_info;
+ expect(expected).not.toBeNull();
fixture.bytes.copy(
fixture.bytes,
512,
diff --git a/tests/boundary/go/goBinaryP32PointerWidth.test.ts b/tests/boundary/go/goBinaryP32PointerWidth.test.ts
deleted file mode 100644
index 0602d8549c..0000000000
--- a/tests/boundary/go/goBinaryP32PointerWidth.test.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { expect, it } from "vitest";
-import { readGoBinaryImage } from "../../../src/go/GoBinaryImage.js";
-import {
- createGoBinaryFixture,
- GO_MODULE_TEXT,
-} from "../../fixtures/go/image.js";
-
-it("decodes legacy ELF64 Go strings at the record's four-byte pointer width", () => {
- const fixture = createGoBinaryFixture({
- format: "elf",
- bits: 64,
- encoding: "pointer",
- pointerSize: 4,
- goVersion: "go1.13.15",
- });
-
- expect(readGoBinaryImage(fixture.bytes)).toMatchObject({
- format: "elf",
- architecture: "amd64",
- bits: 64,
- build_info: {
- encoding: "pointer",
- go_version: "go1.13.15",
- module_text: GO_MODULE_TEXT,
- version_location: { offset: fixture.versionOffset, bytes: 9 },
- module_location: {
- offset: fixture.moduleOffset,
- bytes: fixture.moduleBytes.length,
- },
- },
- });
-});
diff --git a/tests/boundary/gpu/codeObjects.test.ts b/tests/boundary/gpu/codeObjects.test.ts
index a508d009ff..73e693d59a 100644
--- a/tests/boundary/gpu/codeObjects.test.ts
+++ b/tests/boundary/gpu/codeObjects.test.ts
@@ -499,14 +499,17 @@ it.each([
const inventory = await inspect(bytes, { analysis: "inventory" });
if (!inventory.ok) throw inventory.error;
const row = inventory.value.objects.find((value) => value.kind === "amdgpu")!;
- expect(row.target).not.toBeNull();
- const selected = await inspect(bytes, { targets: [row.target!] });
+ const expectedTarget = targetId.endsWith("opaque")
+ ? "amdgcn-amd-amdhsa--gfx900"
+ : "gfx900";
+ expect(row.target).toBe(expectedTarget);
+ const selected = await inspect(bytes, { targets: [expectedTarget] });
if (!selected.ok) throw selected.error;
expect(selected.value.kernels).toHaveLength(1);
expect(
selected.value.objects.find((value) => value.kind === "amdgpu"),
).toMatchObject({
- target: row.target,
+ target: expectedTarget,
payload_target: "amdgcn-amd-amdhsa--gfx900",
target_consistency: targetId.endsWith("opaque")
? "single-source"
diff --git a/tests/boundary/il2cpp/il2cppBinaryFile.test.ts b/tests/boundary/il2cpp/il2cppBinaryFile.test.ts
index 81c9e97bde..2f6010e787 100644
--- a/tests/boundary/il2cpp/il2cppBinaryFile.test.ts
+++ b/tests/boundary/il2cpp/il2cppBinaryFile.test.ts
@@ -1173,7 +1173,9 @@ it.each([1, 0xff])(
(padding) => {
const bytes = createIl2cppBinaryFixture();
bytes.fill(padding, 0x604, 0x608);
- expect(link(bytes)).toEqual(link(createIl2cppBinaryFixture()));
+ const linked = link(bytes);
+ expect(linked.method_addresses).toEqual(expectedAddresses);
+ expect(linked).toEqual(link(createIl2cppBinaryFixture()));
bytes.writeUInt32LE(3, 0x600);
expect(failure(bytes).reason).toBe("code-registration-not-found");
},
@@ -1834,12 +1836,6 @@ it("keeps a capacity refusal while naming a generic row a refusal", () => {
expect((failure as Il2cppBinaryFormatFailure).kind).toBe("capacity");
});
-it("ignores CodeRegistration count alignment padding", () => {
- const bytes = createIl2cppBinaryFixture();
- bytes.fill(0xff, 0x604, 0x608);
- expect(link(bytes).method_addresses).toEqual(expectedAddresses);
-});
-
it.each([0, 8, 16])(
"finds registration with %s file-backed trailing zero bytes",
(tail) => {
diff --git a/tests/boundary/mcp/cutterCancellationMcp.test.ts b/tests/boundary/mcp/cutterCancellationMcp.test.ts
index 4a2a5ca589..f8b520e511 100644
--- a/tests/boundary/mcp/cutterCancellationMcp.test.ts
+++ b/tests/boundary/mcp/cutterCancellationMcp.test.ts
@@ -114,7 +114,7 @@ it.skipIf(process.platform === "win32")(
},
);
-it("propagates MCP cancellation into an active Cutter command and reports uncertain completion", async () => {
+it("propagates MCP cancellation into an active Cutter command", async () => {
let markDispatched: (() => void) | undefined;
let observedAbort = false;
const dispatched = new Promise((resolve) => {
diff --git a/tests/boundary/mcp/enhancedTools.swiftTypes.test.ts b/tests/boundary/mcp/enhancedTools.swiftTypes.test.ts
index 82fc8d4945..9d6c0f2a95 100644
--- a/tests/boundary/mcp/enhancedTools.swiftTypes.test.ts
+++ b/tests/boundary/mcp/enhancedTools.swiftTypes.test.ts
@@ -147,15 +147,24 @@ describe("Swift classification through MCP", () => {
it("returns cancellation during the symbol join", async () => {
const controller = new AbortController();
+ const reason = { stage: "symbol-join" };
const tools = new EnhancedTools({
execute: async (operation) => {
- if (operation === "list_names") controller.abort();
+ if (operation === "list_names") controller.abort(reason);
return ok([{ address: "0x1", value: "$s4main4PairVMa" }]);
},
});
- expect(
- await tools.execute("analyze_swift_types", {}, controller.signal),
- ).toMatchObject({ ok: false, error: { _tag: "AnalysisCancelledError" } });
+ const result = await tools.execute(
+ "analyze_swift_types",
+ {},
+ controller.signal,
+ );
+ expect(result).toMatchObject({
+ ok: false,
+ error: { _tag: "AnalysisCancelledError", operation: "list_names" },
+ });
+ if (result.ok) throw new Error("Expected cancellation");
+ expect(result.error.cause).toBe(reason);
});
});
diff --git a/tests/boundary/mcp/flutterMcp.test.ts b/tests/boundary/mcp/flutterMcp.test.ts
index d76c022367..dda9ac505c 100644
--- a/tests/boundary/mcp/flutterMcp.test.ts
+++ b/tests/boundary/mcp/flutterMcp.test.ts
@@ -13,6 +13,7 @@ import {
flutterResultSchemas,
} from "../../../src/domain/flutter/flutterBuildAnalysis.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
+import { parseMcpEvidenceBundle } from "../../fixtures/mcpEvidenceBundle.js";
import { aotFixtureImage } from "../../../src/flutter/FlutterBuild.fixture.js";
import { createFlutterApk } from "../../fixtures/flutterApk.js";
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
@@ -318,6 +319,14 @@ it("advertises an exact valid Flutter schema and records inline evidence through
.map((part) => part.text ?? "")
.join("");
const inspectedEvidence = parseEvidence(JSON.parse(inspectedText));
+ const bundle = await client.callTool({
+ name: "get_evidence_bundle",
+ arguments: {},
+ });
+ expect(bundle.isError).not.toBe(true);
+ const records = parseMcpEvidenceBundle(bundle).records;
+ expect(records).toContainEqual(evidence);
+ expect(records).toContainEqual(inspectedEvidence);
expect(inspectedEvidence.normalized_result).toMatchObject({
abi: "arm64-v8a",
libapp: {
diff --git a/tests/boundary/mcp/javascriptRuntimeObservationMcp.test.ts b/tests/boundary/mcp/javascriptRuntimeObservationMcp.test.ts
index 82edcee870..77b3413ed5 100644
--- a/tests/boundary/mcp/javascriptRuntimeObservationMcp.test.ts
+++ b/tests/boundary/mcp/javascriptRuntimeObservationMcp.test.ts
@@ -20,6 +20,7 @@ import { JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE } from "../../../src/contract
import { createJavaScriptRuntimeObservationEvidence } from "../../../src/application/javascript/JavaScriptRuntimeObservationEvidence.js";
import { V8_INSPECTOR_PROVIDER_IDENTITY } from "../../../src/inspector/providerIdentity.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
+import { parseMcpEvidenceBundle } from "../../fixtures/mcpEvidenceBundle.js";
import { observed } from "../../fixtures/analysisExecution.js";
import { startFakeV8Inspector } from "../../fixtures/inspector/fakeV8Inspector.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
@@ -271,6 +272,14 @@ function registerRetainedRuntimeEvidence(
},
});
const evidenceId = evidenceIdFrom(observedRuntime.structuredContent);
+ const bundle = await client.callTool({
+ name: "get_evidence_bundle",
+ arguments: {},
+ });
+ expect(bundle.isError).not.toBe(true);
+ expect(parseMcpEvidenceBundle(bundle).records).toContainEqual(
+ observedRuntime.structuredContent,
+ );
expect(observedRuntime.structuredContent).toMatchObject({
evidence_id: evidenceId,
operation: "observe_javascript_runtime",
diff --git a/tests/boundary/mcp/managedMcp.test.ts b/tests/boundary/mcp/managedMcp.test.ts
index 4e45cf91fb..ba370ca045 100644
--- a/tests/boundary/mcp/managedMcp.test.ts
+++ b/tests/boundary/mcp/managedMcp.test.ts
@@ -344,6 +344,16 @@ const verifyManagedCatalogAndNativeWorkflow = async (
await outputAssertion.assert("verify_managed_native_boundaries", verified);
expect(verified).toMatchObject({
evidence_id: expect.stringMatching(/^ev_[a-f0-9]{64}$/u),
+ operation: "verify_managed_native_boundaries",
+ provider: { id: "rea-dotnet-workflows" },
+ confidence: "inferred",
+ authority: "analyst-inference",
+ evidence_links: [
+ MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries.evidence_id,
+ ...MANAGED_NATIVE_VERIFICATION_EXAMPLE.native_observations.map(
+ ({ evidence_id }) => evidence_id,
+ ),
+ ],
normalized_result: {
summary: { verified: 1 },
algorithm: { token_to_address_mapping: "not-inferred" },
diff --git a/tests/boundary/mcp/modelArtifactPartialCancellation.test.ts b/tests/boundary/mcp/modelArtifactPartialReadFailure.test.ts
similarity index 95%
rename from tests/boundary/mcp/modelArtifactPartialCancellation.test.ts
rename to tests/boundary/mcp/modelArtifactPartialReadFailure.test.ts
index 58df84f360..857c8fa0fa 100644
--- a/tests/boundary/mcp/modelArtifactPartialCancellation.test.ts
+++ b/tests/boundary/mcp/modelArtifactPartialReadFailure.test.ts
@@ -52,7 +52,7 @@ mcpTest.for([
{ retained: false, fullHash: true },
{ retained: true, fullHash: true },
])(
- "projects partial model Evidence through an MCP tool error ($retained, fullHash=$fullHash)",
+ "projects partial model Evidence after a denied read ($retained, fullHash=$fullHash)",
async ({ retained, fullHash }, { mcp }) => {
const root = await createTestTempDirectory("rea-model-mcp-partial-");
const path = join(root, fullHash ? "model.safetensors" : "model.gguf");
@@ -133,6 +133,14 @@ mcpTest.for([
});
if (!observedArrayChunk) throw new Error(JSON.stringify(response));
const projected = parseMcpToolError(response);
+ expect(projected.error).toMatchObject({
+ code: "access_denied",
+ details: {
+ operation: "inspect_model_artifact",
+ path,
+ system_code: "EACCES",
+ },
+ });
const details = projected.error.details;
if (details === undefined)
throw new Error("MCP error omitted its partial observation");
diff --git a/tests/boundary/mcp/pcapMcp.test.ts b/tests/boundary/mcp/pcapMcp.test.ts
index 95154eb14e..8678cac2df 100644
--- a/tests/boundary/mcp/pcapMcp.test.ts
+++ b/tests/boundary/mcp/pcapMcp.test.ts
@@ -8,6 +8,7 @@ import { parseEvidence } from "../../../src/domain/evidence.js";
import { ok } from "../../../src/domain/result.js";
import { createServer } from "../../../src/server/createServer.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
+import { parseMcpEvidenceBundle } from "../../fixtures/mcpEvidenceBundle.js";
const identity = { id: "pcap", name: "Packet capture analysis", version: null };
@@ -116,6 +117,12 @@ it("advertises exact valid pcap schemas and records inline evidence through MCP"
.map((part) => part.text ?? "")
.join("");
const evidence = parseEvidence(JSON.parse(text));
+ const bundle = await client.callTool({
+ name: "get_evidence_bundle",
+ arguments: {},
+ });
+ expect(bundle.isError).not.toBe(true);
+ expect(parseMcpEvidenceBundle(bundle).records).toContainEqual(evidence);
expect(evidence.normalized_result).toMatchObject({
packet_count: 50,
capture_start: "2026-10-11T14:13:40.608505Z",
diff --git a/tests/boundary/mcp/promptMcp.test.ts b/tests/boundary/mcp/promptMcp.test.ts
index 7b732a78d0..c57e0f7d35 100644
--- a/tests/boundary/mcp/promptMcp.test.ts
+++ b/tests/boundary/mcp/promptMcp.test.ts
@@ -1,5 +1,5 @@
import { ok as resultOk, err, ok } from "../../../src/domain/result.js";
-import { readFile, rm, writeFile } from "node:fs/promises";
+import { readFile, writeFile } from "node:fs/promises";
import { basename, join } from "node:path";
import {
@@ -45,17 +45,11 @@ import { observed } from "../../fixtures/analysisExecution.js";
import { serveStreamableHttp } from "../../../src/server/http/serveStreamableHttp.js";
const resources: Array<{ close(): Promise }> = [];
-const temporaryDirectories: string[] = [];
afterEach(async () => {
await Promise.allSettled(
resources.splice(0).map((resource) => resource.close()),
);
- await Promise.all(
- temporaryDirectories
- .splice(0)
- .map((directory) => rm(directory, { recursive: true, force: true })),
- );
});
describe("guided prompts over MCP", () => {
@@ -364,7 +358,6 @@ describe("guided prompt family scope", () => {
it("preserves caller-selected paths and verbatim crash signals", async () => {
const directory = await createTestTempDirectory("rea-prompt-exact-context-");
- temporaryDirectories.push(directory);
const targetPath = join(directory, "target with trailing space ");
await writeFile(targetPath, "owned prompt target", "utf8");
await expect(readFile(targetPath.trim(), "utf8")).rejects.toThrow();
@@ -493,7 +486,6 @@ describe("guided prompt completion registry", () => {
it("guided prompt completion avoids cold startup and cancels warm lookup on close", async () => {
const directory = await createTestTempDirectory("rea-prompt-warm-only-");
- temporaryDirectories.push(directory);
const target = join(directory, "target.hop");
await writeFile(target, "fixture target");
const fixture = await createWarmCompletionFixture(target);
@@ -696,7 +688,6 @@ describe("guided prompt completion lifecycle", () => {
it("refreshes wire completions across open, switch, concurrency, and close", async () => {
const directory = await createTestTempDirectory("rea-prompt-mcp-");
- temporaryDirectories.push(directory);
const first = join(directory, "first.hop");
const second = join(directory, "second.hop");
await Promise.all([writeFile(first, "first"), writeFile(second, "second")]);
diff --git a/tests/boundary/mcp/toolResult.test.ts b/tests/boundary/mcp/toolResult.test.ts
index 1ee63a03aa..95bbe231b0 100644
--- a/tests/boundary/mcp/toolResult.test.ts
+++ b/tests/boundary/mcp/toolResult.test.ts
@@ -372,7 +372,7 @@ describe("tool result projection", () => {
.details,
).not.toHaveProperty("launch_rejection");
});
- it("projects bounded private-display coordinates without raw stderr", () => {
+ it("projects private-display diagnostic fields and stderr byte count", () => {
const result = delivery.toCallToolResult(
err(
new HopperProcessError(80, {
@@ -405,6 +405,7 @@ describe("tool result projection", () => {
mount_read_only: true,
wsl: true,
strategy: "user-mount-namespace",
+ xvfb_stderr_bytes: 512,
},
},
},
diff --git a/tests/boundary/mcp/universalSliceMcp.test.ts b/tests/boundary/mcp/universalSliceMcp.test.ts
index 9fab37a6ec..1009f3c1ad 100644
--- a/tests/boundary/mcp/universalSliceMcp.test.ts
+++ b/tests/boundary/mcp/universalSliceMcp.test.ts
@@ -355,6 +355,7 @@ sliceTest(
...thinReport.auditable_metadata,
file_offset: (thinReport.auditable_metadata?.file_offset ?? 0) + offset,
});
+ expect(thinReport.rustc_commit?.hashes.length).toBeGreaterThan(0);
expect(report.rustc_commit?.hashes).toEqual(
thinReport.rustc_commit?.hashes.map((entry) => ({
...entry,
diff --git a/tests/boundary/model/modelArtifact.test.ts b/tests/boundary/model/modelArtifact.test.ts
index be6aef9dfc..f181bb6a62 100644
--- a/tests/boundary/model/modelArtifact.test.ts
+++ b/tests/boundary/model/modelArtifact.test.ts
@@ -1233,7 +1233,7 @@ it("reports a truncated safetensors header whose length resembles a pickle marke
});
});
-it("bounds expansion before allocation and distinguishes unsupported pickle, version and paths", async () => {
+it("bounds expansion before allocation and distinguishes unsupported pickle and paths", async () => {
const fixture = ggufFixture();
fixture.bytes.writeBigUInt64LE(0xffffffffffffffffn, 8);
const { provider, path, root } = await providerAt(fixture.bytes);
@@ -1245,9 +1245,6 @@ it("bounds expansion before allocation and distinguishes unsupported pickle, ver
if (pickle.ok) throw new Error("Pickle admitted");
expect(pickle.error._tag).toBe("AnalysisUnsupportedTargetError");
await writeFile(path, ggufFixture({ version: 999 }).bytes);
- const version = await provider.inspect({ path, hash: "header" });
- if (version.ok) throw new Error("Unknown version admitted");
- expect(version.error._tag).toBe("AnalysisUnsupportedTargetError");
const alias = join(root, "link");
await symlink(path, alias);
const linked = await provider.inspect({ path: alias, hash: "header" });
diff --git a/tests/boundary/process/adbVerifierCleanup.test.ts b/tests/boundary/process/adbVerifierCleanup.test.ts
index 0a8db02b3b..bfe2e4fe2c 100644
--- a/tests/boundary/process/adbVerifierCleanup.test.ts
+++ b/tests/boundary/process/adbVerifierCleanup.test.ts
@@ -21,6 +21,7 @@ afterEach(async () => {
const runVerifier = async (
settings: {
+ args?: string[];
closeFails?: boolean;
thrown?: "undefined" | "null";
removal?: "fails" | "leaves_probe";
@@ -63,7 +64,8 @@ const runVerifier = async (
await writeFile(
join(root, "dist", "composition", "adb.js"),
`import { writeFile } from "node:fs/promises";
-export const createAdbDeviceAnalysisProvider = () => ({
+import { writeFileSync } from "node:fs";
+export const createAdbDeviceAnalysisProvider = () => (writeFileSync(process.env.REA_ADB_CREATE_MARKER, "created"), {
async close() {
await writeFile(process.env.REA_ADB_CLOSE_MARKER, "closed");
if (process.env.REA_ADB_CLOSE_FAIL === "1") {
@@ -112,16 +114,18 @@ export class AdbDeviceAnalysisService {
}\n`,
);
const marker = join(root, "provider-closed");
+ const createdMarker = join(root, "provider-created");
const adbLog = join(root, "adb.log");
const run = spawnSync(
process.execPath,
- [join(root, "scripts", "verify-adb.mjs")],
+ [join(root, "scripts", "verify-adb.mjs"), ...(settings.args ?? [])],
{
encoding: "utf8",
timeout: 10_000,
env: {
...process.env,
REA_ADB_CLOSE_MARKER: marker,
+ REA_ADB_CREATE_MARKER: createdMarker,
REA_ADB_CLOSE_FAIL: settings.closeFails ? "1" : "0",
REA_FAKE_ADB: adb,
REA_FAKE_ADB_LOG: adbLog,
@@ -135,11 +139,12 @@ export class AdbDeviceAnalysisService {
},
);
const closed = await readFile(marker, "utf8").catch(() => null);
+ const created = await readFile(createdMarker, "utf8").catch(() => null);
const adbCalls = await readFile(adbLog, "utf8").then(
(text) => text.trim().split("\n"),
() => [],
);
- return { ...run, closed, adbCalls, deviceFiles: await readdir(device) };
+ return { ...run, created, closed, adbCalls, deviceFiles: await readdir(device) };
};
// The fake adb client is a POSIX shell script.
@@ -251,3 +256,18 @@ it("reports both an unexpected verifier throw and provider cleanup failure", asy
expect(result.stderr).toContain("fixture/private-root");
expect(result.closed).toBe("closed");
});
+
+
+it.each([["--install-apk", "/tmp/unrelated.apk"], ["--install-apk"]])(
+ "rejects %s before contacting the device or acquiring provider resources",
+ async (...args) => {
+ const result = await runVerifier({ args });
+
+ expect(result.status).toBe(1);
+ expect(result.stderr).toContain("APK identity and device cleanup ownership cannot be established safely");
+ expect(result.created).toBeNull();
+ expect(result.closed).toBeNull();
+ expect(result.adbCalls).toEqual([]);
+ expect(result.deviceFiles).toEqual([]);
+ },
+);
diff --git a/tests/boundary/process/applicationWorkflowVerifier.test.ts b/tests/boundary/process/applicationWorkflowVerifier.test.ts
index f420e817ca..2e10cd563d 100644
--- a/tests/boundary/process/applicationWorkflowVerifier.test.ts
+++ b/tests/boundary/process/applicationWorkflowVerifier.test.ts
@@ -1,5 +1,5 @@
import { execFile } from "node:child_process";
-import { copyFile, mkdir, rm } from "node:fs/promises";
+import { copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
@@ -107,3 +107,65 @@ describe("local application workflow verifier", () => {
});
}, 20_000);
});
+
+it.each([false, true])(
+ "joins sibling analysis cleanup after a first failure (cleanup fails: %s)",
+ async (cleanupFails) => {
+ const root = await createTestTempDirectory(
+ "rea-application-verifier-cleanup-",
+ );
+ const left = join(root, "left");
+ const right = join(root, "right");
+ const marker = join(root, "cleanup-completed");
+ const preload = join(root, "instrument.mjs");
+ await Promise.all([mkdir(left), mkdir(right)]);
+ const fake = `
+import { writeFile } from 'node:fs/promises';
+export async function analyzeJavaScriptApplicationWithOwnedScope({input_path}) {
+ if (input_path === ${JSON.stringify(left)}) throw new Error('authored first failure');
+ await new Promise(resolve => setTimeout(resolve, 200));
+ await writeFile(${JSON.stringify(marker)}, 'closed');
+ if (${JSON.stringify(cleanupFails)}) throw new Error('authored late cleanup failure');
+ return {};
+}
+`;
+ await writeFile(
+ preload,
+ `
+import { registerHooks } from 'node:module';
+registerHooks({ resolve(specifier, context, next) {
+ if (specifier === '../../lib/javascript-application-analysis.mjs' && context.parentURL?.endsWith('/scripts/verify/javascript/application-workflows.mjs'))
+ return { shortCircuit: true, url: 'data:text/javascript,' + encodeURIComponent(${JSON.stringify(fake)}) };
+ return next(specifier, context);
+}});
+`,
+ );
+ const result: unknown = await execute(
+ process.execPath,
+ [
+ "--import",
+ preload,
+ "scripts/verify/javascript/application-workflows.mjs",
+ "--left",
+ left,
+ "--right",
+ right,
+ ],
+ { timeout: 10_000 },
+ ).then(
+ () => {
+ throw new Error("Expected analysis failure");
+ },
+ (error: unknown) => error,
+ );
+ expect(await readFile(marker, "utf8")).toBe("closed");
+ expect(result).toMatchObject({
+ stderr: expect.stringContaining("authored first failure"),
+ });
+ if (cleanupFails)
+ expect(result).toMatchObject({
+ stderr: expect.stringContaining("authored late cleanup failure"),
+ });
+ },
+ 20_000,
+);
diff --git a/tests/boundary/process/bunVerifierOwnerInitialization.test.ts b/tests/boundary/process/bunVerifierOwnerInitialization.test.ts
new file mode 100644
index 0000000000..68c711ebac
--- /dev/null
+++ b/tests/boundary/process/bunVerifierOwnerInitialization.test.ts
@@ -0,0 +1,80 @@
+import { spawnSync } from "node:child_process";
+import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { expect, it } from "vitest";
+
+it.each([
+ ["initialization failure", "init", true],
+ ["initialization and root cleanup failures", "init_close", false],
+ ["command failure", "run", true],
+ ["command cleanup failure", "close", false],
+] as const)(
+ "retains the verifier root correctly after %s",
+ async (_name, failure, rootClosed) => {
+ const root = await mkdtemp(join(tmpdir(), "rea-bun-owner-test-"));
+ try {
+ await mkdir(join(root, "scripts", "lib"), { recursive: true });
+ await mkdir(join(root, "dist", "process"), { recursive: true });
+ await mkdir(join(root, "dist", "domain"), { recursive: true });
+ await writeFile(
+ join(root, "scripts", "verify-bun-standalone.mjs"),
+ await readFile(
+ new URL(
+ "../../../scripts/verify-bun-standalone.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),
+ ),
+ );
+ await writeFile(
+ join(root, "scripts", "lib", "verify-commands.mjs"),
+ `export async function createVerifierCommands() {
+ if (process.env.FAULT.startsWith("init")) throw new Error("owner load refused");
+ return { async exec() { throw new Error("command refused"); }, async close() {
+ if (process.env.FAULT === "close") throw new Error("owner close refused");
+ } };
+ }`,
+ );
+ await writeFile(
+ join(root, "dist", "process", "PrivateRuntimeRoot.js"),
+ `import { writeFile } from "node:fs/promises";
+ export class PrivateRuntimeRoot { static async create() { return {
+ path: process.env.ROOT, async close() { if (process.env.FAULT === "init_close") throw new Error("root close refused"); await writeFile(process.env.CLOSED, "closed"); }
+ }; } }`,
+ );
+ await writeFile(
+ join(root, "dist", "domain", "evidence.js"),
+ `export function parseEvidence() { throw new Error("unexpected"); }`,
+ );
+ const marker = join(root, "closed");
+ const result = spawnSync(
+ process.execPath,
+ [join(root, "scripts", "verify-bun-standalone.mjs")],
+ {
+ encoding: "utf8",
+ timeout: 10_000,
+ env: { ...process.env, ROOT: root, CLOSED: marker, FAULT: failure },
+ },
+ );
+ expect(result.status).not.toBe(0);
+ expect(result.stderr).toContain(
+ failure.startsWith("init") ? "owner load refused" : "command refused",
+ );
+ if (failure === "close")
+ expect(result.stderr).toContain("owner close refused");
+ if (failure === "init_close")
+ expect(result.stderr).toContain("root close refused");
+ expect(await readFile(marker, "utf8").catch(() => null)).toBe(
+ rootClosed ? "closed" : null,
+ );
+ } finally {
+ await rm(root, { recursive: true, force: true });
+ }
+ },
+);
diff --git a/tests/boundary/process/claudeVerifierSetupTargets.test.ts b/tests/boundary/process/claudeVerifierSetupTargets.test.ts
new file mode 100644
index 0000000000..995770f6e7
--- /dev/null
+++ b/tests/boundary/process/claudeVerifierSetupTargets.test.ts
@@ -0,0 +1,94 @@
+import { spawnSync } from "node:child_process";
+import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { expect, it } from "vitest";
+
+it.each(([
+ ["claude", "relative path", false],
+ ["claude", "sibling", false],
+ ["claude", "parent traversal", false],
+ ["claude", "owned child", true],
+ ["opencode", "relative path", false],
+ ["opencode", "sibling", false],
+ ["opencode", "parent traversal", false],
+ ["opencode", "owned child", true],
+] as const).filter(([client]) => process.platform !== "win32" || client !== "opencode"))(
+ "%s checks a %s setup-plan target before writing",
+ async (client, kind, allowed) => {
+ const state = await mkdtemp(join(tmpdir(), "rea-claude-plan-"));
+ try {
+ const commands = join(state, "commands.mjs");
+ const fixture = join(state, "fixture.mjs");
+ const hook = join(state, "hook.mjs");
+ await writeFile(
+ commands,
+ `import { writeFile } from 'node:fs/promises';
+import { isAbsolute, join, relative } from 'node:path';
+export async function createVerifierCommands(){return {
+ async exec(command,args,options={}){
+ if(command==='git')return {stdout:'',stderr:''};
+ if(args[0]==='--version')return {stdout:'fake client',stderr:''};
+ if(args.includes('setup') && args.includes('--dry-run')){
+ const client=process.env.CLIENT; const profile=client==='claude'?options.env.CLAUDE_CONFIG_DIR:options.env.OPENCODE_CONFIG_DIR; const skill=client==='claude'?join(profile,'skills','reverse-engineer-anything'):join(options.env.USERPROFILE,'.agents','skills','reverse-engineer-anything');
+ const candidate=process.env.KIND==='relative path' ? relative(process.cwd(),join(skill,'AGENTS.md')) : process.env.KIND==='sibling' ? skill+'-sibling/AGENTS.md' : process.env.KIND==='parent traversal' ? skill+'/../outside/AGENTS.md' : skill+'/AGENTS.md';
+ if (process.env.KIND==='relative path' && (candidate==='' || isAbsolute(candidate))) throw Error('Fixture expected a relative target');
+ return {stdout:JSON.stringify({status:'planned',plannedActions:[{target:join(profile,client==='claude'?'.claude.json':'opencode.jsonc')},{target:skill},{target:candidate}]}),stderr:''};
+ }
+ await writeFile(process.env.STATE+'/setup-advanced','yes'); throw Error('intentional stop before setup mutation');
+ }, async close(){} };}`,
+ );
+ await writeFile(
+ fixture,
+ `export async function createAnthropicModelFixture(){return {baseUrl:'http://127.0.0.1:1',async close(){}};} export const createOpenAiModelFixture=createAnthropicModelFixture;`,
+ );
+ await writeFile(
+ hook,
+ `import {registerHooks} from 'node:module';import{pathToFileURL}from'node:url';
+registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-'+process.env.CLIENT+'-client.mjs')){let f;if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/anthropic-model-fixture.mjs'||specifier==='./verify/clients/model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});`,
+ );
+ const result = spawnSync(
+ process.execPath,
+ [
+ "--import",
+ hook,
+ fileURLToPath(
+ new URL(
+ `../../../scripts/verify-${client}-client.mjs`,
+ import.meta.url,
+ ),
+ ),
+ ],
+ {
+ encoding: "utf8",
+ cwd: state,
+ timeout: 10_000,
+ env: {
+ ...process.env,
+ STATE: state,
+ KIND: kind,
+ CLIENT: client,
+ TMPDIR: state,
+ TMP: state,
+ TEMP: state,
+ },
+ },
+ );
+ expect(result.status).not.toBe(0);
+ const advanced = await readFile(
+ join(state, "setup-advanced"),
+ "utf8",
+ ).then(
+ () => true,
+ () => false,
+ );
+ expect(advanced).toBe(allowed);
+ expect(result.stderr).toContain(
+ allowed ? "intentional stop before setup mutation" : "AssertionError",
+ );
+ } finally {
+ await rm(state, { recursive: true, force: true });
+ }
+ },
+);
diff --git a/tests/boundary/process/clientVerifierSetupTargets.test.ts b/tests/boundary/process/clientVerifierSetupTargets.test.ts
new file mode 100644
index 0000000000..cbb0f16077
--- /dev/null
+++ b/tests/boundary/process/clientVerifierSetupTargets.test.ts
@@ -0,0 +1,99 @@
+import { spawnSync } from "node:child_process";
+import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { expect, it } from "vitest";
+
+it.each(([
+ ["gemini", "relative path", false],
+ ["gemini", "profile traversal", false],
+ ["gemini", "profile root alias", false],
+ ["gemini", "skill root alias", false],
+ ["gemini", "skill traversal", false],
+ ["gemini", "owned child", true],
+ ["copilot", "relative path", false],
+ ["copilot", "sibling", false],
+ ["copilot", "skill traversal", false],
+ ["copilot", "owned child", true],
+ ["qwen", "relative path", false],
+ ["qwen", "profile traversal", false],
+ ["qwen", "profile root alias", false],
+ ["qwen", "skill root alias", false],
+ ["qwen", "skill traversal", false],
+ ["qwen", "profile child", true],
+ ["qwen", "skill child", true],
+] as const).filter(([client]) => process.platform !== "win32" || client !== "copilot"))(
+ "%s checks %s setup-plan targets before writing",
+ async (client, kind, allowed) => {
+ const state = await mkdtemp(join(tmpdir(), "rea-client-plan-"));
+ try {
+ const commands = join(state, "commands.mjs");
+ const fixture = join(state, "fixture.mjs");
+ const hook = join(state, "hook.mjs");
+ await writeFile(
+ commands,
+ `import {writeFile} from 'node:fs/promises'; import {join} from 'node:path';
+export async function createVerifierCommands(){return {
+ async exec(command,args,options={}){
+ if(command==='git')return {stdout:'',stderr:''};
+ if(args.includes('--version'))return {stdout:'fake client',stderr:''};
+ if(args.includes('setup') && args.includes('--dry-run')){
+ const client=process.env.CLIENT; const kind=process.env.KIND;
+ const profile=client==='gemini'?options.env.GEMINI_CLI_HOME:client==='copilot'?options.env.COPILOT_HOME:options.env.QWEN_HOME;
+ const skills=join(client==='gemini'?profile:options.env.HOME,'.agents','skills');
+ const skill=join(skills,'reverse-engineer-anything');
+ const config=join(profile,client==='gemini'?'.gemini/settings.json':client==='copilot'?'mcp-config.json':'settings.json');
+ const candidate=kind==='relative path'?'relative/AGENTS.md':kind==='profile root alias'?profile+'/child/..':kind==='skill root alias'?skills+'/child/..':kind==='profile traversal'?profile+'/../outside/AGENTS.md':kind==='skill traversal'?(client==='copilot'?skill:skills)+'/../outside/AGENTS.md':kind==='sibling'?skill+'-sibling/AGENTS.md':kind==='profile child'?config:join(skill,'SKILL.md');
+ const selectedSkill=(kind==='skill traversal'||kind==='skill root alias')&&client==='gemini'?candidate:join(skill,'SKILL.md');
+ const actions=client==='qwen'?[{target:candidate}]:[{target:config},{target:client==='copilot'?skill:selectedSkill},{target:candidate}];
+ return {stdout:JSON.stringify({status:'planned',plannedActions:actions}),stderr:''};
+ }
+ await writeFile(process.env.STATE+'/setup-advanced','yes'); throw Error('intentional stop before setup mutation');
+ }, async close(){} };}`,
+ );
+ await writeFile(
+ fixture,
+ `export async function createOpenAiModelFixture(){return {baseUrl:'http://127.0.0.1:1',async close(){}};}`,
+ );
+ await writeFile(
+ hook,
+ `import {registerHooks} from 'node:module';import{pathToFileURL}from'node:url';
+registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-'+process.env.CLIENT+'-client.mjs')){let f;if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});`,
+ );
+ const script = fileURLToPath(
+ new URL(
+ `../../../scripts/verify-${client}-client.mjs`,
+ import.meta.url,
+ ),
+ );
+ const result = spawnSync(process.execPath, ["--import", hook, script], {
+ encoding: "utf8",
+ timeout: 10_000,
+ env: {
+ ...process.env,
+ STATE: state,
+ CLIENT: client,
+ KIND: kind,
+ TMPDIR: state,
+ TMP: state,
+ TEMP: state,
+ },
+ });
+ expect(result.status).not.toBe(0);
+ const advanced = await readFile(
+ join(state, "setup-advanced"),
+ "utf8",
+ ).then(
+ () => true,
+ () => false,
+ );
+ expect(advanced).toBe(allowed);
+ expect(result.stderr).toContain(
+ allowed ? "intentional stop before setup mutation" : "AssertionError",
+ );
+ } finally {
+ await rm(state, { recursive: true, force: true });
+ }
+ },
+);
diff --git a/tests/boundary/process/commandcodeVerifierSkillBody.test.ts b/tests/boundary/process/commandcodeVerifierSkillBody.test.ts
new file mode 100644
index 0000000000..3df9272e11
--- /dev/null
+++ b/tests/boundary/process/commandcodeVerifierSkillBody.test.ts
@@ -0,0 +1,138 @@
+import { spawnSync } from "node:child_process";
+import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { expect, it } from "vitest";
+
+const posix = it.skipIf(process.platform === "win32");
+posix.each([
+ ["empty", false],
+ ["empty body", false],
+ ["wrong role", false],
+ ["wrong id", false],
+ ["missing body", false],
+ ["complete", true],
+] as const)(
+ "requires CommandCode skill proof for %s",
+ async (mode, allowed) => {
+ const state = await mkdtemp(join(tmpdir(), "rea-commandcode-skill-"));
+ try {
+ const account = join(state, "account");
+ await mkdir(account);
+ await writeFile(
+ join(account, ".rea-client-verification"),
+ "Disposable REA client verification account\n",
+ );
+ const commands = String.raw`
+import { mkdir, readFile, writeFile } from "node:fs/promises";
+import { join } from "node:path";
+import { TOOL_CONTRACTS } from REPLACE_CONTRACTS;
+
+let setup = 0;
+export async function createVerifierCommands() {
+ return {
+ async exec(command, args, options = {}) {
+ if (command === "git") return { stdout: "", stderr: "" };
+ if (args.includes("--version")) return { stdout: "fake", stderr: "" };
+ const account = options.env.USERPROFILE;
+ const profile = join(account, ".commandcode");
+ const config = join(profile, "mcp.json");
+ const skill = join(account, ".agents", "skills", "reverse-engineer-anything");
+ if (args.includes("setup") && args.includes("--dry-run")) {
+ return { stdout: JSON.stringify({ status: "planned", plannedActions: [{ target: config }, { target: skill }] }), stderr: "" };
+ }
+ if (args.includes("setup")) {
+ if (setup++ === 0) {
+ await writeFile(config + ".rea.backup", await readFile(config));
+ await mkdir(skill, { recursive: true });
+ const frontmatter = "---\nname: reverse-engineer-anything\n---\n";
+ const body = 'Complete "authored" instructions\nKeep a \\ literal\n';
+ await writeFile(join(skill, "SKILL.md"), process.env.MODE === "empty" ? "" : frontmatter + (process.env.MODE === "empty body" ? "" : body));
+ return { stdout: JSON.stringify({ status: "ready" }), stderr: "" };
+ }
+ return { stdout: JSON.stringify({ appliedActions: [] }), stderr: "" };
+ }
+ if (args.includes("doctor")) return { stdout: JSON.stringify({ healthy: true }), stderr: "" };
+ const tools = [
+ { name: "search_tools" },
+ { name: "activate_skill", parameters: { properties: { name: { enum: ["reverse-engineer-anything"] } } } },
+ ];
+ const system = { role: "system", content: TOOL_CONTRACTS.map((t) => "mcp__rea__" + t.name).join(" ") };
+ const first = await globalThis.fakeRequest({ body: { messages: [system] }, tools });
+ const body = 'Complete "authored" instructions\nKeep a \\ literal';
+ const response = {
+ role: process.env.MODE === "wrong role" ? "user" : "tool",
+ tool_call_id: process.env.MODE === "wrong id" ? "wrong" : first.tool_calls[0].id,
+ content: process.env.MODE === "missing body" ? "partial" : body,
+ };
+ const second = await globalThis.fakeRequest({ body: { messages: [system, response] }, tools });
+ await writeFile(process.env.STATE + "/observed.json", JSON.stringify({ first, second }));
+ throw Error("intentional stop before client output");
+ },
+ async close() {},
+ };
+}
+`.replace(
+ "REPLACE_CONTRACTS",
+ JSON.stringify(
+ new URL("../../../dist/contracts/toolContracts.js", import.meta.url).href,
+ ),
+ );
+ await writeFile(join(state, "commands.mjs"), commands);
+ await writeFile(
+ join(state, "fixture.mjs"),
+ "export async function createOpenAiModelFixture({onRequest}){globalThis.fakeRequest=onRequest;return {baseUrl:'http://127.0.0.1:1',async close(){}};}\n",
+ );
+ await writeFile(
+ join(state, "hook.mjs"),
+ "import{registerHooks}from'node:module';import{pathToFileURL}from'node:url';registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-commandcode-client.mjs')){let f;if(specifier==='node:os')f='os.mjs';if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});\n",
+ );
+ await writeFile(
+ join(state, "os.mjs"),
+ "export * from 'node:os';export function homedir(){return process.env.REA_VERIFY_COMMANDCODE_ACCOUNT_HOME;}\n",
+ );
+ const script = fileURLToPath(
+ new URL(
+ "../../../scripts/verify-commandcode-client.mjs",
+ import.meta.url,
+ ),
+ );
+ const result = spawnSync(
+ process.execPath,
+ ["--import", join(state, "hook.mjs"), script],
+ {
+ encoding: "utf8",
+ timeout: 10_000,
+ env: {
+ ...process.env,
+ STATE: state,
+ MODE: mode,
+ REA_VERIFY_COMMANDCODE_ACCOUNT_HOME: account,
+ },
+ },
+ );
+ expect(result.status).not.toBe(0);
+ const observed = await readFile(
+ join(state, "observed.json"),
+ "utf8",
+ ).then(JSON.parse, () => null);
+ expect(observed !== null).toBe(allowed);
+ if (allowed)
+ expect(observed.second.tool_calls[0].function.name).toBe(
+ "search_tools",
+ );
+ expect(result.stderr).toContain(
+ allowed
+ ? "intentional stop before client output"
+ : mode === "empty"
+ ? "Installed skill must have authored frontmatter"
+ : mode === "empty body"
+ ? "Installed skill body must not be empty"
+ : "The model must receive the complete activated skill body",
+ );
+ } finally {
+ await rm(state, { recursive: true, force: true });
+ }
+ },
+);
diff --git a/tests/boundary/process/deepseekVerifierSkillBody.test.ts b/tests/boundary/process/deepseekVerifierSkillBody.test.ts
new file mode 100644
index 0000000000..f20d1c0e25
--- /dev/null
+++ b/tests/boundary/process/deepseekVerifierSkillBody.test.ts
@@ -0,0 +1,82 @@
+import { spawnSync } from "node:child_process";
+import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { expect, it } from "vitest";
+
+const posix = it.skipIf(process.platform === "win32");
+posix.each([
+ ["empty", false],
+ ["outside wrapper", false],
+ ["closed wrapper", false],
+ ["closed early", false],
+ ["inside resources", false],
+ ["split messages", false],
+ ["complete", true],
+ ["complete escaped", true],
+ ["complete CRLF", true],
+ ["complete tags", true],
+] as const)(
+ "requires actual skill body when model receives %s content",
+ async (body, allowed) => {
+ const state = await mkdtemp(join(tmpdir(), "rea-deepseek-skill-"));
+ try {
+ const commands =
+ "import {mkdir,readFile,writeFile} from 'node:fs/promises'; import {join} from 'node:path'; import {TOOL_CONTRACTS} from REPLACE_CONTRACTS;\nlet setup=0;\nexport async function createVerifierCommands(){return {async exec(command,args,options={}){\n if(command==='git')return {stdout:'',stderr:''}; if(args.includes('--version'))return {stdout:'fake',stderr:''};\n const profile=options.env.DSH_HOME;const skill=join(options.env.HOME,'.agents','skills','reverse-engineer-anything');const config=join(profile,'cordis.patch.yml');\n if(args.includes('setup')&&args.includes('--dry-run'))return {stdout:JSON.stringify({status:'planned',plannedActions:[{target:config},{target:skill}]}),stderr:''};\n if(args.includes('setup')){if(setup++===0){await writeFile(config+'.rea.backup',await readFile(config));await mkdir(skill,{recursive:true});await writeFile(join(skill,'SKILL.md'),('---\\nname: reverse-engineer-anything\\n---\\n'+(process.env.BODY==='complete tags'?'Literal and \\n':'')+'Essential \"authored\" instructions\\nKeep a \\\\ literal\\n').replaceAll('\\n',process.env.BODY==='complete CRLF'?'\\r\\n':'\\n'));return {stdout:JSON.stringify({status:'ready'}),stderr:''};}return {stdout:JSON.stringify({appliedActions:[]}),stderr:''};}\n if(args.includes('doctor'))return {stdout:JSON.stringify({healthy:true}),stderr:''};\n const tools=[...TOOL_CONTRACTS.map(t=>({name:'mcp__rea__'+t.name,parameters:{type:'object',properties:{v:{type:'string',pattern:'^x$'}}}})),{name:'skill'}];\n const first=await globalThis.fakeRequest({body:{messages:[]},tools,requestIndex:1});\n const body=((process.env.BODY==='complete tags'?'Literal and \\n':'')+'Essential \"authored\" instructions\\nKeep a \\\\ literal').replaceAll('\\n',process.env.BODY==='complete CRLF'?'\\r\\n':'\\n');\n const escapedSkill=skill.replaceAll('&','&').replaceAll('<','<').replaceAll('>','>'); const wrap='\\n\\n'+escapedSkill+(process.env.BODY==='closed early'?'':'')+(process.env.BODY==='inside resources'?body:'')+'\\n\\n\\n';\n const payload=wrap+(process.env.BODY==='closed wrapper'?'':'')+((process.env.BODY.startsWith('complete')||process.env.BODY==='closed wrapper'||process.env.BODY==='closed early')?'\\n'+body+'\\n\\n':'')+''+(process.env.BODY==='outside wrapper'?body:'');\n const messages=[{role:'tool',content:payload},...(process.env.BODY==='split messages'?[{role:'tool',content:body}]:[])];\n const second=await globalThis.fakeRequest({body:{messages},tools,requestIndex:2});\n await writeFile(process.env.STATE+'/observed.json',JSON.stringify({first,second,payload}));throw Error('intentional stop after empty-skill request');\n },async close(){}};}\n".replace(
+ "REPLACE_CONTRACTS",
+ JSON.stringify(
+ new URL("../../../dist/contracts/toolContracts.js", import.meta.url).href,
+ ),
+ );
+ await writeFile(join(state, "commands.mjs"), commands);
+ await writeFile(
+ join(state, "fixture.mjs"),
+ "export async function createOpenAiModelFixture({onRequest}){globalThis.fakeRequest=onRequest;return {baseUrl:'http://127.0.0.1:1',async close(){}};}\n",
+ );
+ await writeFile(
+ join(state, "hook.mjs"),
+ "import{registerHooks}from'node:module';import{pathToFileURL}from'node:url';registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-deepseek-client.mjs')){let f;if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});\n",
+ );
+ const script = fileURLToPath(
+ new URL("../../../scripts/verify-deepseek-client.mjs", import.meta.url),
+ );
+ const temporary =
+ body === "complete escaped" ? join(state, "dir &") : state;
+ if (temporary !== state) await mkdir(temporary);
+ const result = spawnSync(
+ process.execPath,
+ ["--import", join(state, "hook.mjs"), script],
+ {
+ encoding: "utf8",
+ timeout: 10_000,
+ env: {
+ ...process.env,
+ STATE: state,
+ BODY: body,
+ TMPDIR: temporary,
+ TMP: temporary,
+ TEMP: temporary,
+ },
+ },
+ );
+ expect(result.status).not.toBe(0);
+ const observed = await readFile(
+ join(state, "observed.json"),
+ "utf8",
+ ).then(JSON.parse, () => null);
+ expect(observed !== null).toBe(allowed);
+ if (allowed)
+ expect(observed.second.tool_calls[0].function.name).toBe(
+ "mcp__rea__analyze_javascript_application",
+ );
+ expect(result.stderr).toContain(
+ allowed
+ ? "intentional stop after empty-skill request"
+ : "Harness must load the installed skill before analysis",
+ );
+ } finally {
+ await rm(state, { recursive: true, force: true });
+ }
+ },
+);
diff --git a/tests/boundary/process/flutterVerifierDefaultAbi.test.ts b/tests/boundary/process/flutterVerifierDefaultAbi.test.ts
new file mode 100644
index 0000000000..bf8a1394c8
--- /dev/null
+++ b/tests/boundary/process/flutterVerifierDefaultAbi.test.ts
@@ -0,0 +1,28 @@
+import { execFile } from "node:child_process";
+import { resolve } from "node:path";
+import { promisify } from "node:util";
+import { expect, it } from "vitest";
+
+const execute = promisify(execFile);
+
+it("requires the default Flutter AOT result to belong to the identified ABI set", async () => {
+ const invoke = (kind: string) =>
+ execute(
+ process.execPath,
+ [
+ "--import",
+ resolve("tests/fixtures/flutterVerifierPreload.mjs"),
+ "scripts/verify-flutter.mjs",
+ "--apk",
+ "/tmp/fixture.apk",
+ ],
+ { env: { ...process.env, REA_FLUTTER_PROBE: kind }, timeout: 10_000 },
+ );
+ await expect(invoke("wrong")).rejects.toMatchObject({
+ stderr: expect.stringContaining(
+ "Default AOT selection must be one of the identified ABIs",
+ ),
+ });
+ const result = await invoke("correct");
+ expect(result.stdout).toContain("all asserted Flutter CLI/MCP checks passed");
+});
diff --git a/tests/boundary/process/fridaVerifier.test.ts b/tests/boundary/process/fridaVerifier.test.ts
new file mode 100644
index 0000000000..e55fb24641
--- /dev/null
+++ b/tests/boundary/process/fridaVerifier.test.ts
@@ -0,0 +1,70 @@
+import { execFile } from "node:child_process";
+import { writeFile } from "node:fs/promises";
+import { join } from "node:path";
+import { promisify } from "node:util";
+import { expect, it } from "vitest";
+import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
+
+const execute = promisify(execFile);
+
+it("loads the Frida verifier help without starting instrumentation", async () => {
+ const result = await execute(process.execPath, [
+ "scripts/verify-frida.mjs",
+ "--help",
+ ]);
+ expect(result.stdout).toContain(
+ "Without flags, verifies a local Node.js process",
+ );
+});
+
+it("requires marker identity to match the selected target", async () => {
+ const root = await createTestTempDirectory("rea-frida-verifier-");
+ const preload = join(root, "provider.mjs");
+ await writeFile(
+ preload,
+ `
+import { registerHooks } from 'node:module';
+const service = \`
+export class FridaInstrumentationService {
+ async listProcesses() { return { ok: true, value: { processes: [{ pid: 41, name: 'selected' }] } }; }
+ async instrument() {
+ const pid = process.env.REA_PROBE_KIND === 'missing' ? undefined : process.env.REA_PROBE_KIND === 'correct' ? 41 : 42;
+ return { ok: true, value: { cleanupError: null, evidence: { normalized_result: { pid, messages: [{ type: 'send', payload: { rea_frida_verification: 'ok', pid } }] } } } };
+ }
+}\`;
+const manager = \`export class FridaInstrumentationManager { async closeAll() {} }\`;
+registerHooks({ resolve(specifier, context, next) {
+ if (context.parentURL?.endsWith('/scripts/verify-frida.mjs')) {
+ if (specifier.endsWith('/FridaInstrumentationService.js')) return { shortCircuit: true, url: 'data:text/javascript,' + encodeURIComponent(service) };
+ if (specifier.endsWith('/FridaInstrumentationManager.js')) return { shortCircuit: true, url: 'data:text/javascript,' + encodeURIComponent(manager) };
+ }
+ return next(specifier, context);
+}});
+`,
+ );
+ const invoke = (kind: string, remote: boolean) =>
+ execute(
+ process.execPath,
+ [
+ "--import",
+ preload,
+ "scripts/verify-frida.mjs",
+ ...(remote ? ["--address", "127.0.0.1:27042", "--pid", "41"] : []),
+ ],
+ { env: { ...process.env, REA_PROBE_KIND: kind }, timeout: 10_000 },
+ );
+ for (const [kind, remote, message] of [
+ ["missing", false, "Frida returned no valid target PID"],
+ ["wrong", true, "Frida observed a different target PID"],
+ ] as const) {
+ await expect(invoke(kind, remote)).rejects.toMatchObject({
+ stderr: expect.stringContaining(message),
+ });
+ }
+ const result = await invoke("correct", true);
+ expect(JSON.parse(result.stdout)).toMatchObject({
+ ok: true,
+ target_pid: 41,
+ script_message_observed: true,
+ });
+});
diff --git a/tests/boundary/process/geminiVerifierSkillBody.test.ts b/tests/boundary/process/geminiVerifierSkillBody.test.ts
new file mode 100644
index 0000000000..46d1d53d9c
--- /dev/null
+++ b/tests/boundary/process/geminiVerifierSkillBody.test.ts
@@ -0,0 +1,76 @@
+import { spawnSync } from "node:child_process";
+import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { expect, it } from "vitest";
+
+it.each([
+ ["empty", false],
+ ["outside wrapper", false],
+ ["inside resources", false],
+ ["closed early", false],
+ ["split messages", false],
+ ["complete", true],
+ ["complete CRLF", true],
+ ["complete tags", true],
+] as const)(
+ "requires actual Gemini skill body in %s response",
+ async (body, allowed) => {
+ const state = await mkdtemp(join(tmpdir(), "rea-gemini-skill-"));
+ try {
+ const commands =
+ "import {mkdir,readFile,writeFile} from 'node:fs/promises';import {join} from 'node:path';import {TOOL_CONTRACTS} from REPLACE_CONTRACTS;\nlet setup=0;export async function createVerifierCommands(){return {async exec(command,args,options={}){\nif(command==='git')return {stdout:'',stderr:''};if(args.includes('--version'))return {stdout:'fake',stderr:''};\nconst profile=options.env.GEMINI_CLI_HOME;const config=join(profile,'.gemini','settings.json');const skill=join(profile,'.agents','skills','reverse-engineer-anything');\nif(args.includes('setup')&&args.includes('--dry-run'))return {stdout:JSON.stringify({status:'planned',plannedActions:[{target:config},{target:join(skill,'SKILL.md')}]}),stderr:''};\nif(args.includes('setup')){if(setup++===0){await writeFile(config+'.rea.backup',await readFile(config));await mkdir(skill,{recursive:true});await writeFile(join(skill,'SKILL.md'),('---\\nname: reverse-engineer-anything\\n---\\n'+(process.env.BODY==='complete tags'?'literal and \\n':'')+'Essential \"instructions\"\\nKeep a \\\\ literal\\n').replaceAll('\\n',process.env.BODY==='complete CRLF'?'\\r\\n':'\\n'));return {stdout:JSON.stringify({status:'ready'}),stderr:''};}return {stdout:JSON.stringify({appliedActions:[]}),stderr:''};}\nif(args.includes('doctor'))return {stdout:JSON.stringify({healthy:true}),stderr:''};\nconst tools=[...TOOL_CONTRACTS.map(t=>({name:'rea__'+t.name,parametersJsonSchema:{type:'object'}})),{name:'activate_skill'}];\nconst first=await globalThis.fakeRequest({body:{contents:[]},tools});\nconst body=((process.env.BODY==='complete tags'?'literal and \\n':'')+'Essential \"instructions\"\\nKeep a \\\\ literal').replaceAll('\\n',process.env.BODY==='complete CRLF'?'\\r\\n':'\\n');\nconst valid=(process.env.BODY.startsWith('complete')||process.env.BODY==='closed early');\nconst instructions=valid?' \\n '+body+'\\n \\n\\n':'';\nconst output='\\n'+instructions+' \\n '+skill+(process.env.BODY==='closed early'?'':'')+(process.env.BODY==='inside resources'?body:'')+'\\n \\n'+(process.env.BODY==='outside wrapper'?body:'');\nconst responses=[{functionResponse:{name:'activate_skill',response:{output}}},...(process.env.BODY==='split messages'?[{functionResponse:{name:'activate_skill',response:{output:body}}}]:[])];\nconst second=await globalThis.fakeRequest({body:{contents:[{parts:responses}]},tools});const payload=output;\nawait writeFile(process.env.STATE+'/observed.json',JSON.stringify({first,second,payload}));throw Error('intentional stop before client mutation');},async close(){}};}\n".replace(
+ "REPLACE_CONTRACTS",
+ JSON.stringify(
+ new URL("../../../dist/contracts/toolContracts.js", import.meta.url).href,
+ ),
+ );
+ await writeFile(join(state, "commands.mjs"), commands);
+ await writeFile(
+ join(state, "fixture.mjs"),
+ "export async function createGeminiModelFixture({onRequest}){globalThis.fakeRequest=onRequest;return {baseUrl:'http://127.0.0.1:1',async close(){}};}\n",
+ );
+ await writeFile(
+ join(state, "hook.mjs"),
+ "import{registerHooks}from'node:module';import{pathToFileURL}from'node:url';registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-gemini-client.mjs')){let f;if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/gemini-model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});\n",
+ );
+ const script = fileURLToPath(
+ new URL("../../../scripts/verify-gemini-client.mjs", import.meta.url),
+ );
+ const result = spawnSync(
+ process.execPath,
+ ["--import", join(state, "hook.mjs"), script],
+ {
+ encoding: "utf8",
+ timeout: 10_000,
+ env: {
+ ...process.env,
+ STATE: state,
+ BODY: body,
+ TMPDIR: state,
+ TMP: state,
+ TEMP: state,
+ },
+ },
+ );
+ expect(result.status).not.toBe(0);
+ const observed = await readFile(
+ join(state, "observed.json"),
+ "utf8",
+ ).then(JSON.parse, () => null);
+ expect(observed !== null).toBe(allowed);
+ if (allowed)
+ expect(observed.second[0].functionCall.name).toBe(
+ "rea__analyze_javascript_application",
+ );
+ expect(result.stderr).toContain(
+ allowed
+ ? "intentional stop before client mutation"
+ : "Gemini must load the installed personal REA skill",
+ );
+ } finally {
+ await rm(state, { recursive: true, force: true });
+ }
+ },
+);
diff --git a/tests/boundary/process/ghidraJavaLifecycle.test.ts b/tests/boundary/process/ghidraJavaLifecycle.test.ts
index ccf8c53233..d2527d8433 100644
--- a/tests/boundary/process/ghidraJavaLifecycle.test.ts
+++ b/tests/boundary/process/ghidraJavaLifecycle.test.ts
@@ -176,6 +176,9 @@ posix.each([true, false])(
code: "version_unresolved",
cancellation: { reason },
});
+ if (result.error._tag !== "GhidraJavaProbeFailure")
+ throw new Error("Expected the invalid Java report");
+ expect(result.error.cancellation?.reason).toBe(reason);
expect(Object.keys(result.error)).not.toContain("cancellation");
expect(() => JSON.stringify(result.error)).not.toThrow();
}
diff --git a/tests/boundary/process/ghidraVerifierAssertions.test.ts b/tests/boundary/process/ghidraVerifierAssertions.test.ts
index bd6554bf7e..6f8aebe956 100644
--- a/tests/boundary/process/ghidraVerifierAssertions.test.ts
+++ b/tests/boundary/process/ghidraVerifierAssertions.test.ts
@@ -66,3 +66,48 @@ processTest(
expect(result.exitCode, result.stderr).toBe(0);
},
);
+
+processTest(
+ "Ghidra cleanup rejects unreadable paths and accepts only confirmed absence",
+ async ({ processes }) => {
+ const assertionsUrl = new URL(
+ "../../../scripts/verify-real-ghidra-assertions.mjs",
+ import.meta.url,
+ ).href;
+ const source = `
+ import assert from "node:assert/strict";
+ import { createRequire, syncBuiltinESMExports } from "node:module";
+ const fs = createRequire(import.meta.url)("node:fs/promises");
+ const { assertCleanup } = await import(${JSON.stringify(assertionsUrl)});
+ const root = await fs.mkdtemp((await import("node:os")).tmpdir() + "/rea-ghidra-cleanup-test-");
+ try {
+ const dangling = root + "/dangling";
+ if (process.platform !== "win32") {
+ await fs.symlink(root + "/missing-target", dangling);
+ await assert.rejects(assertCleanup({ runtime_root: dangling }), /Ghidra cleanup left runtime_root/);
+ }
+ } finally { await fs.rm(root, { recursive: true, force: true }); }
+ let result = "exists";
+ fs.lstat = async () => {
+ if (result === "exists") return;
+ const error = new Error(result);
+ error.code = result;
+ throw error;
+ };
+ syncBuiltinESMExports();
+ const coordinates = { runtime_root: "/owned-runtime" };
+ await assert.rejects(assertCleanup(coordinates), /Ghidra cleanup left runtime_root/);
+ result = "ENOENT";
+ await assertCleanup(coordinates);
+ result = "EACCES";
+ await assert.rejects(assertCleanup(coordinates), { code: "EACCES" });
+ `;
+ const result = await processes.run(
+ process.execPath,
+ ["--input-type=module", "--eval", source],
+ { timeoutMs: 10_000 },
+ );
+ expect(result.signal, result.stderr).toBeNull();
+ expect(result.exitCode, result.stderr).toBe(0);
+ },
+);
diff --git a/tests/boundary/process/javascriptVerifierBoundedEvidence.test.ts b/tests/boundary/process/javascriptVerifierBoundedEvidence.test.ts
new file mode 100644
index 0000000000..1fe3fb7320
--- /dev/null
+++ b/tests/boundary/process/javascriptVerifierBoundedEvidence.test.ts
@@ -0,0 +1,150 @@
+import { execFile } from "node:child_process";
+import { realpath, truncate, writeFile } from "node:fs/promises";
+import { join } from "node:path";
+import { promisify } from "node:util";
+import { expect, it } from "vitest";
+
+import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
+import {
+ applicationFixture,
+ electronRuntimeEvidence,
+ SOURCE,
+} from "../../fixtures/javascriptRuntimeReconciliation.js";
+
+const execute = promisify(execFile);
+
+it.each(["once", "always", "physical"] as const)(
+ "retries the exact Evidence descriptor after close denial: %s",
+ async (denial) => {
+ const root = await createTestTempDirectory("rea-verifier-evidence-close-");
+ const evidence = join(root, "evidence.json");
+ const preload = join(root, "instrument.mjs");
+ const application = await applicationFixture();
+ await writeFile(
+ evidence,
+ JSON.stringify(electronRuntimeEvidence(application, SOURCE)),
+ );
+ const selected = await realpath(evidence);
+ await writeFile(
+ preload,
+ `
+import fs from 'node:fs';
+import { syncBuiltinESMExports } from 'node:module';
+const open = fs.promises.open;
+let attempts = 0;
+fs.promises.open = async function(path, ...args) {
+ const handle = await open.call(this, path, ...args);
+ if (String(path) === ${JSON.stringify(selected)}) {
+ const close = handle.close.bind(handle);
+ if (${JSON.stringify(denial)} === 'physical')
+ handle.read = async () => { throw new Error('authored Evidence read failure'); };
+ handle.close = async () => {
+ attempts++;
+ if (${JSON.stringify(denial)} === 'always' || attempts === 1)
+ throw new Error('authored Evidence close denial');
+ return close();
+ };
+ }
+ return handle;
+};
+syncBuiltinESMExports();
+process.on('exit', () => fs.writeSync(2, 'Evidence close attempts: ' + attempts + '\\n'));
+`,
+ );
+ const invocation = execute(
+ process.execPath,
+ [
+ "--import",
+ preload,
+ "scripts/verify/javascript/runtime-observation.mjs",
+ "--application",
+ application,
+ "--runtime-evidence",
+ evidence,
+ ],
+ { timeout: 20_000 },
+ );
+ if (denial === "once") {
+ const result = await invocation;
+ expect(JSON.parse(result.stdout)).toMatchObject({ verified: true });
+ expect(result.stderr).toContain("Evidence close attempts: 2");
+ expect(result.stderr).not.toContain("authored Evidence close denial");
+ return;
+ }
+ const result: unknown = await invocation.then(
+ () => {
+ throw new Error("Expected Evidence failure");
+ },
+ (error: unknown) => error,
+ );
+ expect(result).toMatchObject({
+ stderr: expect.stringContaining("Evidence close attempts: 2"),
+ });
+ if (
+ !(result instanceof Error) ||
+ !("stderr" in result) ||
+ typeof result.stderr !== "string"
+ )
+ throw new Error("Missing verifier diagnostics");
+ if (denial === "always") {
+ expect(result.stderr).toContain("authored Evidence close denial");
+ expect(result.stderr).toContain(
+ "AggregateError: Verifier cleanup failed",
+ );
+ expect(result.stderr).toContain("cleanupLeases");
+ } else {
+ expect(result.stderr).toContain("authored Evidence read failure");
+ expect(result.stderr).not.toContain("authored Evidence close denial");
+ expect(result.stderr).not.toContain(
+ "AggregateError: Verifier cleanup failed",
+ );
+ }
+ },
+ 30_000,
+);
+
+it("refuses oversized Evidence before a whole-file read", async () => {
+ const root = await createTestTempDirectory("rea-verifier-evidence-limit-");
+ const evidence = join(root, "evidence.json");
+ const preload = join(root, "instrument.mjs");
+ await writeFile(evidence, "");
+ await truncate(evidence, 64 * 1024 * 1024 + 1);
+ const selected = await realpath(evidence);
+ await writeFile(
+ preload,
+ `
+import fs from 'node:fs';
+import { syncBuiltinESMExports } from 'node:module';
+const readFile = fs.promises.readFile;
+fs.promises.readFile = function(path, ...args) {
+ if (String(path) === ${JSON.stringify(selected)}) throw new Error('oversized whole-file read');
+ return readFile.call(this, path, ...args);
+};
+syncBuiltinESMExports();
+`,
+ );
+ const application = await applicationFixture();
+ const result = await execute(
+ process.execPath,
+ [
+ "--import",
+ preload,
+ "scripts/verify/javascript/runtime-observation.mjs",
+ "--application",
+ application,
+ "--runtime-evidence",
+ evidence,
+ ],
+ { timeout: 20_000 },
+ ).then(
+ () => {
+ throw new Error("Expected oversized Evidence rejection");
+ },
+ (error: unknown) => error,
+ );
+ expect(result).toMatchObject({
+ stderr: expect.stringContaining(
+ `Runtime Evidence exceeds 64 MiB: ${evidence}`,
+ ),
+ });
+}, 30_000);
diff --git a/tests/boundary/process/jebVerifier.test.ts b/tests/boundary/process/jebVerifier.test.ts
new file mode 100644
index 0000000000..b13038c95a
--- /dev/null
+++ b/tests/boundary/process/jebVerifier.test.ts
@@ -0,0 +1,65 @@
+import { execFile } from "node:child_process";
+import { writeFile } from "node:fs/promises";
+import { join } from "node:path";
+import { promisify } from "node:util";
+import { expect, it } from "vitest";
+import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
+
+const execute = promisify(execFile);
+
+it("reports a decompile marker only when a nonempty requested marker was observed", async () => {
+ const root = await createTestTempDirectory("rea-jeb-verifier-");
+ const preload = join(root, "provider.mjs");
+ await writeFile(
+ preload,
+ `
+import { registerHooks } from 'node:module';
+const service = \`
+export class JebAnalysisService {
+ async execute(name) {
+ if (name === 'inspect_jeb_client') return { ok: true, value: { normalized_result: { engine: { version: 'fixture', gui_client: false, endpoint: 'fixture' } } } };
+ if (name === 'open_jeb_project') return { ok: false, error: { message: 'not available' } };
+ if (name === 'list_jeb_units') return { ok: true, value: { normalized_result: { units: [{}] } } };
+ if (name === 'decompile_jeb_item') return { ok: true, value: { normalized_result: { text: process.env.REA_JEB_PROBE_TEXT ?? '' } } };
+ throw new Error('unexpected operation');
+ }
+}\`;
+const provider = \`export const createJebAnalysisProvider = () => ({ close: async () => {} });\`;
+registerHooks({ resolve(specifier, context, next) {
+ if (context.parentURL?.endsWith('/scripts/verify-jeb.mjs')) {
+ if (specifier.endsWith('/JebAnalysisService.js')) return { shortCircuit: true, url: 'data:text/javascript,' + encodeURIComponent(service) };
+ if (specifier.endsWith('/composition/jeb.js')) return { shortCircuit: true, url: 'data:text/javascript,' + encodeURIComponent(provider) };
+ }
+ return next(specifier, context);
+}});
+`,
+ );
+ const invoke = (text: string, marker?: string) =>
+ execute(
+ process.execPath,
+ [
+ "--import",
+ preload,
+ "scripts/verify-jeb.mjs",
+ "--item-address",
+ "Lx;->x()V",
+ ...(marker === undefined ? [] : ["--marker", marker]),
+ ],
+ { env: { ...process.env, REA_JEB_PROBE_TEXT: text }, timeout: 10_000 },
+ );
+ await expect(invoke("", undefined)).rejects.toMatchObject({
+ stderr: expect.stringContaining("Decompiled pseudo-code was empty"),
+ });
+ await expect(invoke("void x() {}", "missing")).rejects.toMatchObject({
+ stderr: expect.stringContaining("did not contain the fixture marker"),
+ });
+ await expect(invoke("void x() {}", "")).rejects.toMatchObject({
+ stderr: expect.stringContaining("--marker must not be empty"),
+ });
+ expect(
+ JSON.parse((await invoke("void x() {}", undefined)).stdout),
+ ).toMatchObject({ ok: true, decompiled_marker_observed: false });
+ expect(JSON.parse((await invoke("void x() {}", "x()")).stdout)).toMatchObject(
+ { ok: true, decompiled_marker_observed: true },
+ );
+});
diff --git a/tests/boundary/process/qwenVerifierSkillBody.test.ts b/tests/boundary/process/qwenVerifierSkillBody.test.ts
new file mode 100644
index 0000000000..e0d2ab6b99
--- /dev/null
+++ b/tests/boundary/process/qwenVerifierSkillBody.test.ts
@@ -0,0 +1,58 @@
+import { spawnSync } from "node:child_process";
+import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { expect, it } from "vitest";
+
+it.each([
+ ["no skill tool", false],
+ ["user mention", false],
+ ["wrong id", false],
+ ["missing body", false],
+ ["split", false],
+ ["complete", true],
+ ["CRLF", true],
+] as const)("binds Qwen skill evidence for %s", async (mode, loaded) => {
+ const state = await mkdtemp(join(tmpdir(), "rea-qwen-skill-"));
+ try {
+ await writeFile(
+ join(state, "commands.mjs"),
+ "import {mkdir,readFile,writeFile} from 'node:fs/promises';import {join} from 'node:path';\nexport async function createVerifierCommands(){return {async exec(command,args,options={}){\n if(args.includes('--version'))return {stdout:'fake',stderr:''};\n const profile=options.env.QWEN_HOME;const config=join(profile,'settings.json');\n if(args.includes('setup')&&args.includes('--dry-run'))return {stdout:JSON.stringify({plannedActions:[{target:config}]}),stderr:''};\n if(args.includes('setup')){\n const original=await readFile(config,'utf8');await writeFile(config+'.rea.backup',original);\n const value=JSON.parse(original);value.mcpServers.rea={command:'/fake/rea',args:['mcp']};await writeFile(config,JSON.stringify(value));\n const skill=join(options.env.HOME,'.agents','skills','reverse-engineer-anything');await mkdir(skill,{recursive:true});\n const source='---\\nname: reverse-engineer-anything\\n---\\nQwen \"authored\" body\\nKeep a \\\\ literal\\n';\n await writeFile(join(skill,'SKILL.md'),process.env.MODE==='CRLF'?source.replaceAll('\\n','\\r\\n'):source);\n return {stdout:'{}',stderr:''};\n }\n if(args.includes('doctor'))return {stdout:'{}',stderr:''};\n const skill=join(options.env.HOME,'.agents','skills','reverse-engineer-anything');\n const content='Base directory for this skill: '+skill+'\\nImportant: ALWAYS resolve absolute paths from this base directory when working with skills.\\n\\nQwen \"authored\" body\\nKeep a \\\\ literal\\n';\n const tools=[...(process.env.MODE==='no skill tool'?[]:[{name:'skill'}]),{name:'mcp__rea__analyze_javascript_application'}];\n const first=await globalThis.fakeRequest({body:{messages:[]},tools,requestIndex:1});const callId=first.tool_calls[0].id;\n let messages=(process.env.MODE==='user mention'||process.env.MODE==='no skill tool')?[{role:'user',content:'Unrelated '+skill}]:[{role:'tool',tool_call_id:process.env.MODE==='wrong id'?'other':callId,content:process.env.MODE==='missing body'?'Base directory for this skill: '+skill:content}];\n if(process.env.MODE==='split')messages=[{role:'tool',tool_call_id:callId,content:'Base directory for this skill: '+skill},{role:'tool',tool_call_id:'other',content}];\n const second=await globalThis.fakeRequest({body:{messages},tools,requestIndex:2});await writeFile(process.env.STATE+'/observed.json',JSON.stringify({first,second,messages}));throw Error('intentional stop before client output');\n},async close(){}};}\n",
+ );
+ await writeFile(
+ join(state, "fixture.mjs"),
+ "export async function createOpenAiModelFixture({onRequest}){globalThis.fakeRequest=onRequest;return {baseUrl:'http://127.0.0.1:1',async close(){}};}\n",
+ );
+ await writeFile(
+ join(state, "hook.mjs"),
+ "import {registerHooks}from'node:module';import{pathToFileURL}from'node:url';registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-qwen-client.mjs')){let f;if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});\n",
+ );
+ const script = fileURLToPath(
+ new URL("../../../scripts/verify-qwen-client.mjs", import.meta.url),
+ );
+ const result = spawnSync(
+ process.execPath,
+ ["--import", join(state, "hook.mjs"), script],
+ {
+ encoding: "utf8",
+ timeout: 10_000,
+ env: {
+ ...process.env,
+ STATE: state,
+ MODE: mode,
+ TMPDIR: state,
+ TMP: state,
+ TEMP: state,
+ },
+ },
+ );
+ expect(result.status).not.toBe(0);
+ expect(result.stderr).toContain("intentional stop before client output");
+ const receipt = JSON.parse(result.stdout.trim().split("\n")[0] ?? "");
+ expect(receipt.selectedSkillLoaded).toBe(loaded);
+ expect(receipt.passed).toBe(false);
+ } finally {
+ await rm(state, { recursive: true, force: true });
+ }
+});
diff --git a/tests/boundary/providers/RizinDebugSessionCoverage.part1.test.ts b/tests/boundary/providers/RizinDebugSessionCoverage.part1.test.ts
index b167e484e5..c5080464f8 100644
--- a/tests/boundary/providers/RizinDebugSessionCoverage.part1.test.ts
+++ b/tests/boundary/providers/RizinDebugSessionCoverage.part1.test.ts
@@ -159,28 +159,6 @@ it.skipIf(process.platform === "win32")(
},
);
-it.skipIf(process.platform === "win32")(
- "rejects a non-TTY path before spawning Rizin",
- async () => {
- let spawned = false;
- const manager = createManager(
- { REA_RIZIN_COMMAND: "injected-rizin" },
- {
- spawnProcess: async () => {
- spawned = true;
- throw new Error("must not spawn with an invalid TTY");
- },
- },
- );
- const result = await manager.start({
- path: "/tmp/not-a-tty-target",
- inferior_tty: "/dev/null",
- });
- expect(result.ok).toBe(false);
- expect(spawned).toBe(false);
- },
-);
-
it.skipIf(process.platform === "win32")(
"closeAll drains concurrent startups and blocks later admission",
async () => {
diff --git a/tests/boundary/providers/auxiliaryDeclarations.test.ts b/tests/boundary/providers/auxiliaryDeclarations.test.ts
index 15e42fc32a..c28137f5af 100644
--- a/tests/boundary/providers/auxiliaryDeclarations.test.ts
+++ b/tests/boundary/providers/auxiliaryDeclarations.test.ts
@@ -7,7 +7,13 @@ import { parseBinaryTarget } from "../../../src/application/BinaryTargetResolver
it("keeps declaration discovery and client creation lazy and independently owned", async () => {
const target = await parseBinaryTarget(process.execPath);
if (!target.ok) throw target.error;
- for (const declaration of auxiliaryAnalysisProviderDeclarations({})) {
+ const declarations = auxiliaryAnalysisProviderDeclarations({});
+ expect(declarations.map(({ identity }) => identity.id).sort()).toEqual([
+ "native-macos",
+ "rea-artifact-graph",
+ "rea-dotnet-static",
+ ]);
+ for (const declaration of declarations) {
let loads = 0;
const provider = new LazyAnalysisProvider({
...declaration,
diff --git a/tests/boundary/providers/cutterBridgeProducer.test.ts b/tests/boundary/providers/cutterBridgeProducer.test.ts
index 721ffc05a1..c81cf904b3 100644
--- a/tests/boundary/providers/cutterBridgeProducer.test.ts
+++ b/tests/boundary/providers/cutterBridgeProducer.test.ts
@@ -239,10 +239,10 @@ it("retains failed receipt acknowledgements and retries before another command",
bridge.client.execute({
sessionId: bridge.session.session_id,
expectedGeneration: bridge.session.document_generation,
- command: "iI",
+ command: "fixture-receipt-count",
json: false,
}),
- ).resolves.toMatchObject({ executionState: "complete" });
+ ).resolves.toMatchObject({ executionState: "complete", output: "0" });
} finally {
await bridge.close();
}
@@ -263,10 +263,10 @@ it("retains a receipt when an ACK reply omits its acknowledgement field", async
bridge.client.execute({
sessionId: bridge.session.session_id,
expectedGeneration: bridge.session.document_generation,
- command: "iI",
+ command: "fixture-receipt-count",
json: false,
}),
- ).resolves.toMatchObject({ executionState: "complete" });
+ ).resolves.toMatchObject({ executionState: "complete", output: "0" });
} finally {
await bridge.close();
}
diff --git a/tests/boundary/providers/jeb/failureEnvelopes.test.ts b/tests/boundary/providers/jeb/failureEnvelopes.test.ts
index ca64c0e9d9..00342bc52c 100644
--- a/tests/boundary/providers/jeb/failureEnvelopes.test.ts
+++ b/tests/boundary/providers/jeb/failureEnvelopes.test.ts
@@ -170,7 +170,6 @@ it.each(
expect(producer.calls).toEqual([
{ name: "open_project", arguments: { file_path: input.path } },
]);
- expect(projected.error.code).not.toBe("unsupported_target");
} finally {
try {
await client.close();
diff --git a/tests/boundary/providers/kuna/kunaCommandFailures.test.ts b/tests/boundary/providers/kuna/kunaCommandFailures.test.ts
index c480f52a77..ffea9aa070 100644
--- a/tests/boundary/providers/kuna/kunaCommandFailures.test.ts
+++ b/tests/boundary/providers/kuna/kunaCommandFailures.test.ts
@@ -1,4 +1,4 @@
-import { expect, it as test } from "vitest";
+import { expect, it as test, vi } from "vitest";
import { projectAnalysisError } from "../../../../src/domain/analysisErrorProjection.js";
import { inspectKunaInstallationOwned as inspectKunaInstallation } from "./kunaResourceScope.js";
@@ -147,3 +147,98 @@ it("says why Kuna cannot answer instead of a generic unavailable message", async
expect(await client.close()).toEqual({ ok: true, value: null });
}
});
+
+it("preserves a caller reason when a target command is already cancelled", async () => {
+ const { kuna, target, cacheRoot } = await session(
+ "rea-kuna-command-preabort-",
+ );
+ const installed = await inspectKunaInstallation({
+ REA_KUNA_COMMAND: kuna,
+ REA_KUNA_CACHE_DIR: cacheRoot,
+ });
+ if (!installed.ok) throw new Error(installed.error.reason);
+ const controller = new AbortController();
+ const reason = { caller: "before target command admission" };
+ controller.abort(reason);
+ const callsBefore = await fakeKunaCalls(kuna);
+ const releaseRun = vi.fn();
+ const commands = new KunaTargetCommands(target, {
+ signal: controller.signal,
+ });
+ try {
+ const result = await commands.run({
+ installation: installed.value,
+ operation: "list_procedures",
+ arguments: (input) => ["functions", input, "--json"],
+ deadline: { setting: "REA_KUNA_TIMEOUT_MS", ms: 10_000 },
+ outputBytes: 100,
+ signal: controller.signal,
+ releaseRun,
+ });
+ if (result.ok) throw new Error("Expected pre-aborted command to cancel");
+ expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBe(reason);
+ expect(releaseRun).toHaveBeenCalledOnce();
+ expect(await fakeKunaCalls(kuna)).toEqual(callsBefore);
+ } finally {
+ expect(await commands.close()).toEqual({ ok: true, value: null });
+ }
+});
+
+it("preserves the lifetime reason when workspace preparation is already cancelled", async () => {
+ const { kuna, target } = await session("rea-kuna-prepare-preabort-");
+ const controller = new AbortController();
+ const reason = { caller: "before workspace preparation" };
+ controller.abort(reason);
+ const callsBefore = await fakeKunaCalls(kuna);
+ const commands = new KunaTargetCommands(target, {
+ signal: controller.signal,
+ });
+ try {
+ const result = await commands.prepare();
+ if (result.ok) throw new Error("Expected cancelled preparation");
+ expect(result.error).toMatchObject({
+ _tag: "AnalysisCancelledError",
+ operation: "kuna:workspace",
+ });
+ expect(result.error.cause).toBe(reason);
+ expect(await fakeKunaCalls(kuna)).toEqual(callsBefore);
+ } finally {
+ expect(await commands.close()).toEqual({ ok: true, value: null });
+ }
+});
+
+it("does not invent a caller cause when closed without cancellation", async () => {
+ const { kuna, target, cacheRoot } = await session("rea-kuna-command-closed-");
+ const installed = await inspectKunaInstallation({
+ REA_KUNA_COMMAND: kuna,
+ REA_KUNA_CACHE_DIR: cacheRoot,
+ });
+ if (!installed.ok) throw new Error(installed.error.reason);
+ const controller = new AbortController();
+ const callsBefore = await fakeKunaCalls(kuna);
+ const releaseRun = vi.fn();
+ const commands = new KunaTargetCommands(target, {
+ signal: controller.signal,
+ });
+ expect(await commands.close()).toEqual({ ok: true, value: null });
+ const preparation = await commands.prepare();
+ if (preparation.ok) throw new Error("Expected closed preparation to cancel");
+ expect(preparation.error._tag).toBe("AnalysisCancelledError");
+ expect(preparation.error.cause).toBeUndefined();
+ const result = await commands.run({
+ installation: installed.value,
+ operation: "list_procedures",
+ arguments: (input) => ["functions", input, "--json"],
+ deadline: { setting: "REA_KUNA_TIMEOUT_MS", ms: 10_000 },
+ outputBytes: 100,
+ signal: controller.signal,
+ releaseRun,
+ });
+ if (result.ok) throw new Error("Expected closed command to cancel");
+ expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBeUndefined();
+ expect(releaseRun).toHaveBeenCalledOnce();
+ expect(await fakeKunaCalls(kuna)).toEqual(callsBefore);
+ expect(await commands.close()).toEqual({ ok: true, value: null });
+});
diff --git a/tests/boundary/providers/kuna/kunaProjectCache.test.ts b/tests/boundary/providers/kuna/kunaProjectCache.test.ts
index 3b949c8024..311a97ea8d 100644
--- a/tests/boundary/providers/kuna/kunaProjectCache.test.ts
+++ b/tests/boundary/providers/kuna/kunaProjectCache.test.ts
@@ -705,6 +705,28 @@ it("shares one Kuna run between concurrent requests for one export", async () =>
expect(await callsOf(kuna, "decompile-project")).toHaveLength(1);
});
+it("preserves a pre-aborted caller reason without launching an export", async () => {
+ const { kuna, installation, cache, target } = await fixture(
+ "rea-kuna-preabort-reason-",
+ );
+ const input = await target("program");
+ const controller = new AbortController();
+ const reason = { caller: "before admission" };
+ controller.abort(reason);
+ const callsBefore = await fakeKunaCalls(kuna);
+ const result = await cache.build({
+ installation,
+ ...input,
+ signal: controller.signal,
+ });
+ if (result.ok)
+ throw new Error("Expected pre-aborted cache request to cancel");
+ expect(result.error._tag).toBe("AnalysisCancelledError");
+ expect(result.error.cause).toBe(reason);
+ expect(await fakeKunaCalls(kuna)).toEqual(callsBefore);
+ expect(await cache.close()).toEqual({ ok: true, value: null });
+});
+
it("stops the run only when every waiting request is cancelled", async () => {
const { kuna, installation, cacheRoot, cache, target } = await fixture(
"rea-kuna-cancel-",
@@ -727,23 +749,31 @@ it("stops the run only when every waiting request is cancelled", async () => {
await expect.poll(() => callsOf(kuna, "decompile-project")).toHaveLength(1);
const pid = (await callsOf(kuna, "decompile-project"))[0]?.pid ?? 0;
- firstCaller.abort();
- expect(await first).toMatchObject({
+ const firstReason = { caller: "first waiter" };
+ firstCaller.abort(firstReason);
+ const firstResult = await first;
+ expect(firstResult).toMatchObject({
ok: false,
error: { _tag: "AnalysisCancelledError" },
});
+ if (firstResult.ok) throw new Error("Expected first waiter cancellation");
// The other request still owns the run.
expect(processGone(pid)).toBe(false);
- secondCaller.abort();
- expect(await second).toMatchObject({
+ const secondReason = { caller: "last waiter" };
+ secondCaller.abort(secondReason);
+ const secondResult = await second;
+ expect(secondResult).toMatchObject({
ok: false,
error: { _tag: "AnalysisCancelledError" },
});
+ if (secondResult.ok) throw new Error("Expected last waiter cancellation");
expect(await cache.close()).toEqual({ ok: true, value: null });
expect(processGone(pid)).toBe(true);
expect(await entries(cacheRoot, "staging")).toEqual([]);
expect(await entries(cacheRoot, "projects")).toEqual([]);
+ expect(firstResult.error.cause).toBe(firstReason);
+ expect(secondResult.error.cause).toBe(secondReason);
});
it("applies one deadline to the inventory and the export together", async () => {
diff --git a/tests/boundary/providers/managed/managedHashCancellation.test.ts b/tests/boundary/providers/managed/managedHashCancellation.test.ts
index d917a6e6a2..2681f7a48d 100644
--- a/tests/boundary/providers/managed/managedHashCancellation.test.ts
+++ b/tests/boundary/providers/managed/managedHashCancellation.test.ts
@@ -94,6 +94,7 @@ it.each([
code: "cleanup_incomplete",
details: { diagnostics: { primary_error: { code: "cancelled" } } },
});
+ expect(cancelled.error.cleanupPrimary?.cause).toBe(reason);
expect(cancelledHandle?.fd).toBeGreaterThanOrEqual(0);
const readsBeforeRetry = readCount;
const blocked = await client.execute("inspect_managed_members", {});
diff --git a/tests/boundary/providers/managed/managedMemberComparisonFromMetadata.test.ts b/tests/boundary/providers/managed/managedMemberComparisonFromMetadata.test.ts
index 51154ab80d..d703a0b58f 100644
--- a/tests/boundary/providers/managed/managedMemberComparisonFromMetadata.test.ts
+++ b/tests/boundary/providers/managed/managedMemberComparisonFromMetadata.test.ts
@@ -36,8 +36,12 @@ it("selects namespace-bearing nested declarations from parsed type facts and com
expect(selected.result.methods).toHaveLength(2);
expect(selected.result.fields).toHaveLength(2);
const comparison = compareManagedMembers(selected, selected);
+ expect(comparison.methods).toHaveLength(2);
+ expect(comparison.fields).toHaveLength(2);
expect(
- comparison.methods.every(({ match }) => match.status === "matched"),
+ [...comparison.methods, ...comparison.fields].every(
+ ({ match }) => match.status === "matched",
+ ),
).toBe(true);
expect(comparison.summary).toMatchObject({ added: 0, removed: 0 });
expect(
@@ -2569,62 +2573,43 @@ describe("managed member comparison of ownerless members", () => {
}
});
- it("keeps a resolved copy out of the declared round when an ownerless competitor is on the left, as main does", () => {
- const base = inspect(buildManagedPeFixture(), "/tmp/ownerless-left.dll");
- const [method] = base.result.methods;
- if (method === undefined) throw new Error("Expected a fixture method");
- const ownerless = {
- ...method,
- declaring_type: null,
- declaring_type_token: null,
- };
- // The left holds the resolved Foo and an ownerless Foo with the same CIL
- // and signature; the right holds only the resolved Foo. The ownerless
- // Foo's owner may be the resolved one, so the three stay ambiguous.
- const withOwnerless = {
- ...base,
- result: { ...base.result, methods: [method, ownerless], fields: [] },
- };
- const resolvedOnly = {
- ...base,
- result: { ...base.result, methods: [method], fields: [] },
- };
+ it.each(["left", "right"] as const)(
+ "keeps a resolved copy out of the declared round when an ownerless competitor is on the %s",
+ (side) => {
+ const base = inspect(
+ buildManagedPeFixture(),
+ `/tmp/ownerless-${side}.dll`,
+ );
+ const [method] = base.result.methods;
+ if (method === undefined) throw new Error("Expected a fixture method");
+ const ownerless = {
+ ...method,
+ declaring_type: null,
+ declaring_type_token: null,
+ };
+ // The ownerless Foo may belong to the same type as the resolved Foo,
+ // so both comparison directions must leave the three members ambiguous.
+ const withOwnerless = {
+ ...base,
+ result: { ...base.result, methods: [method, ownerless], fields: [] },
+ };
+ const resolvedOnly = {
+ ...base,
+ result: { ...base.result, methods: [method], fields: [] },
+ };
- const result = compareManagedMembers(withOwnerless, resolvedOnly);
+ const result =
+ side === "left"
+ ? compareManagedMembers(withOwnerless, resolvedOnly)
+ : compareManagedMembers(resolvedOnly, withOwnerless);
- expect(result.matching.ambiguous).toBe(1);
- expect(
- result.methods.filter(({ match }) => match.status === "matched"),
- ).toEqual([]);
- expect(result.summary).toMatchObject({ added: 0, removed: 0 });
- });
-
- it("keeps a resolved copy out of the declared round when an ownerless competitor is on the right, as main does", () => {
- const base = inspect(buildManagedPeFixture(), "/tmp/ownerless-right.dll");
- const [method] = base.result.methods;
- if (method === undefined) throw new Error("Expected a fixture method");
- const ownerless = {
- ...method,
- declaring_type: null,
- declaring_type_token: null,
- };
- const withOwnerless = {
- ...base,
- result: { ...base.result, methods: [method, ownerless], fields: [] },
- };
- const resolvedOnly = {
- ...base,
- result: { ...base.result, methods: [method], fields: [] },
- };
-
- const result = compareManagedMembers(resolvedOnly, withOwnerless);
-
- expect(result.matching.ambiguous).toBe(1);
- expect(
- result.methods.filter(({ match }) => match.status === "matched"),
- ).toEqual([]);
- expect(result.summary).toMatchObject({ added: 0, removed: 0 });
- });
+ expect(result.matching.ambiguous).toBe(1);
+ expect(
+ result.methods.filter(({ match }) => match.status === "matched"),
+ ).toEqual([]);
+ expect(result.summary).toMatchObject({ added: 0, removed: 0 });
+ },
+ );
it("keeps an ownerless method ambiguous beside a resolved method of the same shape", () => {
const base = inspect(buildManagedPeFixture(), "/tmp/ownerless-shape.dll");
diff --git a/tests/boundary/providers/managed/managedStaticProvider.test.ts b/tests/boundary/providers/managed/managedStaticProvider.test.ts
index 6e0dd5b9b0..81eecd7970 100644
--- a/tests/boundary/providers/managed/managedStaticProvider.test.ts
+++ b/tests/boundary/providers/managed/managedStaticProvider.test.ts
@@ -27,11 +27,13 @@ import * as boundedFileBytes from "../../../../src/process/BoundedFileBytes.js";
import { primaryAnalysisError } from "../../../../src/domain/analysisErrorBase.js";
it.each(
- [false, true].flatMap((warm) =>
- [false, true].flatMap((changed) =>
- [false, true].map((failedClose) => ({ warm, changed, failedClose })),
- ),
- ),
+ [false, true]
+ .flatMap((warm) =>
+ [false, true].flatMap((changed) =>
+ [false, true].map((failedClose) => ({ warm, changed, failedClose })),
+ ),
+ )
+ .filter(({ changed, failedClose }) => changed || failedClose),
)(
"preserves selected managed identity through finalization (cached=$warm, changed=$changed, failedClose=$failedClose)",
async ({ warm, changed, failedClose }) => {
@@ -291,8 +293,9 @@ describe("managed static completed snapshot cancellation", () => {
kind: "file-snapshot-hash",
path,
bytes: bytes.length,
- sha256: parsed.value.sha256,
+ sha256: createHash("sha256").update(bytes).digest("hex"),
};
+ expect(parsed.value.sha256).toBe(observation.sha256);
expect(result.error.partialObservation).toEqual(observation);
expect(projectAnalysisError(result.error)).toMatchObject({
code: "cancelled",
@@ -302,6 +305,9 @@ describe("managed static completed snapshot cancellation", () => {
expect(owners.every((owner) => owner.handle.fd === -1)).toBe(true);
if (retryClose) expect(owners[0]).toBe(owners[1]);
expect(await client.close()).toEqual({ ok: true, value: null });
+ expect(result.error.partialObservation).toEqual(observation);
+ expect(result.error.cleanupIncomplete).toBe(false);
+ expect(owners.every((owner) => owner.handle.fd === -1)).toBe(true);
} finally {
close.mockRestore();
await client.close();
@@ -529,15 +535,11 @@ describe("managed static provider path boundary", () => {
field_accesses: [expect.objectContaining({ field_name: "counter" })],
});
const memberResult = asManagedMemberResult(members.value);
- expect(members.value.locations).toEqual(
- expect.arrayContaining(
- memberResult.methods.flatMap((method) =>
- method.body.file_offset === null
- ? []
- : [{ kind: "file-offset", offset: method.body.file_offset }],
- ),
- ),
- );
+ expect(memberResult.methods[0]?.body.file_offset).toBe(0x0a00);
+ expect(members.value.locations).toContainEqual({
+ kind: "file-offset",
+ offset: 0x0a00,
+ });
const boundaries = await client.execute(
"inspect_managed_native_boundaries",
diff --git a/tests/composition/idaProvider.test.ts b/tests/composition/idaProvider.test.ts
index 2c6c08f934..eda322f510 100644
--- a/tests/composition/idaProvider.test.ts
+++ b/tests/composition/idaProvider.test.ts
@@ -236,6 +236,8 @@ describe("IDA provider selection cancellation", () => {
ok: false,
error: { _tag: "AnalysisCancelledError", cause: cancellationReason },
});
+ if (replacement.ok) throw new Error("Expected cancellation");
+ expect(replacement.error.cause).toBe(cancellationReason);
expect(session.activeTarget()?.sha256).toBe(first.target.sha256);
expect(
(await session.execute("procedure_pseudo_code", { procedure: "main" }))
@@ -272,6 +274,8 @@ describe("IDA provider selection cancellation", () => {
ok: false,
error: { _tag: "AnalysisCancelledError", cause: reason },
});
+ if (profile.ok) throw new Error("Expected cancellation");
+ expect(profile.error.cause).toBe(reason);
expect(runCalls).toBe(0);
});
});
diff --git a/tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts b/tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
index 0e936b0624..200361bec9 100644
--- a/tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
+++ b/tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
@@ -19,6 +19,17 @@ describe("real Windows Ghidra workflow trust boundary", () => {
repository_dispatch: { types: ["real-ghidra-windows"] },
});
expect(workflow.permissions).toEqual({ contents: "read" });
+ for (const name of ["native-artifact", "verify"]) {
+ const job = workflow.jobs[name];
+ expect(job.if).toBe("github.ref == 'refs/heads/main'");
+ const checkouts = job.steps.filter(
+ (step: { uses?: string }) => step.uses?.startsWith("actions/checkout@"),
+ );
+ expect(checkouts).toHaveLength(1);
+ expect(checkouts[0].uses).toMatch(/^actions\/checkout@[0-9a-f]{40}$/);
+ expect(checkouts[0].with?.ref).toBeUndefined();
+ expect(checkouts[0].with?.repository).toBeUndefined();
+ }
expect(workflow).toMatchObject({
jobs: {
verify: {
diff --git a/tests/conformance/providers/managed/managedNativeVerification.test.ts b/tests/conformance/providers/managed/managedNativeVerification.test.ts
index 60835973c1..b4e25f1b25 100644
--- a/tests/conformance/providers/managed/managedNativeVerification.test.ts
+++ b/tests/conformance/providers/managed/managedNativeVerification.test.ts
@@ -913,21 +913,6 @@ it("retains every observed native candidate", () => {
expect(result.pinvoke_imports[0]?.candidates).toHaveLength(2);
});
-it("wraps verification in derived workflow Evidence", () => {
- const evidence = executeManagedNativeBoundaries(exampleInput());
-
- if (!evidence.ok) throw evidence.error;
- expect(evidence.value.evidence).toMatchObject({
- operation: "verify_managed_native_boundaries",
- provider: { id: "rea-dotnet-workflows" },
- confidence: "inferred",
- authority: "analyst-inference",
- normalized_result: {
- summary: { verified: 1 },
- },
- });
- expect(evidence.value.evidence.evidence_links).toHaveLength(2);
-});
describe("managed/native verification result algebra", () => {
it("rejects states without their required native match", () => {
diff --git a/tests/evaluation/evidenceJsonPreadmissionRule.test.ts b/tests/evaluation/evidenceJsonPreadmissionRule.test.ts
index fc435b3713..850a927070 100644
--- a/tests/evaluation/evidenceJsonPreadmissionRule.test.ts
+++ b/tests/evaluation/evidenceJsonPreadmissionRule.test.ts
@@ -216,14 +216,6 @@ new RuleTester({
createEvidence(target, provider, { rawResult: jsonValueSchema.parse(raw) });`,
"rawResult",
),
- invalid(
- "aliased imports retain their owner",
- `
- import { createEvidence as record } from "../domain/evidence.js";
- import { jsonValueSchema as json } from "../domain/jsonValue.js";
- record(target, provider, { result: json.parse(input) });`,
- "result",
- ),
invalid(
"namespace members retain their owner",
`
diff --git a/tests/evaluation/model-evals/agentEvaluationReport.test.ts b/tests/evaluation/model-evals/agentEvaluationReport.test.ts
index 8d2f8375cd..9c4566c058 100644
--- a/tests/evaluation/model-evals/agentEvaluationReport.test.ts
+++ b/tests/evaluation/model-evals/agentEvaluationReport.test.ts
@@ -131,12 +131,6 @@ describe("scoped factual report", () => {
epistemicCuePresent: false,
}),
).toBe(false);
- expect(
- agentEvaluationPassed({
- ...routingSuccess,
- factualCorrectness: "failed",
- }),
- ).toBe(false);
});
it("reports assessed failures separately from unassessed scenarios", () => {
diff --git a/tests/evaluation/testDiscovery.test.ts b/tests/evaluation/testDiscovery.test.ts
index d4ef905089..70996f2236 100644
--- a/tests/evaluation/testDiscovery.test.ts
+++ b/tests/evaluation/testDiscovery.test.ts
@@ -15,7 +15,23 @@ describe("test discovery migration guard", () => {
[{ file: resolve(root, first), projectName: "domain" }],
root,
),
- ).toEqual({ missing: [], unexpected: [], duplicates: [], discovered: 1 });
+ ).toEqual({
+ missing: [],
+ unexpected: [],
+ duplicates: [],
+ wrongProjects: [],
+ discovered: 1,
+ });
+ });
+
+ it("reports a discovered test in the wrong project", () => {
+ expect(
+ compareTestDiscovery(
+ [first],
+ [{ file: first, projectName: "cli-boundary" }],
+ root,
+ ).wrongProjects,
+ ).toEqual([{ file: first, expected: "domain", actual: "cli-boundary" }]);
});
it("reports a new provider test omitted by the current project globs", () => {
diff --git a/tests/fixtures/android/jniElf.ts b/tests/fixtures/android/jniElf.ts
index b6cdaef0f9..f76686da5b 100644
--- a/tests/fixtures/android/jniElf.ts
+++ b/tests/fixtures/android/jniElf.ts
@@ -328,5 +328,5 @@ export const jniElfFixture = (
},
writer,
);
- return { bytes, base, word, functions, slots, relocationSize };
+ return { bytes, base, word };
};
diff --git a/tests/fixtures/binaryDiagnostics/appleIps.ts b/tests/fixtures/binaryDiagnostics/appleIps.ts
index 4bb557fee7..61bb9eb4ac 100644
--- a/tests/fixtures/binaryDiagnostics/appleIps.ts
+++ b/tests/fixtures/binaryDiagnostics/appleIps.ts
@@ -1,4 +1,4 @@
-export interface AppleIpsFixtureOptions {
+interface AppleIpsFixtureOptions {
readonly bugType?: string;
readonly procName?: string;
readonly uuid?: string;
diff --git a/tests/fixtures/binaryDiagnostics/nativeExports.ts b/tests/fixtures/binaryDiagnostics/nativeExports.ts
index ea6a1a644b..c055b48cf8 100644
--- a/tests/fixtures/binaryDiagnostics/nativeExports.ts
+++ b/tests/fixtures/binaryDiagnostics/nativeExports.ts
@@ -1,5 +1,5 @@
/** One PE export-address-table slot: code RVA, forwarder text, or unused. */
-export type PeFixtureFunction =
+type PeFixtureFunction =
| { readonly rva: number }
| { readonly forwarder: string }
| null;
@@ -132,7 +132,7 @@ export const peRepeatedExportNamesImage = (
};
/** One `.dynsym` entry; `version` is its raw `.gnu.version` half-word. */
-export interface ElfFixtureSymbol {
+interface ElfFixtureSymbol {
readonly name: string;
readonly binding?: number;
readonly type?: number;
@@ -145,7 +145,7 @@ export interface ElfFixtureSymbol {
readonly nameOffset?: number;
}
-export interface ElfFixtureVersionRequirement {
+interface ElfFixtureVersionRequirement {
readonly index: number;
readonly name: string;
}
diff --git a/tests/fixtures/binaryDiagnostics/peImports.ts b/tests/fixtures/binaryDiagnostics/peImports.ts
index bdbdce47b2..5c775b72d4 100644
--- a/tests/fixtures/binaryDiagnostics/peImports.ts
+++ b/tests/fixtures/binaryDiagnostics/peImports.ts
@@ -8,11 +8,11 @@ const SPLIT_GAP_BYTES = 0x200;
export const peImportFixtureOffset = (rva: number): number =>
rva - SECTION_RVA + SECTION_OFFSET;
-export type PeImportFixtureFunction =
+type PeImportFixtureFunction =
| { readonly name: string; readonly hint?: number }
| { readonly ordinal: number };
-export interface PeImportFixtureDll {
+interface PeImportFixtureDll {
readonly name: string;
readonly functions: readonly PeImportFixtureFunction[];
}
diff --git a/tests/fixtures/cutter_bridge_protocol_test.py b/tests/fixtures/cutter_bridge_protocol_test.py
index fd605f7cdd..957731cf18 100644
--- a/tests/fixtures/cutter_bridge_protocol_test.py
+++ b/tests/fixtures/cutter_bridge_protocol_test.py
@@ -143,6 +143,7 @@ class ServeDispatcher:
elif request.get("kind") == "ack":
if self.malformed_next_ack:
self.malformed_next_ack = False
+ self.hide_receipts_after_ack_failure = True
reply.update({"ok": True, "session_id": request["session_id"]})
request["_event"].set()
return
@@ -198,7 +199,11 @@ class ServeDispatcher:
else:
reply.update({
"ok": True,
- "output": 'round-trip: 雪 ☃️ quote=" slash=\\\\ line=\\n tab=\\t',
+ "output": (
+ str(len(self.completed_commands))
+ if request.get("command") == "fixture-receipt-count"
+ else 'round-trip: 雪 ☃️ quote=" slash=\\\\ line=\\n tab=\\t'
+ ),
"current_file": self.current_file,
"document_generation": self.generation,
"cutter_version": self.cutter_version,
@@ -601,14 +606,17 @@ class ProtocolProducerTest(unittest.TestCase):
dispatcher.completed_commands = {}
dispatcher._receipt_lock = threading.Lock()
dispatcher._refresh_document_identity = lambda: None
- bridge.cutter.cmd = lambda command: f"output:{command}"
+ commands = []
+ bridge.cutter.cmd = lambda command: commands.append(command) or f"output:{command}"
- def handle(value):
+ def handle(value, cancelled=False):
request = {
**value,
"_event": threading.Event(),
"_cancelled": threading.Event(),
}
+ if cancelled:
+ request["_cancelled"].set()
reply = {}
bridge._RequestDispatcher._handle(dispatcher, request, reply)
self.assertTrue(request["_event"].is_set())
@@ -616,6 +624,15 @@ class ProtocolProducerTest(unittest.TestCase):
request_a = "4b18ce4d-bf31-456e-ae31-e8c547b2f9db"
request_b = "8ca93d11-107d-41ed-8b40-31dd53cd26a6"
+ request_cancelled = "9c8074cf-4906-4cc1-ac92-3fca3d305f8f"
+ cancelled = handle({
+ "kind": "command",
+ "request_id": request_cancelled,
+ "expected_generation": 4,
+ "command": "cancelled",
+ }, cancelled=True)
+ self.assertEqual(cancelled["error"], "request-cancelled-before-execution")
+ self.assertEqual(cancelled["execution_state"], "not_started")
for request_id, command in ((request_a, "A"), (request_b, "B")):
result = handle({
"kind": "command",
@@ -624,7 +641,14 @@ class ProtocolProducerTest(unittest.TestCase):
"command": command,
})
self.assertTrue(result["ok"])
+ self.assertEqual(commands, ["A", "B"])
+ status = handle({"kind": "status"})
+ self.assertEqual(
+ {receipt["request_id"]: receipt["execution_state"] for receipt in status["completed_commands"]},
+ {request_cancelled: "not_started", request_a: "complete", request_b: "complete"},
+ )
+ self.assertTrue(handle({"kind": "ack", "request_id": request_cancelled})["acknowledged"])
status = handle({"kind": "status"})
self.assertEqual(
{receipt["request_id"] for receipt in status["completed_commands"]},
@@ -757,23 +781,12 @@ class ProtocolProducerTest(unittest.TestCase):
class RequestFrameLimitTest(unittest.TestCase):
def test_payload_limit_excludes_the_line_terminator(self):
- class BufferedSocket:
- def __init__(self, data):
- self.data = data
-
- def settimeout(self, _timeout):
- pass
-
- def recv(self, count):
- part, self.data = self.data[:count], self.data[count:]
- return part
-
payload = b"{}" + b" " * (bridge.MAX_FRAME_BYTES - 2)
self.assertEqual(
- bridge._BridgeServer._receive_frame(BufferedSocket(payload + b"\n")), {}
+ bridge._BridgeServer._receive_frame(_BufferedSocket(payload + b"\n")), {}
)
with self.assertRaisesRegex(ValueError, "frame-limit-exceeded"):
- bridge._BridgeServer._receive_frame(BufferedSocket(payload + b" " + b"\n"))
+ bridge._BridgeServer._receive_frame(_BufferedSocket(payload + b" " + b"\n"))
def test_delimiter_in_a_later_chunk_is_accepted(self):
class ShortReads:
diff --git a/tests/fixtures/electron/fuseImage.ts b/tests/fixtures/electron/fuseImage.ts
index d618a375f7..6de380a43a 100644
--- a/tests/fixtures/electron/fuseImage.ts
+++ b/tests/fixtures/electron/fuseImage.ts
@@ -1,20 +1,13 @@
-import {
- ELECTRON_FUSE_SENTINEL,
- ELECTRON_FUSE_STATE_BYTES,
-} from "../../../src/domain/electron/electronFuses.js";
-
-export const FUSE_SENTINEL = Buffer.from(ELECTRON_FUSE_SENTINEL, "ascii");
+// Electron's documented on-disk fuse wire, independent of the reader constants:
+// https://github.com/electron/electron/blob/main/docs/tutorial/fuses.md#the-hard-way
+export const FUSE_SENTINEL = Buffer.from(
+ "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX",
+ "ascii",
+);
/** Obsidian's observed version-1 states: disabled, enabled, then six more with the last enabled. */
export const OBSIDIAN_FUSE_BYTES = [
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.enabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.disabled,
- ELECTRON_FUSE_STATE_BYTES.enabled,
+ 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31,
] as const;
export const fuseWire = (version: number, fuses: readonly number[]): Buffer =>
@@ -56,7 +49,7 @@ export const universalFuseImage = (): {
Buffer.concat([FUSE_SENTINEL, fuseWire(1, OBSIDIAN_FUSE_BYTES)]),
);
const rightFuses = [...OBSIDIAN_FUSE_BYTES];
- rightFuses[3] = ELECTRON_FUSE_STATE_BYTES.enabled;
+ rightFuses[3] = 0x31;
const right = thinMacho(
0x0100000c,
Buffer.concat([FUSE_SENTINEL, fuseWire(1, rightFuses)]),
diff --git a/tests/fixtures/environmentStateDerivedValues.ts b/tests/fixtures/environmentStateDerivedValues.ts
index 76a2f2f006..ca7f419d58 100644
--- a/tests/fixtures/environmentStateDerivedValues.ts
+++ b/tests/fixtures/environmentStateDerivedValues.ts
@@ -167,7 +167,7 @@ const slugOf = (title: string): string =>
.replace(/^-|-$/gu, "");
/** A folder named by the uid its creator chose, with an address from that uid and its title, and a time-based numeric id. */
-export const folder = (
+const folder = (
uid: string,
title: string,
id: number,
diff --git a/tests/fixtures/environmentStateItemWrites.ts b/tests/fixtures/environmentStateItemWrites.ts
index 203cb03a30..381093e66e 100644
--- a/tests/fixtures/environmentStateItemWrites.ts
+++ b/tests/fixtures/environmentStateItemWrites.ts
@@ -55,7 +55,7 @@ const TAGS = [
];
/** An item as the application answers it: its parent location and tags spelled out from the ids a call sent. */
-export const inventoryItem = (
+const inventoryItem = (
id: string,
name: string,
parent: Entity | null,
diff --git a/tests/fixtures/environmentStateWrites.ts b/tests/fixtures/environmentStateWrites.ts
index 23e4455c4f..12f8d092d1 100644
--- a/tests/fixtures/environmentStateWrites.ts
+++ b/tests/fixtures/environmentStateWrites.ts
@@ -283,7 +283,7 @@ export const UNCHAPTERED_ROWS: readonly TimedCaptureRow[] = renamingRows(
);
/** A book whose sent handle the application stores as its code and embeds in its link. */
-export const handledBook = (entity: Book, handle: string): Book => ({
+const handledBook = (entity: Book, handle: string): Book => ({
...entity,
code: handle,
link: `https://books.example.test/b/${handle}`,
@@ -348,7 +348,7 @@ const shelved = (entry: Book, shelf: string): Book => ({ ...entry, shelf });
const SHELVED_FIRST = shelved(FIRST_BOOK, "a");
const SHELVED_SECOND = shelved(SECOND_BOOK, "b");
/** The book the create at exchange 7 of QUERY_ROWS made, on shelf a. */
-export const SHELVED_THIRD = shelved(book(3, "Third Book", bookClock(7)), "a");
+const SHELVED_THIRD = shelved(book(3, "Third Book", bookClock(7)), "a");
/**
* One list tool recorded whole, filtered by shelf, searched, sorted and with a flag that changes nothing; item reads;
@@ -373,7 +373,7 @@ export const QUERY_ROWS: readonly TimedCaptureRow[] = [
];
/** A clock spelled with a `+00:00` offset where the books application's item reads spell `Z`. */
-export const offsetClock = (clock: JsonValue | undefined): string =>
+const offsetClock = (clock: JsonValue | undefined): string =>
String(clock).replace(/Z$/u, "+00:00");
/** A book as a list that spells its clocks with an offset shows it. */
diff --git a/tests/fixtures/fakeCdpBrowserEvents.ts b/tests/fixtures/fakeCdpBrowserEvents.ts
index 7133d6ad32..5ea79d28e5 100644
--- a/tests/fixtures/fakeCdpBrowserEvents.ts
+++ b/tests/fixtures/fakeCdpBrowserEvents.ts
@@ -67,7 +67,7 @@ const emitMainWebMcpTools = (
description: "Search orders; authorization=Bearer tool-secret",
frameId: "frame-main",
backendNodeId: 42,
- inputSchema: options.webMcpInputSchema ?? {
+ inputSchema: {
type: "object",
properties: inputSchemaProperties,
required: ["orderId"],
diff --git a/tests/fixtures/fakeCdpBrowserTypes.ts b/tests/fixtures/fakeCdpBrowserTypes.ts
index 3ece0256db..1ef4e07d1a 100644
--- a/tests/fixtures/fakeCdpBrowserTypes.ts
+++ b/tests/fixtures/fakeCdpBrowserTypes.ts
@@ -116,7 +116,6 @@ export interface FakeOptions {
readonly webMcpSameUrlRegistrations?: "retain" | "remove-second";
readonly webMcpFrameCount?: number;
readonly webMcpSchemaPropertyCount?: number;
- readonly webMcpInputSchema?: JsonValue;
readonly webMcpChildLeavesScope?: boolean;
readonly webMcpChildTransientBlank?: boolean;
readonly webMcpChildRecoversAfterTransient?: boolean;
diff --git a/tests/fixtures/flutterVerifierPreload.mjs b/tests/fixtures/flutterVerifierPreload.mjs
new file mode 100644
index 0000000000..863c2e0fb4
--- /dev/null
+++ b/tests/fixtures/flutterVerifierPreload.mjs
@@ -0,0 +1,34 @@
+import { registerHooks } from "node:module";
+const model = `
+const identity={sha256:'a'.repeat(64),bytes:1};
+export function result(operation,input) {
+ const path=input.path;const target={path,...identity};
+ if(operation==='identify_flutter_build') return {target,flutter_detected:true,coverage:'complete',abis:[{abi:'x86_64',libapp:{present:true,elf_header_valid:true,snapshot_hash_sources:2,snapshot_hash:'hash',sha256:'b'.repeat(64),bytes:100},libflutter:{present:true,build_id:'12345678',build_id_candidates:['12345678']}}]};
+ const abi=input.abi ?? (process.env.REA_FLUTTER_PROBE === 'wrong' ? 'ghost' : 'x86_64');
+ return {target,abi,coverage:'complete',libapp:{coverage:'complete',sha256:'b'.repeat(64),bytes:100,snapshot_hash_sources:2,snapshot_hash:'hash',sections:['_kDartVmSnapshotData','_kDartVmSnapshotInstructions','_kDartIsolateSnapshotData','_kDartIsolateSnapshotInstructions'].map(name=>({name,offset:0,size:64,magic_valid:true,kind:3,header_length:48}))},string_pool:{coverage:'complete',package_uri_count_at_least:1,dart_uri_count_at_least:1}};
+}
+export function envelope(op,input){const resultValue=result(op,input);return {normalized_result:resultValue,subject:{local_path:input.path,digest:{sha256:identity.sha256}},limitations:[]};}
+`;
+const modelUrl = "data:text/javascript," + encodeURIComponent(model);
+const mocks = {
+ "node:child_process": `import {promisify} from 'node:util';import {envelope} from ${JSON.stringify(modelUrl)};export const execFile=Object.assign(()=>{}, {[promisify.custom]:async (_cmd,args)=>{const op=args[1].replaceAll('-','_');const index=args.indexOf('--abi');const input={path:args[2],...(index<0?{}:{abi:args[index+1]})};return {stdout:JSON.stringify(envelope(op,input)),stderr:''};}});`,
+ "@modelcontextprotocol/client": `import {envelope} from ${JSON.stringify(modelUrl)};export class Client {async connect(){} async close(){} async callTool({name,arguments:input}){return {structuredContent:envelope(name,input)}}}`,
+ "@modelcontextprotocol/client/stdio": `export class StdioClientTransport {async close(){}}`,
+ "../dist/contracts/toolContracts.js": `export const toolContract=()=>({outputSchema:{parse:value=>value}});`,
+ "../dist/artifacts/ArtifactResourceScope.js": `export class ArtifactResourceScope {async close(){}}`,
+ "./lib/mcp-verifier-results.mjs": `export const requireMcpOutput=response=>response.structuredContent;`,
+ "./lib/verifier-file-resources.mjs": `export const hashVerifierFile=async()=>({sha256:'a'.repeat(64),bytes:1});`,
+};
+registerHooks({
+ resolve(specifier, context, next) {
+ if (
+ context.parentURL?.endsWith("/scripts/verify-flutter.mjs") &&
+ Object.hasOwn(mocks, specifier)
+ )
+ return {
+ shortCircuit: true,
+ url: "data:text/javascript," + encodeURIComponent(mocks[specifier]),
+ };
+ return next(specifier, context);
+ },
+});
diff --git a/tests/fixtures/il2cpp/metadata.ts b/tests/fixtures/il2cpp/metadata.ts
index 45bc4a8f7a..cb2e490924 100644
--- a/tests/fixtures/il2cpp/metadata.ts
+++ b/tests/fixtures/il2cpp/metadata.ts
@@ -7,7 +7,7 @@ type SectionName = IL2cppMetadataSectionName;
type Width = 1 | 2 | 4;
/** Synthetic version 39 metadata small enough to read in a hex dump. */
-export interface Il2cppMetadataFixtureOptions {
+interface Il2cppMetadataFixtureOptions {
/** Serialized TypeIndex width. */
readonly typeIndexWidth?: Width;
/** Omit interfaceOffsets so the TypeIndex width comes from type records. */
@@ -46,7 +46,7 @@ export interface Il2cppMetadataFixtureOptions {
* System.Größe, Game.Player.Slot.Add and System.Größe.ToString;
* the fixture names each container's parameters T0, T1 and so on.
*/
-export const FIXTURE_GENERIC_CONTAINERS = [
+const FIXTURE_GENERIC_CONTAINERS = [
[3, 1, 0, 0],
[2, 2, 1, 1],
[4, 1, 1, 3],
@@ -134,7 +134,7 @@ export const FIXTURE_STRING_LITERALS = [
* Per-image method tokens. Row ids restart in each image and do not follow
* metadata order, so linking must use the token rather than the position.
*/
-export const FIXTURE_METHOD_TOKENS = [
+const FIXTURE_METHOD_TOKENS = [
0x06000002, 0x06000001, 0x06000003, 0x06000001, 0x06000002,
] as const;
diff --git a/tests/fixtures/mcpAdvertisedSchemaValidity.ts b/tests/fixtures/mcpAdvertisedSchemaValidity.ts
index 4549cc0b98..30f76b9631 100644
--- a/tests/fixtures/mcpAdvertisedSchemaValidity.ts
+++ b/tests/fixtures/mcpAdvertisedSchemaValidity.ts
@@ -6,7 +6,7 @@ import {
} from "./mcpClientSchemaConstraints.js";
/** Advertised schema pair as a client receives it from `tools/list`. */
-export interface AdvertisedToolSchemas {
+interface AdvertisedToolSchemas {
readonly name: string;
readonly inputSchema: Record;
readonly outputSchema?: Record | undefined;
diff --git a/tests/fixtures/sqlite/database.ts b/tests/fixtures/sqlite/database.ts
index 445ba6b458..07729df8c7 100644
--- a/tests/fixtures/sqlite/database.ts
+++ b/tests/fixtures/sqlite/database.ts
@@ -12,7 +12,7 @@ export const SQLITE_NATIVE_LIMITS_AVAILABLE = (() => {
})();
/** Exact selected SQLite fixture with committed rows and optional live WAL. */
-export interface SqliteDatabaseFixture {
+interface SqliteDatabaseFixture {
readonly path: string;
readonly walPath: string;
readonly quotedTable: string;
diff --git a/tests/fixtures/uimage.ts b/tests/fixtures/uimage.ts
index 5c4f8ec8d0..64cfd5e462 100644
--- a/tests/fixtures/uimage.ts
+++ b/tests/fixtures/uimage.ts
@@ -1,10 +1,9 @@
import { crc32 } from "node:zlib";
-import {
- UIMAGE_HEADER_SIZE,
- UIMAGE_MAGIC,
- UIMAGE_NAME_LENGTH,
-} from "../../src/domain/uimageFormat.js";
+// U-Boot legacy image header layout, independent of the REA reader.
+const UIMAGE_HEADER_SIZE = 64;
+const UIMAGE_MAGIC = 0x27051956;
+const UIMAGE_NAME_LENGTH = 32;
export interface UImageFixtureOptions {
readonly arch?: number;
diff --git a/tests/fixtures/unityfs.ts b/tests/fixtures/unityfs.ts
index 27b78770e1..28c65d511a 100644
--- a/tests/fixtures/unityfs.ts
+++ b/tests/fixtures/unityfs.ts
@@ -8,7 +8,7 @@ export interface UnityFsMember {
readonly size?: number;
}
-export interface UnityFsOptions {
+interface UnityFsOptions {
readonly formatVersion?: number;
readonly playerVersion?: string;
readonly engineVersion?: string;
@@ -29,7 +29,7 @@ const cstring = (value: string): Buffer =>
const align16 = (value: number): number => (value + 15) & ~15;
/** One final LZ4 literal sequence; separate sequences require intervening matches. */
-export const lz4LiteralBlock = (data: Buffer): Buffer => {
+const lz4LiteralBlock = (data: Buffer): Buffer => {
const head = [Math.min(data.length, 15) << 4];
if (data.length >= 15) {
let extra = data.length - 15;
diff --git a/tests/process-global/ghidraLaunchRollback.test.ts b/tests/process-global/ghidraLaunchRollback.test.ts
index c38993e100..e5dd4eb663 100644
--- a/tests/process-global/ghidraLaunchRollback.test.ts
+++ b/tests/process-global/ghidraLaunchRollback.test.ts
@@ -226,9 +226,10 @@ it.skipIf(process.platform === "win32")(
expect(result.error.cause).toBeInstanceOf(AggregateError);
if (!(result.error.cause instanceof AggregateError))
throw new Error("Expected composite failure");
- expect(result.error.cause.errors[0]).toMatchObject({
- cause: fault.failure,
- });
+ const primary: unknown = result.error.cause.errors[0];
+ expect(primary).toBeInstanceOf(GhidraLaunchError);
+ if (!(primary instanceof GhidraLaunchError)) throw primary;
+ expect(primary.cause).toBe(fault.failure);
expect(result.error.cause.errors[1]).toBeUndefined();
expect(result.error.partialLaunch).toBeDefined();
denyCleanup = false;
diff --git a/tests/process-global/shortFileReads.test.ts b/tests/process-global/shortFileReads.test.ts
index e392cd8e2d..957c1bd46c 100644
--- a/tests/process-global/shortFileReads.test.ts
+++ b/tests/process-global/shortFileReads.test.ts
@@ -388,10 +388,11 @@ it("preserves cancellation during continued short reads and releases the descrip
const path = join(root, "Electron");
await writeFile(path, thinFuseImage(OBSIDIAN_FUSE_BYTES).bytes);
const controller = new AbortController();
+ const reason = new Error("cancel continued read");
fault.path = path;
fault.maximum = 2;
fault.onRead = () => {
- if (fault.reads === 2) controller.abort(new Error("cancel continued read"));
+ if (fault.reads === 2) controller.abort(reason);
};
const provider = new ElectronFuseProvider();
try {
@@ -402,6 +403,7 @@ it("preserves cancellation during continued short reads and releases the descrip
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected cancellation");
expect(result.error).toBeInstanceOf(AnalysisCancelledError);
+ expect(result.error.cause).toBe(reason);
expect(fault.reads).toBe(2);
expect(fault.handles.every((handle) => handle.fd === -1)).toBe(true);
} finally {