-
Notifications
You must be signed in to change notification settings - Fork 430
fix: read auth.json directly to avoid macOS sandbox panic #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| import test from "node:test"; | ||
| import assert from "node:assert/strict"; | ||
| import fs from "node:fs"; | ||
| import os from "node:os"; | ||
| import path from "node:path"; | ||
|
|
||
| import { getCodexLoginStatus } from "../plugins/codex/scripts/lib/codex.mjs"; | ||
|
|
||
| /** | ||
| * Creates a temporary HOME with a fake ~/.codex/auth.json so | ||
| * getCodexLoginStatus can read the token file directly without | ||
| * spawning the codex binary (which panics on macOS in sandboxed | ||
| * environments due to SCDynamicStore access being blocked). | ||
| */ | ||
| function withTempAuthHome(authPayload, fn) { | ||
| const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "codex-auth-test-")); | ||
| const codexDir = path.join(tmpHome, ".codex"); | ||
| fs.mkdirSync(codexDir, { recursive: true }); | ||
| fs.writeFileSync( | ||
| path.join(codexDir, "auth.json"), | ||
| JSON.stringify(authPayload), | ||
| "utf8" | ||
| ); | ||
|
|
||
| const origHome = process.env.HOME; | ||
| const origUserProfile = process.env.USERPROFILE; | ||
| try { | ||
| process.env.HOME = tmpHome; | ||
| delete process.env.USERPROFILE; | ||
| return fn(tmpHome); | ||
| } finally { | ||
| process.env.HOME = origHome; | ||
| if (origUserProfile !== undefined) { | ||
| process.env.USERPROFILE = origUserProfile; | ||
| } | ||
| fs.rmSync(tmpHome, { recursive: true, force: true }); | ||
| } | ||
| } | ||
|
|
||
| test("getCodexLoginStatus detects ChatGPT auth from auth.json tokens", () => { | ||
| const result = withTempAuthHome( | ||
| { | ||
| auth_mode: "chatgpt", | ||
| tokens: { | ||
| access_token: "fake-access-token", | ||
| refresh_token: "fake-refresh-token", | ||
| id_token: "fake-id-token" | ||
| }, | ||
| last_refresh: "2026-01-01T00:00:00Z" | ||
| }, | ||
| () => getCodexLoginStatus(process.cwd()) | ||
| ); | ||
|
|
||
| // The file-based check should return loggedIn: true without | ||
| // ever calling `codex login status`. | ||
| assert.equal(result.loggedIn, true); | ||
| assert.equal(result.detail, "Logged in using ChatGPT"); | ||
| }); | ||
|
|
||
| test("getCodexLoginStatus detects API key auth from auth.json", () => { | ||
| const result = withTempAuthHome( | ||
| { | ||
| OPENAI_API_KEY: "sk-fake-key-for-test" | ||
| }, | ||
| () => getCodexLoginStatus(process.cwd()) | ||
| ); | ||
|
|
||
| assert.equal(result.loggedIn, true); | ||
| assert.equal(result.detail, "Logged in using API key"); | ||
| }); | ||
|
|
||
| test("getCodexLoginStatus falls through when auth.json has no tokens", () => { | ||
| const result = withTempAuthHome( | ||
| { auth_mode: "chatgpt", tokens: {} }, | ||
| () => getCodexLoginStatus(process.cwd()) | ||
| ); | ||
|
|
||
| // Without valid tokens, the function should fall through to the | ||
| // binary check. Since codex may or may not be installed in the | ||
| // test environment, we just verify it did NOT return loggedIn: true | ||
| // from the file-based path. | ||
| assert.equal(result.loggedIn, false); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This assertion is nondeterministic because the code path intentionally falls through to Useful? React with 👍 / 👎. |
||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getCodexLoginStatus()checksgetCodexAvailability()before it reads~/.codex/auth.json, so this assertion only passes when a realcodexbinary is installed and runnable on PATH. In CI/local environments without Codex,result.loggedInremainsfalse, causing the new positive-path tests to fail even if the auth-file parsing logic is correct. Mock or fixture the Codex availability check so the test validates the new file-based behavior instead of host tooling state.Useful? React with 👍 / 👎.