cerberus-e2e / tree / test/airlock.test.ts ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
/**
 * 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