The cli tests that launch pi deleted only the session login names, so pi's preflight passed or refused by whatever provider keys the host exported. A shared helper now deletes every credential pi's preflight reads and gives pi launches one made-up key. The refusal itself is unchanged. pi bundle() takes a default argument again, so a call with none returns the non-proxy bundle, as before P3. pi.bundle leaves out a launch.models entry whose provider has no proxy route instead of failing every pi launch (F2); malformed proxy entries still refuse. The invalid session proxy context BundleError gets the code invalid-proxy-context. New tests cover F2, the code, and the three proxy account branches in the launcher (F3).
133 lines
7.9 KiB
JavaScript
133 lines
7.9 KiB
JavaScript
// Mos1961: exercise the actual P2 runtime -> launcher -> P3 harness/runner path.
|
|
// Only management/model HTTP and the model adapter are local stand-ins.
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { sandboxProblem } from '../../seat/src/sandbox.mjs';
|
|
import { managedLaunchFixture } from './model-managed-launch-fixture.mjs';
|
|
|
|
const skip = sandboxProblem() ?? false;
|
|
function editBusiness(f, update) {
|
|
const path = join(f.root, 'config', 'businesses', 'acme.json');
|
|
const document = JSON.parse(fs.readFileSync(path, 'utf8'));
|
|
update(document);
|
|
fs.writeFileSync(path, JSON.stringify(document) + '\n', { mode: 0o600 });
|
|
}
|
|
function runnerEnv(session) {
|
|
return Object.fromEntries(fs.readFileSync(`/proc/${session.runnerPid}/environ`, 'utf8')
|
|
.split('\0').filter(Boolean).map(entry => {
|
|
const at = entry.indexOf('='); return [entry.slice(0, at), entry.slice(at + 1)];
|
|
}));
|
|
}
|
|
function privateArtifacts(f, session, keys) {
|
|
const text = fs.readFileSync(join(session.runDir, 'session.json'), 'utf8');
|
|
const saved = JSON.parse(text);
|
|
for (const key of keys) assert.equal(text.includes(key), false, 'session.json contains no credential value');
|
|
for (const name of ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'CLAUDE_CODE_OAUTH_TOKEN', 'ZAI_API_KEY'])
|
|
assert.equal(Object.hasOwn(saved.harnessEnv, name), false, 'harnessEnv persists no provider credential');
|
|
for (const entry of fs.readdirSync(join(session.runDir, 'bundle'), { withFileTypes: true, recursive: true })) {
|
|
if (!entry.isFile()) continue;
|
|
const bytes = fs.readFileSync(join(entry.parentPath, entry.name), 'utf8');
|
|
for (const key of keys) assert.equal(bytes.includes(key), false, 'bundle contains no credential value');
|
|
}
|
|
f.valueFree();
|
|
}
|
|
|
|
for (const [provider, route, generated, api] of [
|
|
['zai', null, 'mosaic-proxy-glm', 'openai-completions'],
|
|
['anthropic', null, 'anthropic', 'anthropic-messages'],
|
|
['proxy', 'anthropic', 'anthropic', 'anthropic-messages'],
|
|
['proxy', 'glm', 'mosaic-proxy-glm', 'openai-completions'],
|
|
['proxy', 'codex', 'mosaic-proxy-codex', 'openai-responses'],
|
|
]) {
|
|
test(`P3 joined managed ${provider}${route ? ':' + route : ''} uses its one admitted P2 key and private run-local config`, { skip, timeout: 30000 }, async t => {
|
|
const f = await managedLaunchFixture(t);
|
|
assert.deepEqual(f.upstreamCredentialNames, [], 'managed proxy fixture has no inherited fake upstream credential');
|
|
editBusiness(f, doc => {
|
|
doc.launch.models['claude-opus-5-5'].provider = provider;
|
|
if (route) doc.launch.models['claude-opus-5-5'].route = route;
|
|
});
|
|
const answer = await f.launcher.launchPm();
|
|
const session = f.sessions().find(value => value.run === answer.run);
|
|
assert.ok(session?.live, 'same real confined runner is live');
|
|
assert.equal(f.trace.successfulPreflights, 1, 'one actual P2 acquisition, not one per check');
|
|
const own = f.bus.credentials.modelRecord('acme/chief');
|
|
assert.ok(own);
|
|
assert.equal(session.modelKeyId, own.keyId, 'binding/stall identity matches admitted generation');
|
|
assert.equal(f.trace.bindings[0].modelKeyId, own.keyId);
|
|
const other = await f.bus.modelPreflight({ business: 'acme', role: 'coder' });
|
|
assert.equal(other.key === own.key, false, 'different agent receives a different key');
|
|
const env = runnerEnv(session);
|
|
assert.equal(env.ANTHROPIC_API_KEY === own.key, true, 'runner gets exactly the admitted key');
|
|
assert.equal(Object.values(env).includes(other.key), false, 'another agent key never enters runner');
|
|
for (const name of ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_AUTH_TOKEN', 'OPENAI_API_KEY', 'OPENROUTER_API_KEY', 'ZAI_API_KEY'])
|
|
assert.equal(Object.hasOwn(env, name), false, `${name} absent from managed runner`);
|
|
const path = join(session.runDir, 'home', '.pi', 'agent', 'models.json');
|
|
const text = fs.readFileSync(path, 'utf8');
|
|
const models = JSON.parse(text);
|
|
assert.equal(models.providers[generated].api, api);
|
|
assert.equal(models.providers[generated].baseUrl,
|
|
other.baseUrl + (api === 'anthropic-messages' ? '' : '/v1'));
|
|
assert.equal(models.providers[generated].models.some(model => model.id === 'claude-opus-5-5'), true);
|
|
for (const value of Object.values(models.providers)) assert.equal(value.apiKey, '$ANTHROPIC_API_KEY');
|
|
for (const key of [own.key, other.key]) assert.equal(text.includes(key), false, 'models contain no key value');
|
|
assert.equal(fs.statSync(path).mode & 0o777, 0o600);
|
|
for (const part of ['home', 'home/.pi', 'home/.pi/agent'])
|
|
assert.equal(fs.statSync(join(session.runDir, part)).mode & 0o777, 0o700);
|
|
privateArtifacts(f, session, [own.key, other.key]);
|
|
});
|
|
}
|
|
|
|
test('P3 joined Claude harness receives the admitted P2 key only through transient auth env', { skip, timeout: 30000 }, async t => {
|
|
const f = await managedLaunchFixture(t, { harness: 'claude-code' });
|
|
assert.deepEqual(f.upstreamCredentialNames, [], 'Claude proxy fixture holds no upstream credential');
|
|
editBusiness(f, doc => { doc.launch.models['claude-opus-5-5'].provider = 'anthropic'; });
|
|
const answer = await f.launcher.launchPm();
|
|
const session = f.sessions().find(value => value.run === answer.run);
|
|
assert.ok(session?.live);
|
|
assert.equal(f.trace.successfulPreflights, 1);
|
|
const own = f.bus.credentials.modelRecord('acme/chief');
|
|
const env = runnerEnv(session);
|
|
assert.equal(env.ANTHROPIC_AUTH_TOKEN === own.key, true, 'Claude receives admitted key without host login');
|
|
assert.equal(env.ANTHROPIC_BASE_URL?.startsWith('http://127.0.0.1:'), true);
|
|
assert.equal(Object.hasOwn(env, 'ANTHROPIC_API_KEY'), false);
|
|
assert.equal(Object.hasOwn(env, 'CLAUDE_CODE_OAUTH_TOKEN'), false);
|
|
assert.equal(session.modelKeyId, own.keyId);
|
|
privateArtifacts(f, session, [own.key]);
|
|
});
|
|
|
|
test('P3 joined unsupported provider refuses with no key acquisition, fallback, or spawned session', { skip, timeout: 30000 }, async t => {
|
|
const f = await managedLaunchFixture(t);
|
|
editBusiness(f, doc => {
|
|
doc.launch.models['claude-opus-5-5'].provider = 'unknown-wire';
|
|
Object.assign(doc.roles.chief.vars, { 'fallback.harness': 'pi', 'fallback.model': 'glm-5.3-flash', 'fallback.thinking': 'low' });
|
|
});
|
|
await assert.rejects(f.launcher.launchPm(), error => error.code === 'proxy-provider-unsupported');
|
|
assert.equal(f.trace.preflightAttempts, 0);
|
|
assert.equal(f.trace.bindings.length, 0);
|
|
assert.equal(f.sessions().length, 0);
|
|
assert.equal(f.runDirectories().length, 0);
|
|
f.valueFree();
|
|
});
|
|
|
|
// Row 332 R2 (#1830, review F2): an entry in launch.models whose provider has no proxy route no
|
|
// longer fails every pi launch of the business after admission. The selected entry routes, the
|
|
// launch goes live, and the unroutable entry is left out of the run-local models file.
|
|
test('row 332 R2 joined pi launch goes live when launch.models also holds an unroutable entry, which models.json leaves out', { skip, timeout: 30000 }, async t => {
|
|
const f = await managedLaunchFixture(t);
|
|
editBusiness(f, doc => {
|
|
doc.launch.models['claude-opus-5-5'].provider = 'anthropic';
|
|
doc.launch.models.router = { provider: 'openrouter', model: 'x' };
|
|
});
|
|
const answer = await f.launcher.launchPm();
|
|
const session = f.sessions().find(value => value.run === answer.run);
|
|
assert.ok(session?.live, 'same real confined runner is live, not launch-failed');
|
|
assert.equal(f.trace.successfulPreflights, 1);
|
|
assert.equal(f.runDirectories().length, 1, 'one run directory, the live one');
|
|
const { providers } = JSON.parse(fs.readFileSync(join(session.runDir, 'home', '.pi', 'agent', 'models.json'), 'utf8'));
|
|
assert.equal(providers.anthropic.models.some(model => model.id === 'claude-opus-5-5'), true);
|
|
assert.equal(Object.values(providers).some(value => value.models.some(model => model.id === 'x')), false, 'no openrouter entry');
|
|
privateArtifacts(f, session, [f.bus.credentials.modelRecord('acme/chief').key]);
|
|
});
|