Files
stack/packages/bus/tests/proxy-page.test.mjs

56 lines
3.0 KiB
JavaScript

// 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: 'coder', delivery: 'coder' },
vars: { 'bus.tester': true }, roles: { 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);
});