Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion plugins/codex/scripts/lib/codex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
* 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";
import { resolveWorkspaceRoot } from "./workspace.mjs";

const SERVICE_NAME = "claude_code_codex_plugin";
const TASK_THREAD_PREFIX = "Codex Companion Task";
Expand Down Expand Up @@ -691,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`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict trust lookup to the matched project section

The trust check regex can cross section boundaries, so an untrusted workspace can be treated as trusted if any later [projects."..."] block in ~/.codex/config.toml has trust_level = "trusted". In isProjectTrusted, \[projects\."<path>"\][\s\S]*?trust_level... is not bounded to the current table, and getCodexLoginStatus then reads project .codex/config.toml and may report loggedIn: true for custom providers even though Codex would ignore that untrusted project config.

Useful? React with 👍 / 👎.

return re.test(globalConfig);
}

export function getCodexLoginStatus(cwd) {
const availability = getCodexAvailability(cwd);
if (!availability.available) {
Expand All @@ -701,6 +708,30 @@ export function getCodexLoginStatus(cwd) {
};
}

if (process.env.OPENAI_API_KEY) {
return {
available: true,
loggedIn: true,
detail: "authenticated via OPENAI_API_KEY"
};
}

const providerRe = /^\s*model_provider\s*=\s*["']?([^"'\s\r\n]+)["']?/m;
const globalConfigPath = `${process.env.HOME || process.env.USERPROFILE}/.codex/config.toml`;
const globalConfig = safeReadFile(globalConfigPath);
const workspaceRoot = resolveWorkspaceRoot(cwd);
const projectConfig = isProjectTrusted(globalConfig, workspaceRoot)
? safeReadFile(`${workspaceRoot}/.codex/config.toml`)
: "";
const providerMatch = projectConfig.match(providerRe) || globalConfig.match(providerRe);
if (providerMatch && providerMatch[1] !== "openai") {
return {
available: true,
loggedIn: true,
detail: "authenticated via custom model provider"
};
}

const result = runCommand("codex", ["login", "status"], { cwd });
if (result.error) {
return {
Expand Down