From 06b85d62b2ceaa961e914681e0b27e1b94df934c Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Tue, 24 Mar 2026 09:51:44 -0700 Subject: [PATCH] test(codex): add coverage for native auth detection in environment probe Add tests for codex_native_auth_present and codex_openai_api_key_missing code paths. Also pass adapter-configured CODEX_HOME through to readCodexAuthInfo so the probe respects per-adapter home directories. Co-Authored-By: Claude Opus 4.6 --- .../adapters/codex-local/src/server/quota.ts | 4 +- .../adapters/codex-local/src/server/test.ts | 3 +- .../codex-local-adapter-environment.test.ts | 61 +++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/packages/adapters/codex-local/src/server/quota.ts b/packages/adapters/codex-local/src/server/quota.ts index b51f6646..7bc771e4 100644 --- a/packages/adapters/codex-local/src/server/quota.ts +++ b/packages/adapters/codex-local/src/server/quota.ts @@ -107,8 +107,8 @@ function parsePlanAndEmailFromToken(idToken: string | null, accessToken: string return { email: null, planType: null }; } -export async function readCodexAuthInfo(): Promise { - const authPath = path.join(codexHomeDir(), "auth.json"); +export async function readCodexAuthInfo(codexHome?: string): Promise { + const authPath = path.join(codexHome ?? codexHomeDir(), "auth.json"); let raw: string; try { raw = await fs.readFile(authPath, "utf8"); diff --git a/packages/adapters/codex-local/src/server/test.ts b/packages/adapters/codex-local/src/server/test.ts index fbf95e62..ed11cd6a 100644 --- a/packages/adapters/codex-local/src/server/test.ts +++ b/packages/adapters/codex-local/src/server/test.ts @@ -109,7 +109,8 @@ export async function testEnvironment( detail: `Detected in ${source}.`, }); } else { - const codexAuth = await readCodexAuthInfo().catch(() => null); + const codexHome = isNonEmpty(env.CODEX_HOME) ? env.CODEX_HOME : undefined; + const codexAuth = await readCodexAuthInfo(codexHome).catch(() => null); if (codexAuth) { checks.push({ code: "codex_native_auth_present", diff --git a/server/src/__tests__/codex-local-adapter-environment.test.ts b/server/src/__tests__/codex-local-adapter-environment.test.ts index a9201c98..6c77d30f 100644 --- a/server/src/__tests__/codex-local-adapter-environment.test.ts +++ b/server/src/__tests__/codex-local-adapter-environment.test.ts @@ -32,6 +32,67 @@ describe("codex_local environment diagnostics", () => { await fs.rm(path.dirname(cwd), { recursive: true, force: true }); }); + it("emits codex_native_auth_present when ~/.codex/auth.json exists and OPENAI_API_KEY is unset", async () => { + const root = path.join( + os.tmpdir(), + `paperclip-codex-auth-${Date.now()}-${Math.random().toString(16).slice(2)}`, + ); + const codexHome = path.join(root, ".codex"); + const cwd = path.join(root, "workspace"); + + try { + await fs.mkdir(codexHome, { recursive: true }); + await fs.writeFile( + path.join(codexHome, "auth.json"), + JSON.stringify({ accessToken: "fake-token", accountId: "acct-1" }), + ); + + const result = await testEnvironment({ + companyId: "company-1", + adapterType: "codex_local", + config: { + command: process.execPath, + cwd, + env: { CODEX_HOME: codexHome }, + }, + }); + + expect(result.checks.some((check) => check.code === "codex_native_auth_present")).toBe(true); + expect(result.checks.some((check) => check.code === "codex_openai_api_key_missing")).toBe(false); + } finally { + await fs.rm(root, { recursive: true, force: true }); + } + }); + + it("emits codex_openai_api_key_missing when neither env var nor native auth exists", async () => { + const root = path.join( + os.tmpdir(), + `paperclip-codex-noauth-${Date.now()}-${Math.random().toString(16).slice(2)}`, + ); + const codexHome = path.join(root, ".codex"); + const cwd = path.join(root, "workspace"); + + try { + await fs.mkdir(codexHome, { recursive: true }); + // No auth.json written + + const result = await testEnvironment({ + companyId: "company-1", + adapterType: "codex_local", + config: { + command: process.execPath, + cwd, + env: { CODEX_HOME: codexHome }, + }, + }); + + expect(result.checks.some((check) => check.code === "codex_openai_api_key_missing")).toBe(true); + expect(result.checks.some((check) => check.code === "codex_native_auth_present")).toBe(false); + } finally { + await fs.rm(root, { recursive: true, force: true }); + } + }); + itWindows("runs the hello probe when Codex is available via a Windows .cmd wrapper", async () => { const root = path.join( os.tmpdir(),