Skip to content

fix(responses): preserve Codex client metadata on routed requests - #8193

Draft
ParsifalC wants to merge 2 commits into
lidge-jun:devfrom
ParsifalC:codex/forward-codex-client-metadata
Draft

ParsifalC wants to merge 2 commits into
lidge-jun:devfrom
ParsifalC:codex/forward-codex-client-metadata

Conversation

@ParsifalC

@ParsifalC ParsifalC commented Nov 5, 2026 •

Copy link
Copy Markdown

Summary

Official Codex requests can succeed directly against a codex_cli_only gateway but fail with HTTP 403 through a custom OpenCodex Responses provider. The existing four-name metadata allowlist drops the client's x-codex-window-id, and configuration validation prevents opting into it.

Allow providers to explicitly select x-codex-window-id and x-codex-installation-id through forwardClientHeaders. The existing transport copies only values actually supplied by the caller, including the native compact-to-Responses fallback. Forwarding remains off unless each name is selected; configured provider headers retain precedence. Arbitrary x-codex-* fields, credentials, attestations, and assertions remain excluded. This does not generate identities for probes or discovery.

Preserve the original user-agent and x-codex-app-version in the inbound Responses WebSocket handshake snapshot as well. Previously, selectForwardHeaders dropped both before rebuilding per-turn HTTP requests, so a key-auth provider could not receive them even when configured; HTTP ingress retained them. This keeps the same outbound provider policy and never generates a client identity.

Add regressions for key/noncanonical-forward routes, per-provider/per-header opt-in, absent identifiers, case normalization, header precedence, compact fallback, WebSocket-to-HTTP identity preservation, and blocked authentication metadata. Update the public configuration example and architecture contract. Identifiers can correlate requests, so the documentation calls out opting in only for a trusted destination that needs them.

Closes #8192.

Verification

Tested with Bun 1.4.4 on macOS ARM64, based on dev at 0a30c551304927c93c26a96c034bd39a166c7460. Commands below use the checkout-local Bun binary.

  • Before the source fix, node_modules/.bin/bun test ./tests/responses/responses-forward-client-headers.test.ts ./tests/responses/native-compaction-gateway.test.ts: 52 passed, 7 failed, demonstrating the rejected configuration, stripped metadata, and compact fallback regression.
  • After the fix, node_modules/.bin/bun run test ./tests/responses/responses-forward-client-headers.test.ts ./tests/responses/native-compaction-gateway.test.ts ./tests/server/agent-assertion-auth.test.ts ./tests/codex-integration/codex-installation-wire.test.ts: 82 passed, 0 failed, 447 assertions across four files.
  • The added WebSocket regression failed before the handshake fix (user-agent received as null) and passed afterward. Focused headers/WS/transport validation: node_modules/bun/bin/bun.exe test tests/responses/ws-endpoint.test.ts tests/responses/responses-forward-client-headers.test.ts tests/responses/responses-forward-transport-baseurl.test.ts tests/responses/codex-ws-handshake-validation.test.ts: 76 passed, 0 failed, 371 assertions. The real-peer tests required loopback access outside the sandbox.
  • node_modules/.bin/bun run typecheck: passed (2,316 files).
  • In docs-site, ../node_modules/.bin/bun run build: passed; 641 pages built and 93,146 internal links checked.
  • node_modules/.bin/bun run privacy:scan, node_modules/.bin/bun run structure:check, and git diff --check: passed.
  • Follow-up WS commit f0e97e8: node_modules/bun/bin/bun.exe scripts/test.ts --changed=dev outside the sandbox completed in 476.2 seconds: 49,312 passed, 228 skipped, 32 failed, 819,764 assertions across 2,192 files. This run is not green. Thirteen failures in five files were caused by invoking the runner without Bun on child-process PATH (Executable not found in $PATH: bun / command sink spawn failures). Re-running those five files using node_modules/.bin/bun run test passed 84 tests, 362 assertions, zero failures. The other 19 failing names match the earlier recorded unmodified-base failure set below; the baseline comparison itself was performed before the WS follow-up, not repeated for this commit.
  • node_modules/.bin/bun run test:changed, rerun outside the restricted sandbox: 49,324 passed, 228 skipped, 19 failed across 2,192 files (825,151 assertions, 493 seconds; exit 1). All 19 failing test cases also fail on the unmodified base in the same environment; this broader run is not green.
  • The initial sandboxed test:changed attempt could not open loopback listeners (EPERM / server-start failures) and reached the runner's 900-second limit (exit 124). The result above is the unrestricted retry, not the sandbox failure.

Full-suite scope exception: the changed-mode run already selected 2,192 of this checkout's roughly 2,950 test files and took over eight minutes, in addition to the earlier sandbox timeout. A separate full-suite run was not attempted. Validation of the remaining files and other platforms is still outstanding.

Baseline comparison for the 19 broader-suite failures

In a separate worktree at unmodified dev commit 0a30c551304927c93c26a96c034bd39a166c7460, using the same Bun and dependencies, ran all eight files containing those failures:

node_modules/.bin/bun run test \
  ./tests/adapters/anthropic/anthropic-fast-opt-in.test.ts \
  ./tests/codex-integration/catalog-async-lifetime.test.ts \
  ./tests/codex-integration/catalog-omit-disabled-native.test.ts \
  ./tests/codex-integration/codex-cli-update-apply.test.ts \
  ./tests/server/management-provider-validation.test.ts \
  ./tests/codex-integration/codex-composed-acceptance.test.ts \
  ./tests/cli/cli-connect-readiness.test.ts \
  ./tests/update/update-stop-first.test.ts

Result: 281 passed, 1 skipped, 19 failed, 2,142 assertions across 301 tests (76 seconds; exit 1). Comparing failing test names after removing durations gives 19 matching failures, zero PR-only failures, and zero base-only failures. These include provider-management 400 responses, native catalog/process expectations, and CLI lifecycle/update checks in this local environment. This comparison establishes that the observed failures also occur without this patch; it is not a claim that the broader suite passed or that every underlying cause was diagnosed.

The corresponding local runtime patch plus provider opt-in restored requests for both affected models through the official CLI; the desktop user also confirmed their original workflow now succeeds. Live credentials, captured identifier values, and private request contents are not included.

A real T3 Code app-server request reproduced the client-restriction 403 through the local proxy. Local header capture confirmed that T3 supplies its original UA/originator and x-codex-window-id. The WebSocket handshake regression covers preserving that original metadata without relabeling the client.

Keeping this PR in draft while broader validation and review readiness are completed. GitHub's hygiene check passed for commit 934891ef98e7ea35771bcfb498660d24a21b5e8f. The Cross-platform CI and Catalog async contracts runs require maintainer approval for this fork (action_required); neither is passing evidence. CodeRabbit skipped automatic review because the PR is a draft.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • Required local validation passed; commands, results, and any full-suite exception are documented.

  • I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions github-actions Bot added the bug Something isn't working label Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (0/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ Required local validation passed; commands, results, and any full-suite exception are documented.
  • ⬜ I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This PR stays in draft until every box above is ticked.

Hygiene

✅ Deterministic PR hygiene checks passed.

@ParsifalC ParsifalC changed the title fix(responses): allow opt-in forwarding of Codex client identifiers fix(responses): preserve Codex client metadata on routed requests Nov 5, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant