import { runtimeBindings } from '../src/settings-runtime.ts'; import { createServer } from 'node:http'; import { once } from 'node:events'; import { addDatabricks } from '../src/databricks.ts'; import { wrapManagement, unwrapManagement } from '../src/nostr-codec.ts'; import test from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, rmSync, existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { tmpdir } from 'node:os'; import { finalizeEvent } from 'nostr-tools/pure'; import { nsecEncode } from 'nostr-tools/nip19'; import { registerAgent, agentNsec, addOpenAI, addProvider } from '../src/settings-credentials.ts'; import { readSettings, saveSettings, settingsId } from '../src/settings.ts'; import { profileFromEvents } from '../src/agent-profile.ts'; import { isolatedFileCredentials } from './isolated-file-credentials.ts'; import { newKey, publicKey, message, serializeManagement, seal, open, type Message } from '../src/protocol.ts'; import { openAIModels } from '../src/settings-models.ts'; import { host, provision, type Setup, bindingFingerprint } from '../src/host.ts'; import { createGenesis } from '../src/assignment.ts'; import { writePrivate } from '../src/storage.ts'; function fixture(t: test.TestContext) { const root = realpathSync(mkdtempSync(join(tmpdir(),'beehive-pairing-cli-settings-'))); t.after(() => rmSync(root,{ recursive: true, force: true })); return root; } const sleep = (ms: number) => new Promise(r => setTimeout(r,ms)); async function wait(fn: () => boolean) { for(let n=0;n<150;n++) { if(fn()) return; await sleep(20); } throw Error('Fixture wait expired'); } test('identity-only nsec registration verifies retained keys and preserves public-only state', t => { const root = fixture(t), credentials = isolatedFileCredentials(join(root,'keys.json')), secret = newKey(); assert.equal(agentNsec(nsecEncode(Buffer.from(secret,'hex'))),secret); assert.throws(() => agentNsec(secret),/nsec/); const row = registerAgent(root,secret,credentials,{ profileState: 'none' }); assert.equal(row.publicKey,publicKey(secret)); assert.equal(existsSync(join(root,'setup.json')),false); assert.equal(existsSync(join(root,'journal.json')),false); assert.equal(readSettings(root).providers.length,0); assert.equal(readSettings(root).runtimes.length,0); assert.ok(!readFileSync(join(root,'settings.json'),'utf8').includes(secret)); registerAgent(root,secret,credentials,{ profileState: 'unavailable' }); assert.equal(readSettings(root).revision,1); credentials.remove(row.key); assert.throws(() => registerAgent(root,secret,credentials,{ profileState: 'none' }),/missing/); assert.equal(readSettings(root).revision,1); const other = newKey(); assert.throws(() => registerAgent(root,other,{ read: () => null, create() {}, remove() {} },{ profileState: 'none' }),/missing/); assert.equal(readSettings(root).agents.length,1); assert.ok(readFileSync(join(root,'credential-attempts.json'),'utf8').includes(publicKey(other))); }); test('signed profile selects valid latest metadata, strips controls and does not invent names', () => { const secret = newKey(), author = publicKey(secret), now = Math.floor(Date.now()/1000); const event = finalizeEvent({ kind: 0, created_at: now, tags: [], content: JSON.stringify({ name: 'Fixture\u001b[31m', about: 'hello' }) },Buffer.from(secret,'hex')); assert.equal(profileFromEvents([event],author,'wss://fixture.invalid').profileState,'found'); assert.equal(profileFromEvents([event],publicKey(newKey()),'wss://fixture.invalid').profileState,'none'); assert.equal(profileFromEvents([{ ...event, content: '{}' }],author,'wss://fixture.invalid').profileState,'none'); const empty = finalizeEvent({ kind: 0, created_at: now, tags: [], content: '{}' },Buffer.from(secret,'hex')); assert.equal(profileFromEvents([empty],author,'wss://fixture.invalid').profile?.name,undefined); }); test('OpenAI verifies store before public commit; listing is bounded and custom is independent', async t => { const root = fixture(t); let stored: string | null = null; assert.throws(() => addOpenAI(root,'Fixture','synthetic',{ read: () => null, create() {} }),/verification/); assert.equal(readSettings(root).providers.length,0); addOpenAI(root,'Fixture','synthetic',{ read: () => stored, create(_ref,value) { stored = value; } }); const catalog = readSettings(root), provider = catalog.providers[0]!; assert.ok(!readFileSync(join(root,'settings.json'),'utf8').includes('synthetic')); const models = await openAIModels('synthetic',new AbortController().signal,async (_url,options) => { assert.equal((options?.headers as Record).Authorization,'Bearer synthetic'); return new Response(JSON.stringify({ data: [{ id: 'gpt-5' },{ id: 'gpt-5-2026-01-01' },{ id: 'text-embedding-3-small' }] })); }); assert.deepEqual(models,['gpt-5']); await assert.rejects(openAIModels('synthetic',new AbortController().signal,async () => new Response('',{ status: 403 })),/unavailable/); saveSettings(root,{ ...catalog,runtimes: [{ id: settingsId(), name: 'Custom', harness: 'buzz-agent', executable: process.execPath, providerId: provider.id, model: 'unknown-custom-model' }] },catalog.revision); assert.equal(readSettings(root).runtimes[0]?.model,'unknown-custom-model'); assert.throws(() => saveSettings(root,catalog,catalog.revision),/changed/); }); for (const providerType of ['openai','databricks_v2','codex-openai','anthropic','openai-compat','openrouter'] as const) test(`${providerType} saved runtime reaches host Save/new Start while the prior active run remains immutable`, async t => { const root = fixture(t), owner = newKey(), agent = newKey(), hostKey = publicKey(newKey()); const codex = providerType === 'codex-openai'; const added = ['anthropic','openai-compat','openrouter'].includes(providerType); const home = root, config = root; const setup: Setup = { host: hostKey, ownerSecret: owner, agentSecret: agent, runner: realpathSync(process.execPath), args: ['-e','setInterval(()=>{},1000)'], workspace: root, serviceHome: home, configDirectory: config, mode: 'fixture' }; provision(root,setup,createGenesis(publicKey(owner),publicKey(agent),hostKey)); let receive: (m: Message) => void = () => {}; const reports: Message[] = []; const transport = { binding: { host: hostKey, owner: publicKey(owner) }, validate() {}, connect(_url: string,_secret: string,handle: (m: Message) => void) { receive = handle; return { ready: Promise.resolve(), send(m: Message) { reports.push(m); }, close() {} }; } }; let providerReads = 0; const running = await host(root,'ws://127.0.0.1',undefined,transport,undefined,async (input,signal) => { signal.throwIfAborted(); assert.equal((input as any).provider,providerType === 'openai' || codex ? 'openai-compat' : providerType); if (providerType === 'databricks_v2') assert.equal((input as any).host,'https://fixture.example'); providerReads++; return {ok:true,secret:codex ? 'fixture-codex-private-key' : 'synthetic-provider-key'}; }); t.after(() => running.close()); assert.equal(running.agents.length, 1); assert.equal(running.runningAgents, 0); const start = message('start',hostKey,publicKey(agent),0); receive(start); await wait(() => reports.some(m => m.type === 'inventory' && m.body.phase === 'running')); assert.equal(running.runningAgents, 1); const active = reports.filter(m => m.type === 'inventory').at(-1)!.body.actualRun; let stored: string | null = null; if (added) addProvider(root,'Fixture','synthetic',{read:()=>stored,create:(_r,v)=>{stored=v;}},providerType as 'anthropic'|'openai-compat'|'openrouter','https://fixture.example/v1',providerType === 'openai-compat' ? 'responses' : undefined); else if (providerType !== 'databricks_v2') addOpenAI(root,'Fixture','synthetic',{ read: () => stored, create(_r,v) { stored = v; } }); else await addDatabricks(root,'Fixture','https://fixture.example',new AbortController().signal); const prior = readSettings(root), id = settingsId(); const model = codex ? 'custom-codex-model' : added ? (providerType === 'anthropic' ? 'claude-sonnet-4-5' : 'unknown-custom-model') : providerType === 'openai' ? 'gpt-5' : 'databricks-gpt-5-4'; const executable = join(root,'fixture-buzz-agent'); writeFileSync(executable,`#!/bin/sh\n[ \"$REVIEW_MODE\" = synthetic ] || exit 10\n[ \"$BUZZ_AGENT_THINKING_EFFORT\" = high ] || exit 9\nexec '${process.execPath}' '${fileURLToPath(new URL('./acp-fixture.ts',import.meta.url))}' ${providerType === 'openai' ? 'openai' : 'databricks-os'}\n`,{mode:0o700}); let requests = 0; if (added) { const keyName = providerType === 'anthropic' ? 'ANTHROPIC_API_KEY' : providerType === 'openrouter' ? 'OPENROUTER_API_KEY' : 'OPENAI_COMPAT_API_KEY'; const server = createServer(async (req,res) => { assert.equal(req.method,'POST'); assert.equal(req.url, providerType === 'anthropic' ? '/v1/messages' : providerType === 'openrouter' ? '/v1/chat/completions' : '/v1/responses'); assert.equal(req.headers.authorization,'Bearer synthetic-provider-key'); let body=''; for await (const chunk of req) body+=chunk; assert.deepEqual(JSON.parse(body),{model,...(providerType === 'anthropic' ? {} : {effort:'high'})}); requests++; res.end('{}'); }); server.listen(0,'127.0.0.1'); await once(server,'listening'); t.after(()=>new Promise(resolve=>server.close(()=>resolve()))); const endpoint = `http://127.0.0.1:${(server.address() as any).port}` + (providerType === 'anthropic' ? '/v1/messages' : providerType === 'openrouter' ? '/v1/chat/completions' : '/v1/responses'); writeFileSync(executable,`#!${process.execPath} if (process.env.BUZZ_AGENT_PROVIDER !== ${JSON.stringify(providerType)} || process.env.REVIEW_MODE !== 'synthetic') throw Error('Wrong binding'); const response = await fetch(${JSON.stringify(endpoint)},{method:'POST',headers:{authorization:'Bearer '+process.env[${JSON.stringify(keyName)}]},body:JSON.stringify({model:process.env.BUZZ_AGENT_MODEL,effort:process.env.BUZZ_AGENT_THINKING_EFFORT})}); if (!response.ok) throw Error('Synthetic provider refused'); process.argv[2]='saved-provider'; await import(${JSON.stringify(new URL('./acp-fixture.ts',import.meta.url).href)}); `,{mode:0o700}); } if (codex) { const server = createServer(async (req,res) => { assert.equal(req.method,'POST'); assert.equal(req.url,'/v1/responses'); assert.equal(req.headers.authorization,'Bearer fixture-codex-private-key'); let body = ''; for await (const chunk of req) body += chunk; assert.equal(JSON.parse(body).model,model); requests++; res.end('{"output":[]}'); }); server.listen(0,'127.0.0.1'); await once(server,'listening'); t.after(() => new Promise(resolve => server.close(() => resolve()))); const endpoint = `http://127.0.0.1:${(server.address() as any).port}/v1/responses`; writeFileSync(join(root,'mode'),'ok'); writeFileSync(executable,`#!${process.execPath} if (process.env.REVIEW_MODE !== 'synthetic') throw Error('Missing selected runtime environment'); const response = await fetch(${JSON.stringify(endpoint)}, {method:'POST',headers:{authorization:'Bearer '+process.env.OPENAI_API_KEY},body:JSON.stringify({model:JSON.parse(process.env.CODEX_CONFIG).model})}); if (!response.ok) throw Error('Synthetic provider rejected'); await import(${JSON.stringify(new URL('./conversation-harness-fixture.ts',import.meta.url).href)}); `,{mode:0o700}); } saveSettings(root,{ ...prior, runtimes: [{ id, name: 'Future', environment: {REVIEW_MODE:'synthetic'}, harness: codex ? 'codex' : 'buzz-agent', executable, providerId: prior.providers[0]!.id, model, ...(codex ? {cli:realpathSync(process.execPath)} : providerType === 'anthropic' ? {} : {effort:'high'}) }] },prior.revision); const projected = runtimeBindings(setup,readSettings(root))[`runtime:${id}`]!; if (codex) { assert.notEqual(projected.serviceHome,root); assert.equal(existsSync(projected.serviceHome!),false); } await wait(() => running.settingsRevision === 2); await wait(() => reports.some(m => m.type === 'inventory' && (m.body.harnessSetups as any[]).some(r => r.id === `runtime:${id}`))); const inventory = reports.filter(m => m.type === 'inventory').at(-1)!; assert.deepEqual(inventory.body.actualRun,active); const binding = (inventory.body.harnessSetups as any[]).find(r => r.id === `runtime:${id}`); const save = message('save',hostKey,publicKey(agent),inventory.revision,{ model, workspace: root, profile: 'default', harnessSetup: { id: binding.id, fingerprint: binding.fingerprint } }); receive(save); await wait(() => reports.some(m => m.body.operation === save.id)); assert.equal(reports.find(m => m.body.operation === save.id)?.body.result,'saved; running configuration unchanged'); assert.deepEqual(reports.filter(m => m.type === 'inventory').at(-1)!.body.actualRun,active); if (codex) assert.equal(existsSync(projected.serviceHome!),false,'Save is configuration-only'); const current = reports.filter(m => m.type === 'inventory').at(-1)!; const stop = message('stop',hostKey,publicKey(agent),current.revision); receive(stop); await wait(() => reports.some(m => m.body.operation === stop.id)); const stopped = reports.filter(m => m.type === 'inventory').at(-1)!; assert.equal(stopped.body.phase,'stopped'); assert.equal(running.runningAgents, 0); const nextStart = message('start',hostKey,publicKey(agent),stopped.revision); receive(nextStart); await wait(() => reports.some(m => m.body.operation === nextStart.id)); assert.equal(reports.find(m => m.body.operation === nextStart.id)?.body.result,'accepted'); assert.equal((reports.filter(m => m.type === 'inventory').at(-1)!.body.actualRun as any).selection.model,model); assert.equal(providerReads,1); if (added) { assert.equal(requests,1); assert.ok(!readFileSync(join(root,'journal.json'),'utf8').includes('synthetic-provider-key')); } if (codex) { assert.equal(requests,1); assert.ok(!readFileSync(join(root,'journal.json'),'utf8').includes('fixture-codex-private-key')); } assert.ok(!JSON.stringify(reports).includes('synthetic-provider-key')); assert.ok(!readFileSync(join(root,'journal.json'),'utf8').includes('synthetic-provider-key')); const invalid = { ...readSettings(root), revision: 3, runtimes: [] }; writePrivate(join(root,'settings.json'),invalid); await sleep(2100); assert.equal(running.settingsRevision,2,'invalid replacement retains effective catalog'); await running.close(); if (codex) { assert.equal(existsSync(projected.serviceHome!),true,'Stop retains managed state'); assert.equal(existsSync(projected.configDirectory!),true); } }); test('oversized projected inventory retains loaded catalog and serializable reports, including on reopen', async t => { const root = fixture(t), owner = newKey(), agent = newKey(), hostKey = publicKey(newKey()); // Long real paths repeat in each wire row; 100 short public records are not a wire budget. const setup: Setup = { host: hostKey, ownerSecret: owner, agentSecret: agent, runner: realpathSync(process.execPath), args: [], workspace: root, allowedWorkspaces: [root, ...Array.from({length: 12}, (_, i) => join(root, `workspace-${i}-` + 'x'.repeat(120)))], serviceHome: root, configDirectory: root, mode: 'fixture' }; provision(root,setup,createGenesis(publicKey(owner),publicKey(agent),hostKey)); const reports: Message[] = []; const transport = { binding: {host: hostKey, owner: publicKey(owner)}, validate() {}, connect() { return { ready: Promise.resolve(), send(m: Message) { serializeManagement(m); reports.push(m); }, close() {} }; } }; const running = await host(root,'ws://127.0.0.1',undefined,transport); t.after(() => running.close()); let stored: string | null = null; addOpenAI(root,'Fixture','synthetic',{read: () => stored, create(_r,v) { stored = v; }}); const prior = readSettings(root); const row = {id: settingsId(), name: 'Fitting', harness: 'buzz-agent' as const, executable: realpathSync(process.execPath), providerId: prior.providers[0]!.id, model: 'm'.repeat(200)}; saveSettings(root,{...prior, runtimes: [row]},prior.revision); await wait(() => running.settingsRevision === 2); const fitting = reports.filter(m => m.type === 'inventory').at(-1)!; assert.equal((fitting.body.harnessSetups as unknown[]).length,2); // Both production codecs accept the actual fitting inventory. assert.deepEqual(open(seal(fitting,owner),owner),JSON.parse(serializeManagement(fitting))); assert.deepEqual(unwrapManagement(wrapManagement(fitting,Buffer.from(owner,'hex'),publicKey(agent)),Buffer.from(agent,'hex')).message,JSON.parse(serializeManagement(fitting))); const saved = readSettings(root); saveSettings(root,{...saved,runtimes: [...saved.runtimes,...Array.from({length: 18}, () => ({...row,id:settingsId()}))]},saved.revision); assert.equal(readSettings(root).revision,3,'public save is retained, not falsely reported loaded'); const before = reports.length; await sleep(2100); assert.equal(running.settingsRevision,2); assert.ok(reports.length > before,'prior inventory continues to publish'); assert.deepEqual(reports.filter(m => m.type === 'inventory').at(-1)!.body.harnessSetups,fitting.body.harnessSetups); await running.close(); await assert.rejects(host(root,'ws://127.0.0.1',undefined,transport),/bounded wire size/); assert.equal(existsSync(join(root,'host.lock')),false,'failed startup releases only its own lock'); }); test('shared management serializer preserves the exact UTF-8 wire limit for both producers', () => { const secret = newKey(), recipient = newKey(); const m = message('inventory',publicKey(secret),publicKey(recipient),0,{ padding: '' }); const overhead = Buffer.byteLength(JSON.stringify(m)); m.body.padding = 'a'.repeat(32768-overhead); assert.equal(Buffer.byteLength(serializeManagement(m)),32768); assert.deepEqual(open(seal(m,secret),secret),m); assert.deepEqual(unwrapManagement(wrapManagement(m,Buffer.from(secret,'hex'),publicKey(recipient)),Buffer.from(recipient,'hex')).message,m); m.body.padding += 'é'; assert.throws(() => serializeManagement(m),/bounded wire size/); assert.throws(() => seal(m,secret),/bounded wire size/); assert.throws(() => wrapManagement(m,Buffer.from(secret,'hex'),publicKey(recipient)),/bounded wire size/); }); test('legacy registration gains one runtime link without replacing identity or definitions',t=>{ const root=fixture(t),credentials=isolatedFileCredentials(join(root,'keys.json')),secret=newKey(); let providerSecret:string|null=null; addOpenAI(root,'Fixture','synthetic',{read:()=>providerSecret,create:(_r,v)=>{providerSecret=v;}}); const prior=readSettings(root),runtime={id:'runtime-one',name:'Runtime',harness:'buzz-agent' as const,executable:process.execPath,providerId:prior.providers[0]!.id,model:'gpt-5'}; saveSettings(root,{...prior,runtimes:[runtime,{...runtime,id:'runtime-two'}]},prior.revision); const original=registerAgent(root,secret,credentials,{profileState:'none'}),before=readSettings(root); const linked=registerAgent(root,secret,credentials,{profileState:'unavailable'},runtime.id,before.revision); assert.deepEqual(linked,{...original,runtimeId:runtime.id});assert.deepEqual(readSettings(root).runtimes,before.runtimes); assert.deepEqual(registerAgent(root,secret,credentials,{profileState:'none'},'runtime-two'),linked,'registration retains identity and initial choice; host Save owns runtime changes'); assert.throws(()=>registerAgent(root,secret,credentials,{profileState:'none'},runtime.id,before.revision),/changed/); assert.equal(readSettings(root).revision,before.revision+1); });