mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
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.
274 lines
7.7 KiB
JavaScript
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 });
|
|
});
|