// P4: broker security boundary. Mutants: granted user accepted; secret in error/log. import test from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { Broker } from '../src/broker.mjs'; import { Store } from '../src/store.mjs'; const verbs = ['proxy.accounts', 'proxy.login.start', 'proxy.login.submit', 'proxy.login.status', 'proxy.login.cancel', 'proxy.apikey.add', 'proxy.priority.set', 'proxy.group.models.set', 'proxy.keys']; function setup(t, proxyPage = async () => ({ ok: true })) { const root = mkdtempSync(join(tmpdir(), 'p4-bus-')); const store = new Store(root); t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); }); const calls = []; const broker = new Broker({ store, proxyPage: proxyPage && (async (...args) => { calls.push(args); return proxyPage(...args); }), access: () => ({ accessVersion: 1, revision: 1, users: [], grants: [ { id: 'g-1', user: 'alice', business: 'demo', projects: ['*'], instances: ['coder'], level: 'collaborator' }, ] }), businesses: { demo: { id: 'demo', human: 'owner', arbiters: { technical: 'chief', delivery: 'chief' }, vars: { 'bus.tester': true }, roles: {chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, coder: { definition: 'coder', authority: { withinRole: ['message.send'], crossRole: [] } } } } }, }); const caps = { human: broker.bindHuman({ business: 'demo', human: 'owner', via: 'cli', outsideAgent: true }), tester: broker.bindTester({ business: 'demo' }), agent: broker.bindLaunch({ business: 'demo', role: 'coder', run: 'p4-run', harness: 'pi' }), user: broker.bindUser({ business: 'demo', user: 'alice' }), }; return { calls, store, call: (who, verb, args = {}) => broker.request(caps[who], { verb, args }) }; } for (const verb of verbs) { test(`${verb}: owner calls page once with business/human scope`, async t => { const s = setup(t); assert.deepEqual(await s.call('human', verb), { ok: true }); assert.deepEqual(s.calls, [[verb, {}, { business: 'demo', human: 'owner' }]]); }); for (const who of ['tester', 'agent', 'user']) test(`${verb}: ${who} human-required`, async t => { const s = setup(t); await assert.rejects(async () => s.call(who, verb), { code: 'human-required' }); assert.equal(s.calls.length, 0); }); test(`${verb}: not-configured`, async t => { const s = setup(t, null); await assert.rejects(async () => s.call('human', verb), { code: 'not-configured' }); }); } test('API-key canary never enters broker events or unknown error output', async t => { const canary = 'p4-canary-key'; const s = setup(t, async () => { throw new Error(canary); }); await assert.rejects(async () => s.call('human', 'proxy.apikey.add', { provider: 'z.ai', key: canary }), e => e.code === 'proxy-down' && !e.message.includes(canary)); assert.equal(s.calls.length, 1); assert.equal(JSON.stringify(s.store.all('SELECT body FROM events')).includes(canary), false); });