-
Notifications
You must be signed in to change notification settings - Fork 853
fix(codex): emit modern env_key admission line on non-loopback inject #2076
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
Changes from all commits
a0eb776
3da2c2b
f7c6122
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,63 @@ | ||
| # 000 — 260819 triage-execution campaign plan | ||
|
|
||
| Baseline: 4-lane sol-medium triage (2026-08-19) over 53 open PRs + 75 open | ||
| issues. This unit EXECUTES the verdicts. All merges via gh pr merge --admin | ||
| (user pre-approved). Issue-closure rule: a merged PR that resolves an issue | ||
| closes that issue in the same work-phase. | ||
|
|
||
| Live-state reverify (wp0, 2026-08-19): all 14 merge candidates OPEN, | ||
| MERGEABLE, base=dev, zero FAILED checks — but NOT all CI-proven: #2061 #2066 | ||
| #2042 #2072 #2068 #1903 #2075 have no Cross-platform CI run on their exact | ||
| heads (only hygiene/enforce-target). mergeStateStatus=BLOCKED is the | ||
| review-requirement ruleset; admin merge passes. #1885 CONFLICTING (close | ||
| target anyway), #1498 draft+CONFLICTING+red hygiene (close target). | ||
|
Comment on lines
+8
to
+13
Contributor
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. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Correct the merge-candidate inventory before execution. Line [8] says that all 14 merge candidates are 🧰 Tools🪛 markdownlint-cli2 (0.23.2)[warning] 10-10: No space after hash on atx style heading (MD018, no-missing-space-atx) 🤖 Prompt for AI Agents |
||
|
|
||
| **Pre-merge validation rule (r1 audit fold-back):** a PR without a | ||
| Cross-platform CI conclusion on its exact head must NOT be merged on | ||
| mergeability alone. Before merging such a PR: scratch-merge its head onto | ||
| current dev in a lidge worktree and run the focused suites the diff touches | ||
| (plus tsc); only a clean scratch-merge run authorizes the admin merge. The | ||
| post-merge push CI on the merge SHA remains the decisive gate; a red | ||
| post-merge CI triggers immediate fix-forward or revert of that one merge. | ||
|
Comment on lines
+20
to
+21
Contributor
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. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift Classify post-merge CI before continuing a merge batch. The plan schedules multiple admin merges, but it does not require the previous merge's CI result to be classified before the next merge. If a later commit depends on a failed merge, reverting “that one merge” may be unsafe. Require this sequence: one merge, post-merge CI classification, then the next merge. Otherwise, define and test a rollback procedure for batched merges. Also applies to: 27-30 🤖 Prompt for AI Agents |
||
|
|
||
| ## Work-phase map (dependency-ordered) | ||
|
|
||
| | wp | scope | PRs / issues | gate | | ||
| |---|---|---|---| | ||
| | wp1 | batch-quota | merge #2056 #2055 -> close #2047 #2046 | sol review lane per PR, then admin merge, CI on merge SHA | | ||
| | wp2 | batch-small-fixes | merge #2053 #2045 #2061 #2066 -> close #2065 | same | | ||
| | wp3 | batch-lab-chat | merge #2042 #2059; re-diff #2075 vs #2042 (prefix-matching claim); #2044 test-gap decision (merge with follow-up test or request change) | same + 2075 contradiction resolution | | ||
| | wp4 | batch-features | SERIALIZED: merge #2072 first, then re-diff/re-review/scratch-validate #1903 against post-2072 dev before merging it (both touch src/codex/catalog/provider-fetch.ts + provider docs + 9 GUI locales); then #2068 #2057; close #1885 (superseded by #2072) #1498 (stale/dont-merge) | same + serialization gate | | ||
| | wp5 | redesign #2073 | injector env_http_headers -> env_key (codex 0.146+) | C3: wp5's P WRITES 010_env_key_contract.md (contract proof from codex-rs source/release notes via cxc-search) BEFORE impl; impl+tests, PR, admin merge, close #2073 | | ||
| | wp6 | redesign #2064 | Remote raw-thinking on empty summary[] | C3: wp6's P WRITES 020_remote_reasoning_leak_rca.md (root-cause in OUR relay; model-side intermittent exposure is out of scope) BEFORE impl; impl+tests, PR, merge, close #2064 | | ||
| | wp7 | redesign #1926 | tsig credential scope | C4 security: design 051_tsig_credential_scope.md (fin unit), impl+tests, PR, merge, close #1926 | | ||
| | wp8 | redesign #1942 | Windows transactional update rollback | C4: base design 090_transactional_update_rollback.md has a KNOWN path-structure defect (staging/backup as CHILDREN of <prefix> makes the live-prefix swap move them with it, and live cannot move into its own subdirectory) — wp8's P MUST amend the design to sibling-of-prefix staging/backup paths (e.g. <prefix>.ocx-staging-<ts>) before impl; impl+tests, PR, merge, close #1942 | | ||
| | wp9 | closeout | final dev-head CI verify, ledger, unit disposition | push-CI green or pre-existing-red classified | | ||
|
|
||
| ## Review-lane contract (every merge batch) | ||
|
|
||
| - One sol-medium read-only reviewer per PR (parallel), packet includes | ||
| $codexclaw:cxc-dev + $codexclaw:cxc-search mentions, full diff read, | ||
| verdict line MERGE-OK | BLOCK(reason). | ||
| - Main agent merges only MERGE-OK PRs; BLOCK verdicts downgrade the PR to | ||
| NEEDS-WORK with an evidence comment. | ||
|
Comment on lines
+39
to
+43
Contributor
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. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Bind The plan records only Require the verdict to include the exact Proposed verdict contract- verdict line MERGE-OK | BLOCK(reason)
+ verdict line MERGE-OK @ <headRefOid> | BLOCK(reason)🤖 Prompt for AI Agents |
||
| - Merge method: squash when the branch has fixup/noise commits, merge | ||
| otherwise. | ||
| - Suites: lidge dispatch without long blocking waits; decisive gate is the | ||
| Cross-platform CI push run on the merged SHA. | ||
|
|
||
| ## Known risks | ||
|
|
||
| - Seven merge candidates lack head CI (see pre-merge validation rule above); | ||
| scratch-merge lidge validation is mandatory for them. | ||
| - wp4 #2072/#1903 file overlap (provider-fetch.ts, provider docs, locales): | ||
| serialized merge with re-validation between. | ||
| - #1942 base design path defect: fixed at wp8 P via design amendment. | ||
| - #2075 verdict conflict: 1st-pass ADOPT-NOW vs sol NEEDS-WORK (claims it | ||
| reintroduces prefix matching #2042 fixes). Resolve by diffing #2075 head | ||
| against #2042 semantics AFTER #2042 lands. | ||
| - #2064: reasoning leakage can be intermittent model-side behavior; fix only | ||
| what our relay provably does wrong (persisting/rendering raw reasoning when | ||
| summary[] is empty). | ||
| - Windows dispatch CI leg is known-red pre-campaign (Log Guard families) — | ||
| not a gate for these merges. | ||
|
Comment on lines
+62
to
+63
Contributor
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. Bound the known-red Windows CI exception. The plan excludes the Windows dispatch leg based only on “known-red.” It does not identify the baseline run, failing test fingerprints, or a no-new-failures rule. A new Windows regression could therefore be classified as pre-existing. Record the baseline SHA or run, allow only the known failure set, and escalate when the failure set changes. Apply the same evidence to the [stability_and_avAILABILITY] 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # 010 — #2073: injector env_key contract (codex-cli 0.146+) | ||
|
|
||
| ## Contract facts (verified against openai/codex rust-v0.146.0 source, wp5 research lane) | ||
|
|
||
| - env_key reads the named env var and sends Authorization: Bearer <value> | ||
| (model-provider-info/src/lib.rs#L263-281). Missing/empty var = HARD error | ||
| (CodexErr::EnvVar), never an empty bearer. | ||
| - env_key + requires_openai_auth = true is valid; env_key WINS for wire auth | ||
| (first-party scoped auth disabled), requires_openai_auth keeps login/account | ||
| UX (provider.rs#L153-174, auth.rs#L162-178). | ||
| - env_http_headers is still honored in 0.146 (not removed), but bearer auth is | ||
| the documented modern form. | ||
|
|
||
| ## Server-side prerequisite (already landed) | ||
|
|
||
| #1686 chain (22d5492b2, acfedae0a, f848b4997): /v1/responses admits our | ||
|
Contributor
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. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Format the issue reference as normal Markdown text. Line 16 starts with 🧰 Tools🪛 markdownlint-cli2 (0.23.2)[warning] 16-16: No space after hash on atx style heading (MD018, no-missing-space-atx) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| admission secret via Authorization: Bearer and SUBSTITUTES stored main auth | ||
| upstream (materializeCodexUpstreamAuth). So an env_key client works end to end | ||
| on dev today. The injector is the only stale half (this issue). | ||
|
|
||
| ## Change | ||
|
|
||
| src/codex/inject.ts buildProviderTableBlock (legacy/non-loopback mode only — | ||
| loopback Design B emits no auth line at all): | ||
|
|
||
| - BEFORE: env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" } | ||
| - AFTER: env_key = "OPENCODEX_API_AUTH_TOKEN" | ||
|
|
||
| requires_openai_auth = true stays (login UX; env_key wins wire auth). | ||
| Sub-table strip logic from #2061 (env_http_headers orphan cleanup) STAYS — it | ||
| cleans historic configs regenerated by the app. stripExistingModelProvider | ||
| already removes the whole marker-owned block, so old env_http_headers lines | ||
| from prior injections are replaced on next inject (idempotent). | ||
|
|
||
| ## Behavior deltas (accepted) | ||
|
|
||
| - Missing OPENCODEX_API_AUTH_TOKEN in the codex process env: was silent header | ||
| omission -> 401; now a clear codex-side hard error. Better diagnosability; | ||
| the unauthenticated-loopback-listener case already suppresses the auth line | ||
| entirely (shouldInjectApiAuthHeader), so the known no-var environment never | ||
| sees env_key. | ||
| - The client's own ChatGPT bearer is no longer forwarded on this path (env_key | ||
| replaces Authorization); the proxy substitutes stored main auth — exactly the | ||
| #1686 design. Hand-configured env_http_headers remains honored by the runtime | ||
| for users who want the legacy form. | ||
|
|
||
| ## Tests | ||
|
|
||
| - tests/codex-inject.test.ts:44,194 — flip to env_key expectation + add a | ||
| regression that env_http_headers is NOT emitted. | ||
| - tests/loopback-listener-admission.test.ts:199 / integration:617 — extend the | ||
| not-contains to env_key (loopback emits no auth line). | ||
| - Keep #2061 sub-table strip tests untouched. | ||
|
|
||
| ## Docs | ||
|
|
||
| - structure/02_config-and-codex-home.md provider-block sample: update line. | ||
| - docs-site reference mentions of env_http_headers (if any) updated. | ||
|
|
||
| Verifier: bun test tests/codex-inject.test.ts tests/loopback-listener-admission.test.ts tests/loopback-listener-integration.test.ts + bun x tsc --noEmit. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,7 +125,7 @@ name = "OpenCodex Proxy" | |
| base_url = "http://your-host:10100/v1" | ||
| wire_api = "responses" | ||
| requires_openai_auth = true | ||
| env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" } | ||
| env_key = "OPENCODEX_API_AUTH_TOKEN" | ||
|
Contributor
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. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
files=(
docs-site/src/content/docs/fr/guides/codex-integration.md
docs-site/src/content/docs/ja/guides/codex-integration.md
docs-site/src/content/docs/ko/guides/codex-integration.md
docs-site/src/content/docs/ru/guides/codex-integration.md
docs-site/src/content/docs/guides/codex-integration.md
docs-site/src/content/docs/guides/providers.md
)
for file in "${files[@]}"; do
if [ -f "$file" ]; then
echo "===== $file ====="
wc -l "$file"
rg -n -C 8 'env_key|x-opencodex-api-key|loopback|non-loopback|manager|provider.?manager|wire_api|OPENCODEX_API_AUTH_TOKEN' "$file" || true
else
echo "MISSING: $file"
fi
doneRepository: lidge-jun/opencodex Length of output: 30424 🏁 Script executed: #!/bin/bash
set -eu
echo "===== authentication and admission-header implementation ====="
rg -n -C 6 'x-opencodex-api-key|OPENCODEX_API_AUTH_TOKEN|API_AUTH_TOKEN|auth.*header|header.*auth|loopbackOnly|loopback.*auth|non-loopback|isLoopback|isLoopbackHost|provider manager|provider-manager' src docs-site/src/content/docs --glob '!**/node_modules/**' | head -n 1200
echo "===== relevant source files ====="
git ls-files 'src/**' | rg '(auth|server|router|config|inject|proxy|http|provider)' | head -n 200Repository: lidge-jun/opencodex Length of output: 50377 🏁 Script executed: #!/bin/bash
set -eu
echo "===== exact admission predicate and auth matrix ====="
rg -n -C 12 'function shouldInjectApiAuthHeader|shouldInjectApiAuthHeader|validate.*Admission|AUTH_MATRIX|x-opencodex-api-key|apiKeys|hostname' src/clients/config-export.ts src/server/auth-cors.ts src/config.ts src/router.ts src/codex/inject.ts
echo "===== localized manager sections ====="
for file in \
docs-site/src/content/docs/fr/guides/codex-integration.md \
docs-site/src/content/docs/ja/guides/codex-integration.md \
docs-site/src/content/docs/ko/guides/codex-integration.md \
docs-site/src/content/docs/ru/guides/codex-integration.md
do
echo "===== $file ====="
case "$file" in
*"/fr/"*) sed -n '286,298p' "$file" ;;
*"/ja/"*) sed -n '183,189p' "$file" ;;
*"/ko/"*) sed -n '173,179p' "$file" ;;
*"/ru/"*) sed -n '277,287p' "$file" ;;
esac
doneRepository: lidge-jun/opencodex Length of output: 50375 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
docs = {
"fr": ("docs-site/src/content/docs/fr/guides/codex-integration.md", 290, 296),
"ja": ("docs-site/src/content/docs/ja/guides/codex-integration.md", 183, 188),
"ko": ("docs-site/src/content/docs/ko/guides/codex-integration.md", 173, 178),
"ru": ("docs-site/src/content/docs/ru/guides/codex-integration.md", 279, 286),
}
for locale, (name, start, end) in docs.items():
lines = Path(name).read_text().splitlines()
section = "\n".join(f"{i+1}: {lines[i]}" for i in range(start - 1, min(end, len(lines))))
print(f"===== {locale}: {name} =====\n{section}")
print("mentions_loopback_endpoint:", "127.0.0.1" in section)
print("mentions_non_loopback_condition:", bool(re.search(r"non.?loopback|не-loopback|非ループバック|non-loopback", section, re.I)))
print("mentions_header:", "x-opencodex-api-key" in section)
print("conditions_header_on_auth:", bool(re.search(r"auth|аутентификац|認証|auth", section, re.I)))
source = Path("src/codex/inject.ts").read_text().splitlines()
print("===== src/codex/inject.ts predicate =====")
for i in range(168, 211):
print(f"{i+1}: {source[i]}")
PYRepository: lidge-jun/opencodex Length of output: 6361 Tie proxy authentication to the bind hostname. The manager guidance must state that Update 📍 Affects 4 files
🤖 Prompt for AI AgentsSources: Path instructions, Learnings |
||
| # supports_websockets = true # only when config.websockets is true | ||
| ``` | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -196,7 +196,7 @@ name = "OpenCodex Proxy" | |
| base_url = "http://<host>:<port>/v1" | ||
| wire_api = "responses" | ||
| requires_openai_auth = true | ||
| env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" } | ||
| env_key = "OPENCODEX_API_AUTH_TOKEN" | ||
|
Contributor
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. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Update the authentication explanation to match The sample now uses 🤖 Prompt for AI Agents |
||
| ``` | ||
|
|
||
| Root TOML keys must be written before the first `[table]`. Re-injection strips the stale form of | ||
|
|
||
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.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Avoid a heading-shaped issue list entry.
Line [10] starts with
#2042and triggers markdownlint rule MD018. Prefix the sentence with text so the issue IDs do not begin the line.Proposed wording
📝 Committable suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 10-10: No space after hash on atx style heading
(MD018, no-missing-space-atx)
🤖 Prompt for AI Agents
Source: Linters/SAST tools