// SPDX-License-Identifier: Apache-2.0 // © 2026 Lutar, Stephen P. — SZL Holdings // ORCID: 0009-0001-0110-4173 // // serve.test.ts — integration tests for `a11oy serve`. // // Each test boots the real HTTP server on an ephemeral port (port 0), seeds a // real receipt ledger on disk using the real emitReceipt/appendReceiptJsonl // path, and hits each route over real TCP with fetch(). Nothing is mocked: the // /v1/verify route runs the real verifyChain, and /v1/policy/evaluate runs the // real threshold gate (real HMAC-SHA-256 receipt). // // Run: node --experimental-strip-types --test src/serve.test.ts // // Authored for SZL Holdings. Signed-off per repository DCO. import { test, before, after } from "node:test"; import assert from "node:assert/strict"; import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import type { AddressInfo } from "node:net"; import type { Server } from "node:http"; import { appendReceiptJsonl, createToolEnvelope, emitReceipt, type OperationalReceipt, } from "./index.ts"; import { createServer, parseServeConfig, handleRoute, brokenIndex } from "./serve.ts"; const policy = { algorithm: "SHA3-256" as const, chaining: "hash_chain" as const, quorum: "1-of-1", nodes: ["test-node"], }; function mkEnvelope(seq: number) { return createToolEnvelope({ protocol: "mcp", actor_id: "did:example:serve-test", tool_name: "receipted_retrieval", lambda_axes: ["Λ7"], payload: { test: true, seq }, metadata: { source: "a11oy-serve-test" }, }); } /** Seed a real 3-receipt chain on disk. Returns the chain. */ function seedLedger(ledgerPath: string): OperationalReceipt[] { const chain: OperationalReceipt[] = []; let prev: OperationalReceipt | null = null; const t0 = Date.now(); for (let i = 0; i < 3; i += 1) { // Distinct, monotonically increasing timestamps so the real verifyChain // timestamp-regression check is satisfied (it compares tai64n at ms // resolution). const r = emitReceipt(mkEnvelope(i), { previousReceipt: prev, policy, timestamp: new Date(t0 + i * 1000), }); appendReceiptJsonl(ledgerPath, r); chain.push(r); prev = r; } return chain; } let dir: string; let ledgerPath: string; let server: Server; let base: string; let seeded: OperationalReceipt[]; before(async () => { dir = fs.mkdtempSync(path.join(os.tmpdir(), "a11oy-serve-test-")); ledgerPath = path.join(dir, "proof.jsonl"); seeded = seedLedger(ledgerPath); const config = parseServeConfig(["--port", "0", "--host", "127.0.0.1", "--ledger", ledgerPath]); server = createServer(config); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const addr = server.address() as AddressInfo; base = `http://127.0.0.1:${addr.port}`; }); after(async () => { await new Promise((resolve) => server.close(() => resolve())); fs.rmSync(dir, { recursive: true, force: true }); }); test("GET /healthz returns 200 with status/sha/ts", async () => { const res = await fetch(`${base}/healthz`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.status, "ok"); assert.equal(typeof body.sha, "string"); assert.ok(body.sha.length > 0); // ts must parse as a valid ISO timestamp. assert.ok(!Number.isNaN(Date.parse(body.ts))); }); test("GET /readyz returns 200 when the ledger is readable", async () => { const res = await fetch(`${base}/readyz`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.status, "ready"); }); test("GET /readyz returns 503 with a reason when the ledger is unreadable", async () => { // Point a fresh server at a path inside a non-existent directory chain that // also can't be created as a plain readReceiptJsonl target. Use a directory // as the ledger path so readReceiptJsonl throws (EISDIR on read). const badConfig = parseServeConfig(["--ledger", dir]); // dir is a directory const r = handleRoute("GET", new URL("http://x/readyz"), "", badConfig); assert.equal(r.status, 503); const body = r.body as { status: string; reason: string }; assert.equal(body.status, "not_ready"); assert.ok(body.reason.length > 0); }); test("GET /v1/ledger?limit=2 returns the last 2 real receipts", async () => { const res = await fetch(`${base}/v1/ledger?limit=2`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.total, 3); assert.equal(body.count, 2); assert.equal(body.receipts.length, 2); // Last two by sequence. assert.equal(body.receipts[0].sequence, 1); assert.equal(body.receipts[1].sequence, 2); // Real receipt_id/merkle_root match what we seeded. assert.equal(body.receipts[1].merkle_root, seeded[2].merkle_root); }); test("GET /v1/ledger/{hash} returns the matching receipt by merkle_root", async () => { const target = seeded[1]; const res = await fetch(`${base}/v1/ledger/${encodeURIComponent(target.merkle_root)}`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.receipt.receipt_id, target.receipt_id); assert.equal(body.receipt.merkle_root, target.merkle_root); }); test("GET /v1/ledger/{hash} returns 404 for an unknown hash", async () => { const res = await fetch(`${base}/v1/ledger/${"0".repeat(64)}`); assert.equal(res.status, 404); }); test("POST /v1/verify accepts a valid real chain (broken_at null)", async () => { const res = await fetch(`${base}/v1/verify`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ledger: seeded }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.valid, true); assert.equal(body.broken_at, null); }); test("POST /v1/verify flags a tampered chain with broken_at index", async () => { // Tamper the second receipt's merkle_root — real verifyChain must catch it. const tampered = seeded.map((r) => ({ ...r })); tampered[1] = { ...tampered[1], merkle_root: "0".repeat(tampered[1].merkle_root.length) }; const res = await fetch(`${base}/v1/verify`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ledger: tampered }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.valid, false); assert.equal(typeof body.broken_at, "number"); assert.ok(body.broken_at >= 1); }); test("POST /v1/policy/evaluate allows a well-attested action with a real receipt_hash", async () => { const res = await fetch(`${base}/v1/policy/evaluate`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: { actionId: "deploy-123", severity: "low", confidence: 0.95, witnesses: [ { id: "w1", role: "operator", attested: true }, { id: "w2", role: "reviewer", attested: true }, ], }, }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.decision, "allow"); assert.equal(body.gate, "ThresholdPolicySeverity"); // Real HMAC-SHA-256 signature is non-empty on allow. assert.equal(typeof body.receipt_hash, "string"); assert.ok(body.receipt_hash.length > 0); }); test("POST /v1/policy/evaluate denies an under-attested high-severity action", async () => { const res = await fetch(`${base}/v1/policy/evaluate`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: { actionId: "wire-funds-1", severity: "critical", confidence: 0.5, witnesses: [{ id: "w1", role: "operator", attested: true }], }, }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.decision, "deny"); assert.equal(body.gate, "ThresholdPolicySeverity"); }); test("brokenIndex maps verifyChain position errors to the earliest index", () => { assert.equal(brokenIndex(["position 2: merkle_root mismatch", "position 5: x"]), 2); assert.equal(brokenIndex([]), null); });