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

143 lines
11 KiB
JavaScript

// P4 named mutant: returning any unfiltered credential field. Every projection
// and write hits the real management client against a local stand-in server.
import test from 'node:test';
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { fakeManagement } from './proxy-page-fixture.mjs';
const id = value => createHash('sha256').update(value).digest('hex').slice(0, 12);
const oauth = extra => ({ id: 'oauth-one.json', name: 'oauth-one.json', provider: 'claude', label: 'p4-private-label',
email: 'p4-private-email', token: 'p4-private-token', status: 'ready', priority: 3, ...extra });
test('accounts have exactly the allowlisted public fields, id from credential identifier', async t => {
const s = await fakeManagement(t, { files: [oauth()] });
const result = await s.call('proxy.accounts');
assert.deepEqual(result, { accounts: [{ accountId: id('oauth-one.json'), provider: 'claude',
displayName: `Claude account ${id('oauth-one.json')}`, status: 'ready', priority: 3 }] });
for (const value of ['p4-private-label', 'p4-private-email', 'p4-private-token']) {
assert.equal(JSON.stringify(result).includes(value), false);
assert.notEqual(result.accounts[0].accountId, id(value));
assert.equal(JSON.stringify(s.state.receipts).includes(value), false);
}
});
test('token-like data in every upstream field never reaches public accounts', async t => {
const toxic = 'p4-private-token';
const s = await fakeManagement(t, { files: [oauth({ label: toxic, email: toxic, token: toxic, status: toxic,
provider: toxic, account: toxic, account_type: toxic, auth_index: toxic, path: toxic, size: toxic, priority: toxic })] });
const result = await s.call('proxy.accounts');
assert.equal(JSON.stringify(result).includes(toxic), false);
assert.equal(JSON.stringify(s.state.receipts).includes(toxic), false);
assert.deepEqual(Object.keys(result.accounts[0]).sort(), ['accountId', 'displayName', 'priority', 'provider', 'status']);
});
test('API key account is derived from proxy auth_index, never api-key, and can set priority', async t => {
const s = await fakeManagement(t);
await s.call('proxy.apikey.add', { provider: 'z.ai', key: 'p4-canary-key' });
const first = (await s.call('proxy.accounts')).accounts[0];
assert.equal(first.accountId, id('upstream-1')); assert.notEqual(first.accountId, id('p4-canary-key'));
assert.equal(first.provider, 'z.ai'); assert.equal(first.priority, 0);
// Fake preserves derived identifiers across writes, just as the pinned proxy does.
// The next write is expected to strip derived auth_index before sending config.
await s.call('proxy.priority.set', { accountId: first.accountId, priority: 7 });
assert.equal((await s.call('proxy.accounts')).accounts[0].priority, 7);
assert.equal(JSON.stringify(s.state.receipts).includes('p4-canary-key'), false);
});
test('OAuth priority uses top-level name/priority and confirms it through list', async t => {
const s = await fakeManagement(t, { files: [oauth()] });
assert.deepEqual(await s.call('proxy.priority.set', { accountId: id('oauth-one.json'), priority: 8 }),
{ accountId: id('oauth-one.json'), priority: 8 });
assert.equal(s.state.files[0].priority, 8);
assert.equal(s.state.calls.filter(c => c === 'PATCH /v8/management/credentials/fields').length, 1);
});
test('priority-unconfirmed: accepted API-key write with unchanged read-back refuses', async t => {
const s = await fakeManagement(t, { priorityNoop: true,
groups: [{ name: 'z.ai', 'base-url': 'https://api.z.ai/api/anthropic', priority: 0,
keys: [{ 'api-key': 'p4-upstream', auth_index: 'upstream-1' }] }] });
await assert.rejects(s.call('proxy.priority.set', { accountId: id('upstream-1'), priority: 8 }), { code: 'priority-unconfirmed' });
});
for (const status of [201, 400]) test(`priority-write-refused: OAuth PATCH status ${status}`, async t => {
const s = await fakeManagement(t, { files: [oauth()], patchStatus: status });
await assert.rejects(s.call('proxy.priority.set', { accountId: id('oauth-one.json'), priority: 8 }), { code: 'priority-write-refused' });
assert.equal(s.state.calls.filter(c => c.startsWith('PATCH ')).length, 1);
});
test('priority-invalid: unknown account refuses before any write', async t => {
const s = await fakeManagement(t);
await assert.rejects(s.call('proxy.priority.set', { accountId: 'a'.repeat(12), priority: 8 }), { code: 'priority-invalid' });
assert.equal(s.state.calls.some(c => c.startsWith('PUT ') || c.startsWith('PATCH ')), false);
});
test('proxy-down: a closed management listener refuses once', async t => {
const s = await fakeManagement(t);
await new Promise(r => s.server.close(r));
await assert.rejects(s.call('proxy.accounts'), { code: 'proxy-down' });
assert.equal(s.state.receipts.length, 1);
});
test('client keys return ids, sentinel/foreign labels and only scoped record metadata', async t => {
const s = await fakeManagement(t, { keys: ['msk-fixture-sentinel-x', 'msk-fixture-agent', 'foreign-key'],
records: [{ keyId: id('msk-fixture-agent'), agent: 'coder', issuedAt: '2026-10-24T00:00:00Z', state: 'valid' }] });
const result = await s.call('proxy.keys');
assert.deepEqual(result, { keys: [
{ keyId: id('msk-fixture-sentinel-x'), management: 'sentinel', agent: null, issuedAt: null, state: null },
{ keyId: id('msk-fixture-agent'), management: 'stack-managed', agent: 'coder', issuedAt: '2026-10-24T00:00:00Z', state: 'valid' },
{ keyId: id('foreign-key'), management: 'not stack-managed', agent: null, issuedAt: null, state: null },
] });
for (const value of s.state.keys) assert.equal(JSON.stringify(result).includes(value), false);
});
test('a human configures a key group model list and the public row shows it after readback', async t => {
const s = await fakeManagement(t, { groups: [{ name: 'fixture-group', 'base-url': 'https://api.z.ai/api/anthropic', keys: [{ 'api-key': 'fixture-secret', auth_index: 'fixture-index' }] }] });
const result = await s.call('proxy.group.models.set', { accountId: id('fixture-index'), models: ['fixture-one', 'fixture-two'] });
assert.deepEqual(result, { accountId: id('fixture-index'), models: ['fixture-one', 'fixture-two'] });
assert.deepEqual((await s.call('proxy.accounts')).accounts[0].models, ['fixture-one', 'fixture-two']);
assert.equal(JSON.stringify(result).includes('fixture-secret'), false);
for (const models of [['bad model'], ['x', 'x'], Array(33).fill('fixture'), ['../bad']])
await assert.rejects(s.call('proxy.group.models.set', { accountId: id('fixture-index'), models }), { code: 'models-invalid' });
});
test('models save preserves retained upstream aliases while adding and removing ids', async t => {
const s=await fakeManagement(t,{groups:[{name:'fixture-group','base-url':'https://api.z.ai/api/anthropic',keys:[{'api-key':'fixture-secret',auth_index:'fixture-index'}],models:[{name:'fixture-upstream',alias:'fixture-friendly'},{name:'fixture-remove'}]}]});
const accountId=id('fixture-index');
await s.call('proxy.group.models.set',{accountId,models:['fixture-friendly','fixture-remove']});
assert.deepEqual(s.state.groups[0].models,[{name:'fixture-upstream',alias:'fixture-friendly'},{name:'fixture-remove'}]);
await s.call('proxy.group.models.set',{accountId,models:['fixture-friendly','fixture-added']});
assert.deepEqual(s.state.groups[0].models,[{name:'fixture-upstream',alias:'fixture-friendly'},{name:'fixture-added'}]);
});
test('models save refuses ambiguous displayed aliases without writing', async t => {
const s=await fakeManagement(t,{groups:[{name:'fixture-group','base-url':'https://api.z.ai/api/anthropic',keys:[{'api-key':'fixture-secret',auth_index:'fixture-index'}],models:[{name:'fixture-one',alias:'fixture-same'},{name:'fixture-two',alias:'fixture-same'}]}]});
await assert.rejects(s.call('proxy.group.models.set',{accountId:id('fixture-index'),models:['fixture-same']}),{code:'models-ambiguous'});
assert.equal(s.state.calls.some(c=>c.startsWith('PUT ')),false);
});
test('models readback confirms both upstream name and displayed alias', async () => {
const {ProxyPage}=await import('../src/proxy-page.mjs');
let groups=[{name:'fixture-group','base-url':'https://api.z.ai/api/anthropic',keys:[{auth_index:'fixture-index','api-key':'fixture-secret'}],models:[{name:'fixture-upstream',alias:'fixture-friendly'}]}];
const client={getCredentials:async()=>({files:[]}),getUpstreamGroups:async()=>structuredClone(groups),putUpstreamGroups:async next=>{groups=structuredClone(next);groups[0].models[0].name='fixture-wrong';}};
const page=new ProxyPage({client,instanceTag:'fixture'});
await assert.rejects(page.request('proxy.group.models.set',{accountId:id('fixture-index'),models:['fixture-friendly']},{business:'demo',human:'owner'}),{code:'models-unconfirmed'});
});
test('organization proxy page writes refuse while the shared proxy is uncertain', async t => {
const fs = await import('node:fs'); const { join } = await import('node:path'); const { tmpdir } = await import('node:os');
const { createProxyLock } = await import('../src/proxy-lock.mjs');
const dir = fs.mkdtempSync(join(tmpdir(), 'p4-lock-')); t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
const lock = createProxyLock({ stateDir: dir, identity: 'fixture' });
const s = await fakeManagement(t, { lock, org: 'alpha' });
await lock.run(async () => lock.fence({ org: 'beta', op: 'keys.put' }));
await assert.rejects(s.call('proxy.apikey.add', { provider: 'z.ai', key: 'p4-canary' }), { code: 'proxy-uncertain' });
assert.equal(s.state.receives, 0);
});
test('organization key view does not classify a sibling key as its sentinel', async t => {
const sibling = `mso-fixture-alpha-sentinel-key-${'A'.repeat(43)}`;
const s = await fakeManagement(t, { org: 'alpha', keys: [sibling] });
assert.equal((await s.call('proxy.keys')).keys[0].management, 'not stack-managed');
});
test('OAuth callback changes the shared generation for other organization catalogues', async t => {
const fs = await import('node:fs'); const { join } = await import('node:path'); const { tmpdir } = await import('node:os');
const { createProxyLock } = await import('../src/proxy-lock.mjs');
const dir = fs.mkdtempSync(join(tmpdir(), 'p4-oauth-')); t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
const lock = createProxyLock({ stateDir: dir, identity: 'fixture' });
const s = await fakeManagement(t, { lock, org: 'alpha' });
const login = await s.call('proxy.login.start', { provider: 'claude' });
await s.call('proxy.login.submit', { redirect_url: `http://localhost/?state=${login.state}&code=fixture` });
assert.equal(lock.generation(), 1);
});