From 4e99583bae2a5164f8cbd4b48fb73ca40cb7136e Mon Sep 17 00:00:00 2001 From: "Chirappat, Sudev" Date: Wed, 1 Apr 2026 01:03:11 +0900 Subject: [PATCH 1/5] fix: support non-OAuth auth in login status check `codex login status` only validates OAuth tokens, causing the plugin to reject users who authenticate via OPENAI_API_KEY or a custom model_provider in config.toml (Azure, Bedrock, corporate gateways). Check these auth methods before falling through to `codex login status`. Fixes #21 Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/codex/scripts/lib/codex.mjs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index bf7e8c8..55da44d 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -701,6 +701,24 @@ export function getCodexLoginStatus(cwd) { }; } + if (process.env.OPENAI_API_KEY) { + return { + available: true, + loggedIn: true, + detail: "authenticated via OPENAI_API_KEY" + }; + } + + const configPath = `${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`; + const grep = runCommand("grep", ["-m1", "^model_provider", configPath]); + if (grep.status === 0 && !/=\s*"openai"/.test(grep.stdout)) { + return { + available: true, + loggedIn: true, + detail: "authenticated via custom model provider" + }; + } + const result = runCommand("codex", ["login", "status"], { cwd }); if (result.error) { return { From e1db3103170d1dde06d52915083bdd42914a10e8 Mon Sep 17 00:00:00 2001 From: "Chirappat, Sudev" Date: Wed, 1 Apr 2026 01:35:28 +0900 Subject: [PATCH 2/5] fix: use native fs for provider detection (Windows + single-quote support) Replace grep shell-out with safeReadFile to fix Windows compatibility (grep unavailable) and handle single-quoted TOML values for model_provider. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/codex/scripts/lib/codex.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index 55da44d..3ae2a17 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -34,7 +34,7 @@ * onProgress: ProgressReporter | null * }} TurnCaptureState */ -import { readJsonFile } from "./fs.mjs"; +import { readJsonFile, safeReadFile } from "./fs.mjs"; import { BROKER_BUSY_RPC_CODE, BROKER_ENDPOINT_ENV, CodexAppServerClient } from "./app-server.mjs"; import { loadBrokerSession } from "./broker-lifecycle.mjs"; import { binaryAvailable, runCommand } from "./process.mjs"; @@ -710,8 +710,9 @@ export function getCodexLoginStatus(cwd) { } const configPath = `${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`; - const grep = runCommand("grep", ["-m1", "^model_provider", configPath]); - if (grep.status === 0 && !/=\s*"openai"/.test(grep.stdout)) { + const configContent = safeReadFile(configPath); + const providerMatch = configContent.match(/^model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m); + if (providerMatch && providerMatch[1] !== "openai") { return { available: true, loggedIn: true, From ff7997816fa4dc2643016a3652af03aeb2c9cc7d Mon Sep 17 00:00:00 2001 From: "Chirappat, Sudev" Date: Wed, 1 Apr 2026 10:47:24 +0900 Subject: [PATCH 3/5] fix: also check project-level .codex/config.toml for custom providers Project config takes precedence over global config, matching Codex CLI behavior for provider resolution. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/codex/scripts/lib/codex.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index 3ae2a17..e5d053e 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -709,9 +709,10 @@ export function getCodexLoginStatus(cwd) { }; } - const configPath = `${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`; - const configContent = safeReadFile(configPath); - const providerMatch = configContent.match(/^model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m); + const providerRe = /^model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m; + const globalConfig = safeReadFile(`${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`); + const projectConfig = safeReadFile(`${cwd}/.codex/config.toml`); + const providerMatch = projectConfig.match(providerRe) || globalConfig.match(providerRe); if (providerMatch && providerMatch[1] !== "openai") { return { available: true, From 958487b3d7a67e58bfcfb3b40a3eae339909f9f5 Mon Sep 17 00:00:00 2001 From: "Chirappat, Sudev" Date: Wed, 1 Apr 2026 10:53:21 +0900 Subject: [PATCH 4/5] fix: resolve workspace root for project config and allow indented keys Use resolveWorkspaceRoot (git toplevel) instead of raw cwd for project-level config lookup, and permit leading whitespace in model_provider regex to handle indented TOML entries. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/codex/scripts/lib/codex.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index e5d053e..9b396d2 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -38,6 +38,7 @@ import { readJsonFile, safeReadFile } from "./fs.mjs"; import { BROKER_BUSY_RPC_CODE, BROKER_ENDPOINT_ENV, CodexAppServerClient } from "./app-server.mjs"; import { loadBrokerSession } from "./broker-lifecycle.mjs"; import { binaryAvailable, runCommand } from "./process.mjs"; +import { resolveWorkspaceRoot } from "./workspace.mjs"; const SERVICE_NAME = "claude_code_codex_plugin"; const TASK_THREAD_PREFIX = "Codex Companion Task"; @@ -709,9 +710,10 @@ export function getCodexLoginStatus(cwd) { }; } - const providerRe = /^model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m; + const providerRe = /^\s*model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m; const globalConfig = safeReadFile(`${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`); - const projectConfig = safeReadFile(`${cwd}/.codex/config.toml`); + const workspaceRoot = resolveWorkspaceRoot(cwd); + const projectConfig = safeReadFile(`${workspaceRoot}/.codex/config.toml`); const providerMatch = projectConfig.match(providerRe) || globalConfig.match(providerRe); if (providerMatch && providerMatch[1] !== "openai") { return { From 83a32d5f9d02e53a9809d9ba2774fb4e9938563d Mon Sep 17 00:00:00 2001 From: "Chirappat, Sudev" Date: Wed, 1 Apr 2026 12:49:25 +0900 Subject: [PATCH 5/5] fix: gate project config on trust state from global config Only read project-level .codex/config.toml when the workspace is marked as trusted in the global config, matching Codex CLI behavior. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/codex/scripts/lib/codex.mjs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index 9b396d2..9c925f5 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -692,6 +692,12 @@ export function getSessionRuntimeStatus(env = process.env, cwd = process.cwd()) }; } +function isProjectTrusted(globalConfig, workspaceRoot) { + const escaped = workspaceRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const re = new RegExp(`\\[projects\\."${escaped}"\\][\\s\\S]*?trust_level\\s*=\\s*["']?trusted`); + return re.test(globalConfig); +} + export function getCodexLoginStatus(cwd) { const availability = getCodexAvailability(cwd); if (!availability.available) { @@ -711,9 +717,12 @@ export function getCodexLoginStatus(cwd) { } const providerRe = /^\s*model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m; - const globalConfig = safeReadFile(`${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`); + const globalConfigPath = `${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`; + const globalConfig = safeReadFile(globalConfigPath); const workspaceRoot = resolveWorkspaceRoot(cwd); - const projectConfig = safeReadFile(`${workspaceRoot}/.codex/config.toml`); + const projectConfig = isProjectTrusted(globalConfig, workspaceRoot) + ? safeReadFile(`${workspaceRoot}/.codex/config.toml`) + : ""; const providerMatch = projectConfig.match(providerRe) || globalConfig.match(providerRe); if (providerMatch && providerMatch[1] !== "openai") { return {