betterwithage's picture
sync(space): complete build context — fix BUILD_ERROR (CTO)
518343a verified
Raw
History Blame
4.68 kB
#!/usr/bin/env node
// Copyright 2026 SZL Holdings
// SPDX-License-Identifier: Apache-2.0
//
// selftest.ts — in-process boot self-test for the receipt-substrate CLI image.
//
// The a11oy container is a CLI image, not a long-running network service, so
// it has no HTTP readiness probe. Without a self-test, a built image can ship
// with a broken or partially-copied dist/ and still "start" (the entrypoint
// prints --help and exits 0), giving a misleading green signal.
//
// This self-test exercises the real receipt path end to end against an
// ephemeral temp file: it emits a genesis receipt, appends a second receipt,
// reads the chain back from disk, and verifies the hash chain. It writes
// solely to a unique temp file under the OS temp dir, makes no network calls,
// and cleans up after itself. A non-zero exit means the bundled substrate is
// not functional in this image.
//
// Authored for SZL Holdings. Signed-off per repository DCO.
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import {
appendReceiptJsonl,
createToolEnvelope,
emitReceipt,
readReceiptJsonl,
verifyChain,
type OperationalReceipt,
} from "./index.ts";
interface SelfTestResult {
ok: boolean;
checks: { name: string; ok: boolean; detail?: string }[];
}
/**
* Run the receipt-substrate boot self-test.
*
* Returns a structured result. Does not throw on a failed check; instead each
* failure is recorded so the caller can report all problems at once.
*/
export function runSelfTest(): SelfTestResult {
const checks: SelfTestResult["checks"] = [];
const record = (name: string, ok: boolean, detail?: string) => {
checks.push({ name, ok, detail });
};
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "a11oy-selftest-"));
const out = path.join(dir, "selftest-receipts.jsonl");
const policy = {
algorithm: "SHA3-256" as const,
chaining: "hash_chain" as const,
quorum: "1-of-1",
nodes: ["selftest-node"],
};
const mkEnvelope = (seq: number) =>
createToolEnvelope({
protocol: "mcp",
actor_id: "did:example:selftest",
tool_name: "receipted_retrieval",
lambda_axes: ["Λ7"],
payload: { selftest: true, seq },
metadata: { source: "a11oy-receipt-substrate-selftest" },
});
try {
// 1. Emit a genesis receipt and persist it.
const genesis = emitReceipt(mkEnvelope(0), { policy });
appendReceiptJsonl(out, genesis);
record("emit-genesis", true);
// 2. Append a second receipt chained to the genesis.
const second = emitReceipt(mkEnvelope(1), { previousReceipt: genesis, policy });
appendReceiptJsonl(out, second);
record("append-chained", true);
// 3. Read the chain back from disk (round-trip through JSONL).
const chain: OperationalReceipt[] = readReceiptJsonl(out);
const readBackOk = chain.length === 2;
record("read-back", readBackOk, readBackOk ? undefined : `expected 2 receipts, found ${chain.length}`);
// 4. Verify the hash chain.
const verification = verifyChain(chain, { quorum: "1-of-1", nodes: ["selftest-node"] });
record(
"verify-chain",
verification.valid,
verification.valid ? undefined : verification.errors.join("; "),
);
// 5. Negative control: a tampered chain must fail verification. This
// guards against a verifier that always returns valid.
const tampered: OperationalReceipt[] = [
{ ...chain[0] },
{ ...chain[1], merkle_root: "0".repeat(chain[1].merkle_root.length) },
];
const tamperedResult = verifyChain(tampered, { quorum: "1-of-1", nodes: ["selftest-node"] });
record(
"reject-tampered",
tamperedResult.valid === false,
tamperedResult.valid ? "tampered chain was incorrectly accepted" : undefined,
);
} catch (error) {
record("unexpected-error", false, (error as Error).message);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
return { ok: checks.every((c) => c.ok), checks };
}
function main(): void {
const result = runSelfTest();
for (const c of result.checks) {
const icon = c.ok ? "ok " : "FAIL";
const detail = c.detail ? ` (${c.detail})` : "";
console.log(` [${icon}] ${c.name}${detail}`);
}
if (result.ok) {
console.log("a11oy receipt-substrate self-test: PASS");
process.exit(0);
}
console.error("a11oy receipt-substrate self-test: FAIL");
process.exit(1);
}
// Run when invoked directly (node src/selftest.ts), not when imported.
const invokedDirectly =
process.argv[1] !== undefined && path.resolve(process.argv[1]).endsWith("selftest.ts");
if (invokedDirectly) {
main();
}