Files
gods-eye-view/src/codexOauthRealtime.test.mjs
T
Sameh Khamis 3fa5bb7f5f fix(voice): start codex login without the server's provider secrets
The login child inherited the whole server environment, including
OPENAI_API_KEY and every other provider credential. Pass only what Codex
needs to find its home, open a browser and reach OpenAI through a proxy.
2026-10-08 11:02:12 -07:00

274 lines
7.7 KiB
JavaScript

import assert from 'node:assert/strict';
import { EventEmitter } from 'node:events';
import test from 'node:test';
import path from 'node:path';
import {
codexAuthPath,
preferCodexOAuth,
readCodexOAuthAccessToken,
resolveCodexExecutable,
startCodexChatGptLogin,
} from '../server/providers/openai/codex-auth.js';
const nowMs = Date.UTC(2026, 8, 27);
const jwt = (payload) =>
`${Buffer.from('{}').toString('base64url')}.${Buffer.from(JSON.stringify(payload)).toString('base64url')}.signature`;
const auth = (token, extras = {}) =>
JSON.stringify({
auth_mode: 'chatgpt',
tokens: { access_token: token, refresh_token: 'refresh-fixture' },
...extras,
});
test('optional Codex OAuth pin fails closed on ambiguous values', () => {
assert.equal(preferCodexOAuth({}), false);
assert.equal(preferCodexOAuth({ GEV_PREFER_CODEX_OAUTH: 'true' }), true);
assert.equal(preferCodexOAuth({ GEV_PREFER_CODEX_OAUTH: 'off' }), false);
assert.throws(
() => preferCodexOAuth({ GEV_PREFER_CODEX_OAUTH: 'maybe' }),
/must be true or false/,
);
});
test('Codex auth path follows explicit auth file, CODEX_HOME, then home directory', () => {
assert.equal(
codexAuthPath({
environment: { CODEX_AUTH_JSON: '/tmp/custom-auth.json' },
home: '/home/fixture',
}),
path.resolve('/tmp/custom-auth.json'),
);
assert.equal(
codexAuthPath({
environment: { CODEX_HOME: '/tmp/codex-home' },
home: '/home/fixture',
}),
path.join(path.resolve('/tmp/codex-home'), 'auth.json'),
);
assert.equal(
codexAuthPath({ environment: {}, home: '/home/fixture' }),
path.join('/home/fixture', '.codex', 'auth.json'),
);
});
test('Codex OAuth reader accepts a current ChatGPT token and rejects unusable credentials', () => {
const current = jwt({ exp: nowMs / 1000 + 3600 });
assert.equal(
readCodexOAuthAccessToken({
authPath: '/unused',
nowMs,
readFile: () => auth(current),
}),
current,
);
assert.equal(
readCodexOAuthAccessToken({
authPath: '/unused',
nowMs,
readFile: () =>
JSON.stringify({
auth_mode: 'chatgpt',
tokens: { access_token: current },
}),
}),
current,
'GEV does not require or consume the vendor refresh token',
);
for (const readFile of [
() => '{bad json',
() => JSON.stringify({ tokens: {} }),
() => auth(current, { auth_mode: 'apikey' }),
() =>
JSON.stringify({
OPENAI_API_KEY: 'sk-fixture',
tokens: { access_token: current, refresh_token: 'refresh-fixture' },
}),
() => auth('opaque-token'),
() => auth('header.not-json.signature'),
() => auth(jwt({ exp: 'tomorrow' })),
() => {
throw new Error('missing');
},
]) {
assert.throws(
() => readCodexOAuthAccessToken({ authPath: '/unused', readFile, nowMs }),
/ChatGPT sign-in is unavailable/,
);
}
});
test('Codex OAuth reader enforces expiry margin and bounds tokens without exp by file age', () => {
for (const exp of [nowMs / 1000 - 1, nowMs / 1000 + 59]) {
assert.throws(
() => {
readCodexOAuthAccessToken({
authPath: '/unused',
nowMs,
readFile: () => auth(jwt({ exp })),
});
},
(error) => {
assert.match(error.message, /sign-in has expired/);
assert.equal(error.code, 'CODEX_OAUTH_REAUTH_REQUIRED');
return true;
},
);
}
const noExp = jwt({ sub: 'fixture' });
const base = { authPath: '/unused', nowMs, readFile: () => auth(noExp) };
assert.equal(
readCodexOAuthAccessToken({
...base,
statFile: () => ({ mtimeMs: nowMs }),
}),
noExp,
);
assert.throws(
() =>
readCodexOAuthAccessToken({
...base,
statFile: () => ({ mtimeMs: nowMs - 3600_000 }),
}),
/sign-in has expired/,
);
assert.throws(
() =>
readCodexOAuthAccessToken({
...base,
statFile: () => {
throw new Error('missing');
},
}),
/sign-in is unavailable/,
);
});
test('Codex login resolves an installed executable before PATH and starts browser auth detached', async () => {
const checked = [];
assert.equal(
resolveCodexExecutable({
environment: {},
home: '/home/fixture',
access(candidate) {
checked.push(candidate);
if (candidate.endsWith('/.local/bin/codex')) return;
throw new Error('missing');
},
}),
path.join('/home/fixture', '.local', 'bin', 'codex'),
);
assert.equal(checked.length, 1);
const child = new EventEmitter();
let unref = 0;
child.unref = () => {
unref += 1;
};
const calls = [];
const pending = startCodexChatGptLogin({
executable: '/fixture/codex',
home: '/home/fixture',
environment: {
PATH: '/fixture',
https_proxy: 'http://proxy.fixture:8080',
OPENAI_API_KEY: 'fixture-api-key',
GOOGLE_MAPS_SERVER_API_KEY: 'fixture-google-key',
OPENSKY_CLIENT_SECRET: 'fixture-opensky-secret',
},
spawnImpl(command, args, options) {
calls.push({ command, args, options });
queueMicrotask(() => child.emit('spawn'));
return child;
},
});
const login = await pending;
assert.equal(unref, 1);
assert.equal(calls[0].command, '/fixture/codex');
assert.deepEqual(calls[0].args, ['login']);
assert.equal(calls[0].options.detached, true);
assert.equal(calls[0].options.stdio, 'ignore');
assert.deepEqual(
calls[0].options.env,
{
PATH: '/fixture',
https_proxy: 'http://proxy.fixture:8080',
CODEX_HOME: path.join('/home/fixture', '.codex'),
},
'provider secrets stay out of the login process',
);
child.emit('exit', 1);
assert.deepEqual(await login.completion, { exitCode: 1 });
});
test('Codex login refuses a read/write storage mismatch before spawning', async () => {
await assert.rejects(
startCodexChatGptLogin({
environment: { CODEX_AUTH_JSON: '/tmp/another-auth.json' },
home: '/home/fixture',
executable: 'codex',
spawnImpl: () => assert.fail('mismatched storage must not launch login'),
}),
{ code: 'CODEX_OAUTH_STORAGE_MISMATCH' },
);
});
test('Codex login resolves relative CODEX_HOME before changing the child directory', async () => {
const child = new EventEmitter();
const environment = { CODEX_HOME: './fixture-codex' };
const login = await startCodexChatGptLogin({
environment,
executable: 'codex',
spawnImpl(_command, _args, options) {
assert.equal(
options.env.CODEX_HOME,
path.resolve(environment.CODEX_HOME),
);
queueMicrotask(() => child.emit('spawn'));
return child;
},
});
assert.equal(
environment.CODEX_HOME,
'./fixture-codex',
'caller environment is unchanged',
);
child.emit('exit', 0);
assert.deepEqual(await login.completion, { exitCode: 0 });
});
test('Codex login hides spawn errors and can cancel only its owned child', async () => {
const child = new EventEmitter();
await assert.rejects(
startCodexChatGptLogin({
executable: 'codex',
spawnImpl() {
queueMicrotask(() =>
child.emit('error', new Error('private-token-fixture')),
);
return child;
},
}),
(error) =>
error.code === 'CODEX_OAUTH_LOGIN_FAILED' &&
!error.message.includes('private-token-fixture'),
);
const running = new EventEmitter();
let cancelled = 0;
running.kill = (signal) => {
assert.equal(signal, 'SIGTERM');
cancelled += 1;
running.emit('exit', null);
};
const login = await startCodexChatGptLogin({
executable: 'codex',
spawnImpl() {
queueMicrotask(() => running.emit('spawn'));
return running;
},
});
login.cancel();
assert.equal(cancelled, 1);
assert.deepEqual(await login.completion, { exitCode: null });
});