/**
* Cerberus end to end suite (seat SEAT3). Every chamber comes from loadChambers() (kit pact-chambers version 1),
* so the same file runs against the reference chambers, Kognai's production chambers, or a broken set:
* CERBERUS_CHAMBERS=/path/to/chambers.ts npm test
*/
import test from 'node:test';
import assert from 'node:assert/strict';
import { fx, NOW, ch, runCase, sessionToken, mutate, type AirlockCase, type SessionCase } from './helpers.ts';
import type { AirlockDecision } from '../src/types.ts';
const AIRLOCK: AirlockCase[] = fx.airlock;
const SESSION: SessionCase[] = fx.session;
const NAMES = ['identity', 'trust', 'intent', 'soul', 'session'];
/** What every decision must look like, pass or refuse: the chambers ran in order and stopped at the first refusal. */
function assertShape(d: AirlockDecision) {
assert.deepEqual(d.steps.map((s) => s.chamber), [1, 2, 3, 4, 5].slice(0, d.steps.length), 'chambers ran in order');
assert.deepEqual(d.steps.map((s) => s.name), NAMES.slice(0, d.steps.length));
if (d.passed) {
assert.equal(d.refused_at, null); assert.equal(d.steps.length, 5); assert.ok(d.steps.every((s) => s.ok));
assert.ok(d.token, 'a passing agent gets a token');
} else {
assert.equal(d.token, null, 'no token after a refusal');
assert.equal(d.steps.length, d.refused_at, 'the airlock stops at the first refusal');
const last = d.steps[d.steps.length - 1];
assert.equal(last.ok, false); assert.ok(last.reason.length > 0, 'a refusal has a reason');
assert.ok(d.steps.slice(0, -1).every((s) => s.ok));
}
}
test('A1 at least 20 fixture cases, driven through runAirlock in order, with no network', async (t) => {
assert.ok(AIRLOCK.length + SESSION.length >= 20);
assert.ok(AIRLOCK.length >= 20, `${AIRLOCK.length} airlock cases`);
assert.equal(new Set([...AIRLOCK, ...SESSION].map((c) => c.id)).size, AIRLOCK.length + SESSION.length, 'unique ids');
const realFetch = globalThis.fetch;
globalThis.fetch = (() => { throw new Error('network used'); }) as typeof fetch;
try {
for (const c of AIRLOCK) {
await t.test(`${c.id} ${c.name}`, async () => {
const { d, second } = await runCase(c);
const final = second ?? d;
if (second) { assert.equal(d.passed, true, 'the first use of the challenge passes'); assertShape(d); }
assertShape(final);
assert.equal(final.passed, c.expect.passed, JSON.stringify(final.steps));
if (c.expect.refused_at !== undefined) assert.equal(final.refused_at, c.expect.refused_at);
if (c.expect.steps !== undefined) assert.equal(final.steps.length, c.expect.steps);
if (c.expect.tier) assert.equal(final.tier, c.expect.tier);
if (c.expect.flags) assert.ok(final.flags.length > 0, 'flagged');
if (final.passed) {
const k = await ch();
const v = k.verifySessionToken({ token: final.token!, now: NOW + (c.at ?? 1000) + 1, secret: fx.secret, jobId: fx.job_id });
assert.equal(v.ok, true, 'the issued token verifies for this job');
assert.equal(final.token!.did, fx.did); assert.equal(final.token!.job_id, fx.job_id); assert.equal(final.token!.tier, final.tier);
}
});
}
} finally { globalThis.fetch = realFetch; }
});
test('A2 each of the five chambers has a pass case and a refusing case', async () => {
for (const n of [1, 2, 3, 4]) assert.ok(AIRLOCK.some((c) => c.expect.refused_at === n), `a refusal at chamber ${n}`);
assert.ok(SESSION.some((c) => !c.expect.ok) && SESSION.some((c) => c.expect.ok), 'chamber 5 pass and refuse');
assert.ok(AIRLOCK.some((c) => c.expect.passed), 'a case passes all five');
// an unproven agent is never refused when the job sets no minimum tier
const { d } = await runCase({ id: 'X1', name: 'unproven', record: 'unproven', expect: { passed: true } });
assert.equal(d.passed, true); assert.equal(d.tier, 'unproven');
// chamber 2 never refuses by itself
const k = await ch();
for (const r of Object.values(fx.records)) assert.ok(['unproven', 'bronze', 'silver', 'gold'].includes(k.scoreAgent(r as any).tier));
});
test('A3 the session token is checked for expiry and for tampering', async (t) => {
const k = await ch();
for (const c of SESSION) {
await t.test(`${c.id} ${c.name}`, async () => {
const token = mutate(await sessionToken(c.tier), c.mutate);
const v = k.verifySessionToken({ token, now: NOW + c.check, secret: c.secret ?? fx.secret, jobId: c.job_id ?? fx.job_id });
assert.equal(v.ok, c.expect.ok, v.reason);
if (!v.ok) assert.ok(v.reason.length > 0);
if (c.check_expired !== undefined) {
const e = k.verifySessionToken({ token, now: NOW + c.check_expired, secret: fx.secret, jobId: fx.job_id });
assert.equal(e.ok, false, 'expired at its tier lifetime');
}
});
}
// the token from a full airlock run expires with its tier lifetime
const { d } = await runCase({ id: 'X2', name: 'gold run', record: 'veteran', expect: { passed: true } });
const life = Date.parse(d.token!.expires_at) - Date.parse(d.token!.issued_at);
assert.equal(life, 240 * 60_000);
assert.equal(k.verifySessionToken({ token: d.token!, now: Date.parse(d.token!.expires_at), secret: fx.secret }).ok, false);
});
agentgate-source: code mirror on Cloudflare Pages. All repos