import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFile, readdir, stat, lstat, writeFile, mkdir, symlink } from 'node:fs/promises'; import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { resolveFixtureExecution } from '../src/execution.mjs'; import { createFixtureCredentialStore } from '../src/fixture-store.mjs'; import { createFixtureWorkspace } from '../src/materialize-fixture.mjs'; const base = resolve(import.meta.dirname, 'fixtures/valid'); const json = name => JSON.parse(readFileSync(`${base}/${name}`, 'utf8')); function registry() { const account = json('auth/accounts/openai-codex/homelab-openai/account.json'); const profile = json('auth/settings/research-default.json'); profile.allowedAccounts.push('openai-codex/personal'); return { errors: [], entries: { providers: { 'openai-codex': json('auth/providers/openai-codex.json'), 'ollama-remote': json('auth/providers/ollama-remote.json') }, profiles: { 'research-default': profile }, harnesses: { pi: json('harnesses/pi.json') }, selections: {}, accounts: { 'openai-codex/homelab-openai': account, 'openai-codex/personal': { ...account, id: 'personal', name: 'Personal' } }, } }; } const credential = suffix => ({ type: 'oauth', access: `FIXTURE_ACCESS_${suffix}`, refresh: `FIXTURE_REFRESH_${suffix}`, expires: 9000000000000 }); const store = () => createFixtureCredentialStore({ 'openai-codex/homelab-openai': credential('A'), 'openai-codex/personal': credential('B') }); const request = (executionId = 'exec-a') => ({ fixtureOnly: true, agentId: 'rocko', projectId: 'project-a', workspaceId: 'workspace-a', sessionId: 'session-a', executionId, profile: 'research-default' }); const read = async p => JSON.parse(await readFile(p, 'utf8')); async function workspace(t) { const w = await createFixtureWorkspace(); t.after(() => w.close()); return w; } test('pure resolution selects current default or explicit enrolled account', () => { const r = registry(), req = request(); const p = resolveFixtureExecution(r, req); assert.equal(p.accounts['openai-codex'], 'openai-codex/homelab-openai'); assert.equal(p.models.providers['ollama-remote'].models[0].id, 'qwen2.5-coder:7b'); r.entries.profiles['research-default'].defaultAccounts['openai-codex'] = 'openai-codex/personal'; assert.equal(resolveFixtureExecution(r, req).accounts['openai-codex'], 'openai-codex/personal'); assert.equal(p.accounts['openai-codex'], 'openai-codex/homelab-openai'); }); test('scope is explicit, bounded and never inferred', () => { for (const key of ['agentId', 'projectId', 'workspaceId', 'sessionId', 'executionId']) { const r = request(); delete r[key]; assert.throws(() => resolveFixtureExecution(registry(), r), /invalid-fixture-input/); r[key] = '../outside'; assert.throws(() => resolveFixtureExecution(registry(), r), /invalid-scope/); } assert.throws(() => resolveFixtureExecution(registry(), { ...request(), fixtureOnly: false }), /fixture-only/); }); test('fork pin is preserved against default change, override, missing account and revocation', () => { const r = registry(), q = { ...request(), fork: { sourceSessionId: 'source', accounts: { 'openai-codex': 'openai-codex/homelab-openai' } } }; r.entries.profiles['research-default'].defaultAccounts['openai-codex'] = 'openai-codex/personal'; assert.equal(resolveFixtureExecution(r, q).accounts['openai-codex'], 'openai-codex/homelab-openai'); assert.throws(() => resolveFixtureExecution(r, { ...q, accounts: { 'openai-codex': 'openai-codex/personal' } }), /fork-account-change/); assert.throws(() => resolveFixtureExecution(r, { ...q, fork: { sourceSessionId: 'source', accounts: {} } }), /missing-fork-pin/); delete r.entries.accounts['openai-codex/homelab-openai']; assert.throws(() => resolveFixtureExecution(r, q), /missing-account/); r.entries.profiles['research-default'].allowedAccounts = ['openai-codex/personal']; assert.throws(() => resolveFixtureExecution(r, q), /account-not-enrolled/); }); test('unenrolled account/provider, missing harness, model expansion and native model ceiling refuse', () => { assert.throws(() => resolveFixtureExecution(registry(), { ...request(), accounts: { unknown: 'unknown/a' } }), /provider-not-enrolled/); assert.throws(() => resolveFixtureExecution(registry(), { ...request(), accounts: { 'openai-codex': 'other/a' } }), /account-not-enrolled/); const r = registry(); delete r.entries.harnesses.pi; assert.throws(() => resolveFixtureExecution(r, request()), /unsupported-harness/); const s = registry(); s.entries.profiles['research-default'].models['ollama-remote'] = ['not-allowed']; assert.throws(() => resolveFixtureExecution(s, request()), /model-not-enrolled/); s.entries.profiles['research-default'].models = { 'openai-codex': ['not-enforceable'] }; assert.throws(() => resolveFixtureExecution(s, request()), /native-model-enforcement-unavailable/); }); test('only explicit synthetic credential forms and internal fixture stores admitted', async t => { assert.throws(() => createFixtureCredentialStore({ 'openai-codex/homelab-openai': { type: 'oauth', access: 'not-fixture', refresh: 'not-fixture', expires: 3 } }), /invalid-fixture-credential/); const w = await workspace(t); await assert.rejects(w.generate(registry(), request(), { fixtureOnly: true, transaction() { throw Error('must not execute'); } }), /fixture-store-required/); }); test('two concurrent workspaces of the same agent publish distinct complete private generations', async t => { const w = await workspace(t), s = store(); const a = request('one'), b = { ...request('two'), sessionId: 'session-b', workspaceId: 'workspace-b', accounts: { 'openai-codex': 'openai-codex/personal' } }; const [x, y] = await Promise.all([w.generate(registry(), a, s), w.generate(registry(), b, s)]); assert.notEqual(x.generationPath, y.generationPath); assert.equal((await read(`${x.generationPath}/auth.json`))['openai-codex'].access, 'FIXTURE_ACCESS_A'); assert.equal((await read(`${y.generationPath}/auth.json`))['openai-codex'].access, 'FIXTURE_ACCESS_B'); for (const g of [x, y]) { assert.deepEqual((await readdir(g.generationPath)).sort(), ['auth.json', 'manifest.json', 'models.json']); assert.equal((await stat(g.generationPath)).mode & 0o777, 0o700); for (const file of ['auth.json', 'manifest.json', 'models.json']) assert.equal((await stat(`${g.generationPath}/${file}`)).mode & 0o777, 0o600); const manifest = await readFile(`${g.generationPath}/manifest.json`, 'utf8'); assert.ok(!/FIXTURE_ACCESS|FIXTURE_REFRESH|expires|sha256|credentialHash/.test(manifest)); assert.equal(g.manifest.state, 'ready'); } assert.deepEqual(await readdir(`${w.path}/pending`), []); }); test('same execution ID is exclusively claimed and cannot overwrite a published generation', async t => { const w = await workspace(t), s = store(); const attempts = await Promise.allSettled([w.generate(registry(), request(), s), w.generate(registry(), request(), s)]); assert.equal(attempts.filter(a => a.status === 'fulfilled').length, 1); const g = attempts.find(a => a.status === 'fulfilled').value; const before = await readFile(`${g.generationPath}/auth.json`); await assert.rejects(w.generate(registry(), request(), s), /execution-already-claimed/); assert.deepEqual(await readFile(`${g.generationPath}/auth.json`), before); }); for (const fault of ['after-auth', 'before-publish']) test(`failed generation ${fault} preserves prior files, records failure and refuses blind same-ID retry`, async t => { const w = await workspace(t), s = store(); const first = await w.generate(registry(), request('good'), s); const before = await readFile(`${first.generationPath}/auth.json`); await assert.rejects(w.generate(registry(), request('bad'), s, { fault }), /injected-generation-failure/); assert.deepEqual(await readdir(`${w.path}/generations`), ['good']); assert.deepEqual(await readdir(`${w.path}/pending`), []); assert.deepEqual(await readFile(`${first.generationPath}/auth.json`), before); assert.equal((await read(`${w.path}/claims/bad/failure.json`)).state, 'failed'); await assert.rejects(w.generate(registry(), request('bad'), s), /execution-already-claimed/); }); test('credential lock contention refuses without duplicate side effects', async t => { const w = await workspace(t), s = store(); let release, entered; const ready = new Promise(r => { entered = r; }); const held = s.transaction(['openai-codex/homelab-openai'], async () => { entered(); await new Promise(r => { release = r; }); }); await ready; try { await assert.rejects(w.generate(registry(), request(), s), /credential-busy/); } finally { release(); await held; } assert.deepEqual(await readdir(`${w.path}/generations`), []); }); test('symlinked pre-existing final target is refused and never followed', async t => { const w = await workspace(t); await mkdir(`${w.path}/outside`, { mode: 0o700 }); await writeFile(`${w.path}/outside/sentinel`, 'unchanged'); await symlink(`${w.path}/outside`, `${w.path}/generations/exec-a`); await assert.rejects(w.generate(registry(), request(), store()), /generation-exists/); assert.equal(await readFile(`${w.path}/outside/sentinel`, 'utf8'), 'unchanged'); assert.ok((await lstat(`${w.path}/generations/exec-a`)).isSymbolicLink()); }); test('invalid registry cannot resolve; no fallback to supplied partial entries', () => { const r = registry(); r.errors = [{ code: 'refused' }]; assert.throws(() => resolveFixtureExecution(r, request()), /invalid-registry/); }); test('post-publication failure records uncertainty, preserves complete generation and prevents replay', async t => { const w = await workspace(t), s = store(); await assert.rejects(w.generate(registry(), request('uncertain'), s, { fault: 'after-publish' }), /publication-uncertain/); const dir = `${w.path}/generations/uncertain`; assert.deepEqual((await readdir(dir)).sort(), ['auth.json', 'manifest.json', 'models.json']); const before = await readFile(`${dir}/auth.json`); assert.equal((await read(`${w.path}/claims/uncertain/failure.json`)).state, 'uncertain'); await assert.rejects(w.generate(registry(), request('uncertain'), s), /execution-already-claimed/); assert.deepEqual(await readFile(`${dir}/auth.json`), before); assert.deepEqual(await readdir(`${w.path}/pending`), []); }); test('expired credentials refresh under transaction and subsequent generation reuses rotation', async t => { const w = await workspace(t), s = createFixtureCredentialStore({ 'openai-codex/homelab-openai': { ...credential('OLD'), expires: 1 }, }); const first = await w.generate(registry(), request('rotate'), s); const auth = await read(`${first.generationPath}/auth.json`); assert.equal(auth['openai-codex'].access, 'FIXTURE_ROTATED_ACCESS'); assert.equal(auth['openai-codex'].refresh, 'FIXTURE_ROTATED_REFRESH'); const second = await w.generate(registry(), request('reuse'), s); assert.deepEqual(await read(`${second.generationPath}/auth.json`), auth); await s.transaction(['openai-codex/homelab-openai'], draft => { assert.equal(draft.get('openai-codex/homelab-openai').refresh, 'FIXTURE_ROTATED_REFRESH'); }); }); for (const mode of ['failure', 'timeout', 'malformed']) test(`refresh ${mode} retains prior generation and store state`, async t => { const w = await workspace(t), s = store(); const prior = await w.generate(registry(), request('prior'), s); const bytes = await readFile(`${prior.generationPath}/auth.json`); await assert.rejects(w.generate(registry(), request('failed-refresh'), s, { refresh: { mode, timeoutMs: mode === 'timeout' ? 100 : 2000 } })); assert.deepEqual(await readdir(`${w.path}/generations`), ['prior']); assert.deepEqual(await readFile(`${prior.generationPath}/auth.json`), bytes); await s.transaction(['openai-codex/homelab-openai'], draft => { assert.equal(draft.get('openai-codex/homelab-openai').access, 'FIXTURE_ACCESS_A'); }); await assert.rejects(w.generate(registry(), request('failed-refresh'), s), /execution-already-claimed/); }); test('concurrent refresh on same account refuses contention while unrelated account proceeds', async t => { const w = await workspace(t), s = store(); const results = await Promise.allSettled([ w.generate(registry(), request('busy-a'), s, { refresh: { mode: 'timeout', timeoutMs: 200 } }), w.generate(registry(), request('busy-b'), s, { refresh: { mode: 'timeout', timeoutMs: 200 } }), w.generate(registry(), { ...request('independent'), accounts: { 'openai-codex': 'openai-codex/personal' } }, s), ]); const codes = results.slice(0, 2).map(r => r.reason?.code).sort(); assert.deepEqual(codes, ['credential-busy', 'refresh-timeout']); assert.equal(results[2].status, 'fulfilled'); assert.deepEqual(await readdir(`${w.path}/generations`), ['independent']); }); test('invalid refresh options refuse before burning claim', async t => { const w = await workspace(t), s = store(); await assert.rejects(w.generate(registry(), request(), s, { refresh: { executable: '/bin/false' } }), /invalid-fixture-input/); await w.generate(registry(), request(), s); });