import assert from "node:assert/strict";
|
import { execFileSync, spawnSync } from "node:child_process";
|
import { createHash } from "node:crypto";
|
import { mkdtempSync, readFileSync, readdirSync, writeFileSync, chmodSync } from "node:fs";
|
import { tmpdir } from "node:os";
|
import { join } from "node:path";
|
import test from "node:test";
|
|
const sourceDir = new URL(".", import.meta.url).pathname;
|
const runnerSource = join(sourceDir, "EvidenceToolRunner.swift");
|
const isolationSource = join(sourceDir, "FinderWindowIsolation.swift");
|
|
function sha256(path) {
|
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
}
|
|
function compile(source, output) {
|
execFileSync("swiftc", ["-D", "EVIDENCE_RUNNER_TESTING", source, "-o", output], { stdio: "pipe" });
|
}
|
|
function fixture(root, name, body) {
|
const path = join(root, name);
|
writeFileSync(path, `#!/bin/sh\n${body}\n`);
|
chmodSync(path, 0o700);
|
return path;
|
}
|
|
function invoke(runner, root, binary, expectedSha, suffix, env = {}) {
|
const record = join(root, `${suffix}.json`);
|
const result = spawnSync(runner, [
|
"run",
|
record,
|
expectedSha,
|
"session-fixture-a",
|
"cell-fixture-b",
|
binary,
|
"isolate",
|
join(root, "private-state.json"),
|
"private-source-identifier",
|
], { encoding: "utf8", env: { ...process.env, ...env } });
|
const evidence = JSON.parse(readFileSync(record, "utf8"));
|
const expectedRecordSha = readFileSync(`${record}.sha256`, "utf8").trim();
|
assert.equal(expectedRecordSha, sha256(record));
|
assert.equal(readdirSync(root).some((entry) => entry.includes(".tmp-")), false);
|
return { result, evidence, serialized: JSON.stringify(evidence) };
|
}
|
|
test("production runner captures exit, stderr, signal, identity, privacy, and atomic record SHA", () => {
|
const root = mkdtempSync(join(tmpdir(), "mindraw-evidence-runner-test-"));
|
const runner = join(root, "EvidenceToolRunner");
|
compile(runnerSource, runner);
|
|
const selfTest = spawnSync(runner, ["--self-test"], { encoding: "utf8" });
|
assert.equal(selfTest.status, 0);
|
assert.match(selfTest.stdout, /self_test=PASS/);
|
|
const ok = fixture(root, "ok-tool", 'printf "stage=PASS mutation=0\\n"');
|
const okRun = invoke(runner, root, ok, sha256(ok), "ok");
|
assert.equal(okRun.result.status, 0);
|
assert.equal(okRun.evidence.exitCode, 0);
|
assert.equal(okRun.evidence.terminationSignal, null);
|
assert.equal(okRun.evidence.binarySha256, sha256(ok));
|
assert.equal(okRun.evidence.binaryIdentityMatched, true);
|
assert.equal(okRun.evidence.stdout, "stage=PASS mutation=0\n");
|
assert.equal(okRun.evidence.stderr, "");
|
assert.match(okRun.evidence.argvFingerprintSha256, /^[a-f0-9]{64}$/);
|
assert.equal(okRun.evidence.sessionIdentity, "session-fixture-a");
|
assert.equal(okRun.evidence.cellIdentity, "cell-fixture-b");
|
|
const failed = fixture(root, "failed-tool", 'printf "stage=STATE_ATOMIC_WRITE_FAILED mutation=0\\n" >&2; exit 70');
|
const failedRun = invoke(runner, root, failed, sha256(failed), "failed");
|
assert.equal(failedRun.result.status, 70);
|
assert.equal(failedRun.evidence.exitCode, 70);
|
assert.equal(failedRun.evidence.stderr, "stage=STATE_ATOMIC_WRITE_FAILED mutation=0\n");
|
|
const signaled = fixture(root, "signaled-tool", "kill -TERM $$");
|
const signalRun = invoke(runner, root, signaled, sha256(signaled), "signal");
|
assert.equal(signalRun.evidence.exitCode, null);
|
assert.equal(signalRun.evidence.terminationSignal, 15);
|
|
const privateOutput = fixture(root, "private-tool", `printf "/Users/private/person ${join(root, "private-state.json")} private-source-identifier\\n"`);
|
const privateRun = invoke(runner, root, privateOutput, sha256(privateOutput), "private");
|
assert.doesNotMatch(privateRun.serialized, /Users|private-state|private-source-identifier/);
|
assert.match(privateRun.evidence.stdout, /<PRIVATE_PATH>|<STATE_PATH>|<SOURCE_IDENTIFIER>/);
|
|
const mismatchMarker = join(root, "must-not-run");
|
const mismatch = fixture(root, "mismatch-tool", `touch '${mismatchMarker}'`);
|
const mismatchRun = invoke(runner, root, mismatch, "0".repeat(64), "mismatch");
|
assert.equal(mismatchRun.result.status, 78);
|
assert.equal(mismatchRun.evidence.launchStatus, "BINARY_IDENTITY_MISMATCH");
|
assert.equal(mismatchRun.evidence.exitCode, null);
|
assert.equal(mismatchRun.evidence.binaryIdentityMatched, false);
|
assert.equal(readdirSync(root).includes("must-not-run"), false);
|
});
|
|
test("production runner launches the verified snapshot after the source path is replaced", () => {
|
const root = mkdtempSync(join(tmpdir(), "mindraw-evidence-runner-snapshot-test-"));
|
const runner = join(root, "EvidenceToolRunner");
|
compile(runnerSource, runner);
|
|
const executedPath = join(root, "executed-path");
|
const executedFlags = join(root, "executed-flags");
|
const replacementMarker = join(root, "replacement-ran");
|
const source = fixture(root, "source-tool", `printf '%s' "$0" > '${executedPath}'; stat -f '%Sf' "$0" > '${executedFlags}'`);
|
const replacement = fixture(root, "replacement-tool", `touch '${replacementMarker}'`);
|
const expectedSha = sha256(source);
|
const run = invoke(runner, root, source, expectedSha, "source-replaced", {
|
MINDRAW_EVIDENCE_TEST_REPLACE_SOURCE_WITH: replacement,
|
});
|
|
assert.equal(run.result.status, 0);
|
assert.equal(run.evidence.binarySha256, expectedSha);
|
assert.equal(run.evidence.binaryIdentityMatched, true);
|
assert.notEqual(readFileSync(executedPath, "utf8"), source);
|
assert.match(readFileSync(executedFlags, "utf8"), /uchg/);
|
assert.equal(readdirSync(root).includes("replacement-ran"), false);
|
assert.equal(sha256(source), sha256(replacement));
|
assert.equal(readdirSync(tmpdir()).some((entry) => entry.startsWith("mindraw-evidence-exec-")), false);
|
});
|
|
test("production runner rejects replacement of the snapshot object before hardening", () => {
|
const root = mkdtempSync(join(tmpdir(), "mindraw-evidence-runner-snapshot-race-test-"));
|
const runner = join(root, "EvidenceToolRunner");
|
compile(runnerSource, runner);
|
|
const originalMarker = join(root, "original-ran");
|
const replacementMarker = join(root, "replacement-ran");
|
const source = fixture(root, "source-tool", `touch '${originalMarker}'`);
|
const replacement = fixture(root, "replacement-tool", `touch '${replacementMarker}'`);
|
const run = invoke(runner, root, source, sha256(source), "snapshot-replaced", {
|
MINDRAW_EVIDENCE_TEST_REPLACE_SNAPSHOT_WITH: replacement,
|
});
|
|
assert.equal(run.result.status, 77);
|
assert.equal(run.evidence.binaryIdentityMatched, false);
|
assert.equal(run.evidence.exitCode, null);
|
assert.equal(run.evidence.terminationSignal, null);
|
assert.equal(run.evidence.launchStatus, "SNAPSHOT_OBJECT_REPLACED");
|
assert.equal(readdirSync(root).includes("original-ran"), false);
|
assert.equal(readdirSync(root).includes("replacement-ran"), false);
|
assert.doesNotMatch(run.serialized, /source-tool|replacement-tool|mindraw-evidence-exec/);
|
assert.equal(readdirSync(tmpdir()).some((entry) => entry.startsWith("mindraw-evidence-exec-")), false);
|
});
|
|
test("snapshot create, verification, and cleanup failures fail closed and remain auditable", () => {
|
const root = mkdtempSync(join(tmpdir(), "mindraw-evidence-runner-failure-test-"));
|
const runner = join(root, "EvidenceToolRunner");
|
compile(runnerSource, runner);
|
const source = fixture(root, "source-tool", "exit 0");
|
const expectedSha = sha256(source);
|
|
for (const [suffix, variable] of [
|
["create-failure", "MINDRAW_EVIDENCE_TEST_FAIL_SNAPSHOT_CREATE"],
|
["verify-failure", "MINDRAW_EVIDENCE_TEST_FAIL_SNAPSHOT_VERIFY"],
|
]) {
|
const failed = invoke(runner, root, source, expectedSha, suffix, { [variable]: "1" });
|
assert.equal(failed.result.status, 77);
|
assert.match(failed.result.stderr, /snapshot unavailable/);
|
assert.equal(failed.evidence.binaryIdentityMatched, false);
|
assert.equal(failed.evidence.exitCode, null);
|
assert.equal(failed.evidence.terminationSignal, null);
|
assert.equal(failed.evidence.launchStatus,
|
suffix === "create-failure" ? "SNAPSHOT_CREATE_FAILED" : "SNAPSHOT_VERIFY_FAILED");
|
assert.equal(failed.evidence.binarySha256, expectedSha);
|
assert.equal(failed.evidence.snapshotCleanupStatus, "CLEANUP_COMPLETE");
|
assert.equal(failed.evidence.stdout, "");
|
assert.equal(failed.evidence.stderr, "");
|
assert.doesNotMatch(failed.serialized, /source-tool|private-state|private-source-identifier|mindraw-evidence-exec/);
|
}
|
|
const cleanup = invoke(runner, root, source, expectedSha, "cleanup-failure", {
|
MINDRAW_EVIDENCE_TEST_FAIL_SNAPSHOT_CLEANUP: "1",
|
});
|
assert.equal(cleanup.result.status, 77);
|
assert.equal(cleanup.evidence.binaryIdentityMatched, false);
|
assert.equal(cleanup.evidence.launchStatus, "SNAPSHOT_CLEANUP_FAILED");
|
assert.match(cleanup.evidence.stderr, /SNAPSHOT_CLEANUP_FAILED/);
|
assert.equal(readdirSync(tmpdir()).some((entry) => entry.startsWith("mindraw-evidence-exec-")), false);
|
|
const invalidExecutable = join(root, "invalid-executable");
|
writeFileSync(invalidExecutable, "not an executable image\n");
|
chmodSync(invalidExecutable, 0o700);
|
const launchFailure = invoke(runner, root, invalidExecutable, sha256(invalidExecutable), "launch-failure");
|
assert.equal(launchFailure.result.status, 77);
|
assert.equal(launchFailure.evidence.binaryIdentityMatched, true);
|
assert.equal(launchFailure.evidence.launchStatus, "LAUNCH_FAILED");
|
});
|
|
test("Finder isolation self-test proves fixed pre-state stages and state-write classification", () => {
|
const root = mkdtempSync(join(tmpdir(), "mindraw-isolation-observability-test-"));
|
const binary = join(root, "FinderWindowIsolation");
|
compile(isolationSource, binary);
|
const result = spawnSync(binary, ["--self-test"], { encoding: "utf8" });
|
assert.equal(result.status, 0);
|
assert.match(result.stdout, /pre_state_observability=true/);
|
assert.match(result.stdout, /state_write_classification=true/);
|
});
|