Skip to content

fix: inject OPENAI_API_KEY/CODEX_API_KEY placeholders for Codex api-proxy routing#2136

Merged
lpcox merged 3 commits intomainfrom
fix/codex-api-proxy-websocket-auth
Apr 21, 2026
Merged

fix: inject OPENAI_API_KEY/CODEX_API_KEY placeholders for Codex api-proxy routing#2136
lpcox merged 3 commits intomainfrom
fix/codex-api-proxy-websocket-auth

Conversation

@lpcox
Copy link
Copy Markdown
Collaborator

@lpcox lpcox commented Apr 21, 2026

Problem

Codex v0.121.0 introduced a CODEX_API_KEY-based WebSocket auth flow. When neither CODEX_API_KEY nor OPENAI_API_KEY is present in the agent environment, Codex bypasses OPENAI_BASE_URL and connects directly to wss://api.openai.com/v1/responses for OAuth authentication — getting a 401 because AWF holds the real keys in the api-proxy sidecar.

Diagnostic evidence from the failing smoke run:

  • auth_env_openai_api_key_present=false
  • auth_env_codex_api_key_present=false
  • auth_env_codex_api_key_enabled=true
  • auth_header_attached=false
  • Codex exhausts all 5 WebSocket reconnection retries to api.openai.com directly

Fix

Inject placeholder values for OPENAI_API_KEY and CODEX_API_KEY in the agent container when --enable-api-proxy is active — the same pattern already used for Anthropic credential isolation (ANTHROPIC_AUTH_TOKEN placeholder).

With a key present, Codex finds it, routes API calls through OPENAI_BASE_URL=http://172.30.0.30:10000, and the api-proxy WebSocket upgrade handler (proxyWebSocket()) replaces the placeholder's Authorization header with the real key via Object.assign(forwardHeaders, injectHeaders) before forwarding to api.openai.com.

The real keys are never present in the agent container. The one-shot-token LD_PRELOAD library caches and clears the placeholder from /proc/self/environ as normal.

Changes

  • src/docker-manager.ts: Set OPENAI_API_KEY and CODEX_API_KEY to sk-placeholder-for-api-proxy when api-proxy is enabled
  • src/docker-manager.test.ts: Update 3 tests to assert placeholder is set and real key is not leaked

…redential isolation

Codex v0.121.0 introduced a CODEX_API_KEY-based WebSocket auth flow. When neither
CODEX_API_KEY nor OPENAI_API_KEY is present in the agent environment, Codex bypasses
OPENAI_BASE_URL and connects directly to wss://api.openai.com/v1/responses for OAuth
authentication, getting a 401 because AWF holds the real keys in the api-proxy sidecar.

Fix: inject placeholder values for OPENAI_API_KEY and CODEX_API_KEY when api-proxy is
active (same pattern as ANTHROPIC_AUTH_TOKEN for credential isolation). With a key
present, Codex routes API calls through OPENAI_BASE_URL=http://172.30.0.30:10000. The
api-proxy sidecar then replaces the placeholder Authorization header with the real key
via Object.assign(forwardHeaders, injectHeaders) before forwarding to api.openai.com.

The real keys are never present in the agent container; the placeholders are intercepted
by the api-proxy WebSocket upgrade handler (proxyWebSocket() in server.js:689) and
replaced with the real credentials. The one-shot-token LD_PRELOAD library caches and
clears placeholders from /proc/self/environ as normal.

Update tests to assert placeholder is set and real key is not leaked.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 21, 2026 17:19
@lpcox lpcox requested a review from Mossaka as a code owner April 21, 2026 17:19
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a Codex v0.121+ behavior where missing OPENAI_API_KEY/CODEX_API_KEY in the agent environment can cause Codex to bypass OPENAI_BASE_URL and connect directly to api.openai.com, breaking api-proxy routing and credential isolation.

Changes:

  • Injects placeholder OPENAI_API_KEY and CODEX_API_KEY into the agent container when OpenAI api-proxy routing is configured.
  • Updates docker-manager tests to assert placeholders are present and host keys are not leaked to the agent.
Show a summary per file
File Description
src/docker-manager.ts Adds OpenAI/Codex placeholder key injection alongside OPENAI_BASE_URL proxy configuration.
src/docker-manager.test.ts Updates existing tests to validate placeholder injection and prevent secret leakage under normal and --env-all scenarios.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment thread src/docker-manager.ts Outdated
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…keys

The health check was blocking startup when OPENAI_API_KEY or CODEX_API_KEY
contained the placeholder value 'sk-placeholder-for-api-proxy', treating it
as a credential isolation failure.

Update the check to allow the known placeholder value while still rejecting
any real (non-placeholder) keys. This mirrors the Anthropic pattern where
ANTHROPIC_AUTH_TOKEN is allowed to hold its placeholder value.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results:

  • ✅ Playwright Testing (GitHub page load)
  • ❌ GitHub MCP Testing (gh CLI authentication failed)
  • ✅ File Writing Testing
  • ✅ Bash Tool Testing

Status: FAIL - gh CLI not authenticated for PR listing

💥 [THE END] — Illustrated by Smoke Claude

@github-actions
Copy link
Copy Markdown
Contributor

🔥 Smoke Test: Copilot BYOK — PASS

Test Result
GitHub MCP (list PRs) ✅ Latest merged: "Increase Smoke Claude turn budget to prevent premature engine termination"
GitHub.com connectivity ✅ REST API reachable
File write/read /tmp/gh-aw/agent/smoke-test-copilot-byok-24737140756.txt confirmed
BYOK inference ✅ Response received (agent → api-proxy → api.githubcopilot.com)

Running in BYOK offline mode (COPILOT_OFFLINE=true) via api-proxy → api.githubcopilot.com

Overall: PASS | PR by @lpcox (no assignees)

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Smoke Test Results — @lpcox

Test Result
GitHub MCP (GraphQL) ❌ 404 from proxy
GitHub.com HTTP ⚠️ N/A (template var unresolved)
File write/read ✅ confirmed
REST API (merged PR) ✅ "Increase Smoke Claude turn budget..."

Overall: FAIL (MCP GraphQL unavailable; REST API functional)

📰 BREAKING: Report filed by Smoke Copilot

@github-actions
Copy link
Copy Markdown
Contributor

OpenCode smoke test results

PR titles (last 2 merged):

  • (fetch failed)

  • (fetch failed)

  • File write: ✅

  • Bash read: ✅

  • Build AWF: ✅

Overall status: PASS

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • models.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "models.dev"

See Network Configuration for more information.

🌐 Transmitted by Smoke OpenCode

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results
PR Titles: "fix: inject OPENAI_API_KEY/CODEX_API_KEY placeholders for Codex api-proxy routing"; "Increase Smoke Claude turn budget to prevent premature engine termination"
GitHub MCP Testing: ❌
Safe Inputs GH CLI Testing: ❌
Playwright Testing: ✅
Tavily Web Search Testing: ❌
File Writing + Bash Verification: ✅
Discussion Interaction Testing: ✅
Build AWF (npm ci && npm run build): ✅
Overall Status: FAIL

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.14.1 v20.20.2 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ Tests did not all pass — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx All passed ✅ PASS
Node.js execa All passed ✅ PASS
Node.js p-limit All passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Note (Java): Maven initially failed to create ~/.m2/repository due to a permissions issue in the sandbox environment. Resolved by using -Dmaven.repo.local=/tmp/gh-aw/agent/m2repo to point Maven to a writable location. Both gson and caffeine compiled and tested successfully (1/1 tests each).

Generated by Build Test Suite for issue #2136 · ● 374.4K ·

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test: GitHub Actions Services Connectivity ✅

All checks passed:

Service Check Result
Redis host.docker.internal:6379 PING PONG
PostgreSQL host.docker.internal:5432 pg_isready ✅ accepting connections
PostgreSQL smoketest DB SELECT 1 ✅ returned 1

Note: redis-cli was unavailable; Redis was verified via raw TCP (nc).

🔌 Service connectivity validated by Smoke Services

@lpcox lpcox merged commit 737a5e9 into main Apr 21, 2026
61 of 64 checks passed
@lpcox lpcox deleted the fix/codex-api-proxy-websocket-auth branch April 21, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants