Files
stack/packages/mosaic/tests/materialize.test.mjs
T

185 lines
13 KiB
JavaScript

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);
});