Skip to content

fix(claude): isolate native passthrough credentials - #1536

Merged
lidge-jun merged 2 commits into
lidge-jun:devfrom
luvs01:agent/isolate-claude-passthrough-credentials
Aug 12, 2026
Merged

fix(claude): isolate native passthrough credentials#1536
lidge-jun merged 2 commits into
lidge-jun:devfrom
luvs01:agent/isolate-claude-passthrough-credentials

Conversation

@luvs01

@luvs01 luvs01 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • require the dedicated x-opencodex-api-key admission header before native Anthropic passthrough on a non-loopback listener
  • keep Authorization and x-api-key as upstream credential domains on that branch and strip any exact OpenCodex admission secret before forwarding
  • reject comma-joined credential headers so duplicate fields cannot hide an admission secret behind a provider credential
  • use the effective per-listener admission policy for both Messages and count_tokens, preserving loopback behavior and routed Messages compatibility
  • document the boundary in the English source and all shipped translations

Coverage includes both safe credential layouts: provider credentials in Authorization with proxy admission elsewhere, and exact proxy admission in Authorization with a real Anthropic credential in x-api-key.

Verification

  • Bun 1.3.14: focused exposed-listener credential-boundary regression passed (1/1, 16 assertions)
  • Bun 1.4.0-canary.1: the same focused regression passed (1/1, 16 assertions)
  • Bun 1.4.0-canary.1: the complete Claude native passthrough file passed before the final fixture-only privacy rename
  • Bun 1.3.14: the complete file passed 9 unaffected/new tests; one existing native SSE body assertion was empty once, then passed in isolated rerun (1/1, 21 assertions)
  • TypeScript 7.0.2 tsc --noEmit passed under Bun 1.3.14 and Bun 1.4.0-canary.1
  • bun run privacy:scan passed under both Bun runtimes
  • docs-site: bun install --frozen-lockfile and bun run build passed (265 pages)
  • git diff --check passed
  • follow-up listener-policy regression passed under Bun 1.3.14 and Bun 1.4.0-canary.1 (17/17 on each runtime)
  • all three correct CodeRabbit findings were fixed in 884e7fe, answered, and resolved
  • latest-dev rebase preserved both validated patch ids; the intervening provider-management commit had no changed-path overlap
  • independent production and test/docs reviews found no remaining P0-P3 findings

Focused dual-runtime tests, typecheck, privacy, docs build, diff validation, and independent review were used instead of duplicating the full GitHub CI workload locally.

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:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened native Claude/Anthropic passthrough authentication for non-loopback connections.
    • Requires valid proxy admission through the dedicated x-opencodex-api-key header when applicable.
    • Keeps Anthropic credentials separate from proxy credentials and removes proxy secrets before forwarding.
    • Rejects ambiguous or duplicate credential headers instead of forwarding them.
    • Filters additional non-forwardable headers, including host, content-length, and accept-encoding.
  • Documentation

    • Updated Claude passthrough, server configuration, and proxy format guidance across supported languages.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added bug Something isn't working review-ready labels Aug 12, 2026
@github-actions
github-actions Bot marked this pull request as ready for review August 12, 2026 12:42
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request is already Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently. If no CodeRabbit review appears, comment @coderabbitai review to request one.
Maintainers: @lidge-jun @Ingwannu @Wibias

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Native Anthropic passthrough now requires dedicated proxy admission on non-loopback listeners. It validates credentials, removes proxy secrets, rejects ambiguous headers, propagates listener policy, and documents the behavior across supported languages.

Changes

Native Anthropic passthrough

Layer / File(s) Summary
Passthrough authentication and header filtering
src/server/claude-messages.ts
Credential parsing rejects ambiguous values, requires dedicated admission on exposed listeners, removes proxy secrets, and filters forwarded headers. Messages and count_tokens use RequestPolicyView.
Policy propagation and integration coverage
src/server/index.ts, tests/claude-native-passthrough.test.ts, tests/loopback-listener-admission.test.ts
Server routing passes listener policy to Claude handlers. Tests cover admission requirements, credential isolation, header stripping, rejected duplicate credentials, and policy-aware CORS handling.
Multilingual passthrough documentation
docs-site/src/content/docs/**/guides/claude-code.md, docs-site/src/content/docs/**/reference/configuration/server.md, docs-site/src/content/docs/**/reference/proxy-formats.md
Guide and reference pages document admission requirements, credential separation, header filtering, count_tokens coverage, and fail-closed handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ClaudeHandlers
  participant RequestPolicyView
  participant AnthropicUpstream
  Client->>ClaudeHandlers: Send Messages or count_tokens request
  ClaudeHandlers->>RequestPolicyView: Validate listener admission
  RequestPolicyView-->>ClaudeHandlers: Return admission decision
  ClaudeHandlers->>ClaudeHandlers: Validate and filter credentials
  ClaudeHandlers->>AnthropicUpstream: Forward filtered request
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: isolating credentials used by native Claude passthrough.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/ko/guides/claude-code.md`:
- Around line 84-86: Clarify the passthrough conditions in
docs-site/src/content/docs/ko/guides/claude-code.md lines 84-86,
docs-site/src/content/docs/ru/guides/claude-code.md lines 64-66, and
docs-site/src/content/docs/zh-cn/guides/claude-code.md lines 58-60 so each
explicitly states that the token following “Bearer” starts with “sk-ant-”,
rather than implying the complete Authorization header does. Preserve the
distinction between native Anthropic OAuth/API-key authentication and
passthrough behavior in all three localized guides.

In `@docs-site/src/content/docs/reference/configuration/server.md`:
- Around line 63-67: Update the admission-policy paragraphs to document both
`/v1/messages` and `/v1/messages/count_tokens`, preserving the existing policy
details. Apply this change in
docs-site/src/content/docs/reference/configuration/server.md lines 63-67,
docs-site/src/content/docs/ko/reference/configuration/server.md lines 57-60, and
docs-site/src/content/docs/ru/reference/configuration/server.md lines 65-69.

In `@src/server/index.ts`:
- Around line 1243-1244: Update the withCors call wrapping handleClaudeMessages
in the /v1/messages branch to use the request’s policy instead of the shared
config, matching the count_tokens branch and ensuring CORS decisions use the
correct listener view.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c4bf0697-c89c-4077-8c7a-138a3b427ef4

📥 Commits

Reviewing files that changed from the base of the PR and between 9e777fb and 1768e78.

📒 Files selected for processing (21)
  • docs-site/src/content/docs/guides/claude-code.md
  • docs-site/src/content/docs/ja/guides/claude-code.md
  • docs-site/src/content/docs/ja/reference/configuration/server.md
  • docs-site/src/content/docs/ja/reference/proxy-formats.md
  • docs-site/src/content/docs/ko/guides/claude-code.md
  • docs-site/src/content/docs/ko/reference/configuration/server.md
  • docs-site/src/content/docs/ko/reference/proxy-formats.md
  • docs-site/src/content/docs/reference/configuration/server.md
  • docs-site/src/content/docs/reference/proxy-formats.md
  • docs-site/src/content/docs/ru/guides/claude-code.md
  • docs-site/src/content/docs/ru/reference/configuration/server.md
  • docs-site/src/content/docs/ru/reference/proxy-formats.md
  • docs-site/src/content/docs/zh-cn/guides/claude-code.md
  • docs-site/src/content/docs/zh-cn/reference/configuration/server.md
  • docs-site/src/content/docs/zh-cn/reference/proxy-formats.md
  • docs-site/src/content/docs/zh-tw/guides/claude-code.md
  • docs-site/src/content/docs/zh-tw/reference/configuration/server.md
  • docs-site/src/content/docs/zh-tw/reference/proxy-formats.md
  • src/server/claude-messages.ts
  • src/server/index.ts
  • tests/claude-native-passthrough.test.ts

Comment thread docs-site/src/content/docs/ko/guides/claude-code.md
Comment thread docs-site/src/content/docs/reference/configuration/server.md Outdated
Comment thread src/server/index.ts
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] The readiness gate is complete for head SHA 1768e78eb67dfa031d2e525ddaf301034cc790d2.

I am replying to the latest comment only. The earlier comment chain is not available. This status does not request a review. Post @coderabbitai review to start one.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions The readiness gate is complete for head SHA 1768e78eb67dfa031d2e525ddaf301034cc790d2.

No review was requested. Post @coderabbitai review to start a review.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

@luvs01
luvs01 force-pushed the agent/isolate-claude-passthrough-credentials branch from 1768e78 to 884e7fe Compare August 12, 2026 13:35
@github-actions
github-actions Bot marked this pull request as draft August 12, 2026 13:36
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions The readiness gate is complete for head SHA 1768e78eb67dfa031d2e525ddaf301034cc790d2.

No CodeRabbit review was requested. Post @coderabbitai review to start a review.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

@github-actions
github-actions Bot marked this pull request as ready for review August 12, 2026 13:40
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The PR is marked Ready for Review at head SHA 884e7fe7492bfd1e6ca4d1662b7cd478adc90525. I will review the changes.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] The readiness gate is complete for head SHA 884e7fe7492bfd1e6ca4d1662b7cd478adc90525. A CodeRabbit review was already triggered for this head SHA.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/ja/reference/configuration/server.md`:
- Line 56: Update the Japanese sentence in the configuration documentation so it
states that candidate values are compared in constant time, using wording
equivalent to「候補値は定数時間で比較されます」. Keep the surrounding explanation unchanged and
align it with the English source’s constant-time comparison guarantee.

In `@tests/loopback-listener-admission.test.ts`:
- Around line 70-75: Extend the loopback listener assertions for the two source
branches covering handleClaudeCountTokens and handleClaudeMessages, verifying
each exact handler call passes policy rather than config. Keep the existing
withCors assertions so both handler policy propagation and CORS policy
propagation remain covered.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a6ebff89-c874-4ddb-81c5-bd5f4f1737ed

📥 Commits

Reviewing files that changed from the base of the PR and between 1768e78 and 884e7fe.

📒 Files selected for processing (14)
  • docs-site/src/content/docs/guides/claude-code.md
  • docs-site/src/content/docs/ja/guides/claude-code.md
  • docs-site/src/content/docs/ja/reference/configuration/server.md
  • docs-site/src/content/docs/ko/guides/claude-code.md
  • docs-site/src/content/docs/ko/reference/configuration/server.md
  • docs-site/src/content/docs/reference/configuration/server.md
  • docs-site/src/content/docs/ru/guides/claude-code.md
  • docs-site/src/content/docs/ru/reference/configuration/server.md
  • docs-site/src/content/docs/zh-cn/guides/claude-code.md
  • docs-site/src/content/docs/zh-cn/reference/configuration/server.md
  • docs-site/src/content/docs/zh-tw/guides/claude-code.md
  • docs-site/src/content/docs/zh-tw/reference/configuration/server.md
  • src/server/index.ts
  • tests/loopback-listener-admission.test.ts

| `/v1/messages/count_tokens` |受け入れられました |受け入れられました |受け入れられました |
| `/v1/models` |受け入れられました |受け入れられました |受け入れられました |

応答とチャット完了では、Codex Direct パススルーの可能性のために `Authorization` を予約しているため、そこでは専用のアドミッション ヘッダーのみが受け入れられます。ダッシュボードで生成された `apiKeys` は、起動後に環境トークンを置き換える可能性があります。候補は一定時間内に比較されます。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Preserve the constant-time comparison guarantee.

Line 56 says 候補は一定時間内に比較されます. This describes a time window, not constant-time comparison. The English source states that candidate credentials are compared in constant time. Use Japanese wording such as 候補値は定数時間で比較されます.

Proposed wording
-候補は一定時間内に比較されます。
+候補値は定数時間で比較されます。

Based on the English source in docs-site/src/content/docs/reference/configuration/server.md Lines 60-62, the intended property is constant-time comparison. As per path instructions: “Check that user-facing docs stay in sync with actual CLI/API behavior and that translated locale pages (ja, ko, ru, zh-cn) are not left contradicting the English source.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
応答とチャット完了では、Codex Direct パススルーの可能性のために `Authorization` を予約しているため、そこでは専用のアドミッション ヘッダーのみが受け入れられます。ダッシュボードで生成された `apiKeys` は、起動後に環境トークンを置き換える可能性があります。候補は一定時間内に比較されます
応答とチャット完了では、Codex Direct パススルーの可能性のために `Authorization` を予約しているため、そこでは専用のアドミッション ヘッダーのみが受け入れられます。ダッシュボードで生成された `apiKeys` は、起動後に環境トークンを置き換える可能性があります。候補値は定数時間で比較されます
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-site/src/content/docs/ja/reference/configuration/server.md` at line 56,
Update the Japanese sentence in the configuration documentation so it states
that candidate values are compared in constant time, using wording equivalent
to「候補値は定数時間で比較されます」. Keep the surrounding explanation unchanged and align it
with the English source’s constant-time comparison guarantee.

Source: Path instructions

Comment on lines +70 to +75
for (const branch of [
source.slice(countTokensStart, messagesStart),
source.slice(messagesStart, chatStart),
]) {
expect(branch).toContain("req,\n policy,\n ));");
expect(branch).not.toContain("req,\n config,\n ));");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Assert handler policy propagation as well as CORS policy propagation.

Lines 70-75 check only the final withCors argument. The test will pass if either handler regresses from policy to config, even though native passthrough then receives the wrong listener policy. Add assertions for the exact handleClaudeCountTokens(..., policy) and handleClaudeMessages(..., policy) calls.

🛡️ Proposed assertions
+    expect(source.slice(countTokensStart, messagesStart)).toContain(
+      "await handleClaudeCountTokens(req, config, policy)",
+    );
+    expect(source.slice(messagesStart, chatStart)).toContain(
+      "await handleClaudeMessages(req, config, logCtx, { requestId, start, turnAdmissionLease }, policy)",
+    );

As per path instructions, tests for changed server behavior must provide focused regression coverage. The supplied src/server/claude-messages.ts contract shows that requestPolicy is a separate native-passthrough input.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const branch of [
source.slice(countTokensStart, messagesStart),
source.slice(messagesStart, chatStart),
]) {
expect(branch).toContain("req,\n policy,\n ));");
expect(branch).not.toContain("req,\n config,\n ));");
expect(source.slice(countTokensStart, messagesStart)).toContain(
"await handleClaudeCountTokens(req, config, policy)",
);
expect(source.slice(messagesStart, chatStart)).toContain(
"await handleClaudeMessages(req, config, logCtx, { requestId, start, turnAdmissionLease }, policy)",
);
for (const branch of [
source.slice(countTokensStart, messagesStart),
source.slice(messagesStart, chatStart),
]) {
expect(branch).toContain("req,\n policy,\n ));");
expect(branch).not.toContain("req,\n config,\n ));");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/loopback-listener-admission.test.ts` around lines 70 - 75, Extend the
loopback listener assertions for the two source branches covering
handleClaudeCountTokens and handleClaudeMessages, verifying each exact handler
call passes policy rather than config. Keep the existing withCors assertions so
both handler policy propagation and CORS policy propagation remain covered.

Source: Path instructions

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions The readiness gate is complete for 884e7fe7492bfd1e6ca4d1662b7cd478adc90525.

A CodeRabbit review was already triggered for this head SHA. No additional review request is needed.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] The readiness gate is complete for head SHA 884e7fe7492bfd1e6ca4d1662b7cd478adc90525.

A CodeRabbit review was already triggered for this head SHA. No additional review request is required.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

1 similar comment
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] The readiness gate is complete for head SHA 884e7fe7492bfd1e6ca4d1662b7cd478adc90525.

A CodeRabbit review was already triggered for this head SHA. No additional review request is required.


🧠 Learnings used
Learnt from: Wibias
Repo: lidge-jun/opencodex PR: 986
File: .github/workflows/enforce-pr-target.yml:631-636
Timestamp: 2026-08-04T06:41:30.089Z
Learning: For the PR readiness gate in `.github/workflows/enforce-pr-target.yml`, the required scope is to bind contributor checklist completion and maintainer notification to the exact PR head SHA, then reset them after a new head commit. Maintainer approval staleness is separate from this gate and should be enforced by GitHub branch protection, such as `dismiss-stale-reviews` or `require_last_push_approval`, when configured for `dev`.

You are interacting with an AI system.

@lidge-jun

Copy link
Copy Markdown
Owner

Security review complete — LAND. Independent threat-model review plus my own verification of the listener boundary.

The admission decision comes from which Bun.serve instance received the request (src/server/index.ts:710-726), not from Host, X-Forwarded-For, or any peer-supplied header. That is the detail that makes this defensible: the usual spoofing routes into a "is this loopback?" check do not exist here. The optional unauthenticated listener is physically bound to 127.0.0.1, and 0.0.0.0, ::, and IPv4-mapped addresses all remain non-loopback public policy.

Verified against the three questions:

  • Does the defense close the path? Yes. Dedicated admission is checked before native selection (claude-messages.ts:125-142), and admission secrets are filtered while constructing outbound headers (:145-150, :371-375), covering both Messages and count_tokens.
  • Any bypass? None found. Configured-secret comparison reaches timingSafeEqual (auth-cors.ts:259-264), so it is not a naive string compare. Duplicate headers are comma-joined by Bun and rejected outright (:105-115) rather than parsed — failing closed on an ambiguous credential is the right call, since that is exactly where a secret could hide behind a provider credential.
  • Any legitimate use broken? Yes, deliberately: existing non-loopback native-passthrough clients must now send x-opencodex-api-key. That is the point of the change and it is documented in the English source and all changed translations. Loopback behavior is unchanged.

Verification on a Linux runner (Bun 1.3.14): red-before 26 pass / 2 fail — the exposed listener previously accepted native passthrough without the dedicated header; at head 70 pass / 0 fail across the passthrough, loopback-admission, and messages-endpoint suites; bun x tsc --noEmit exit 0; bun run privacy:scan pass; docs build 265 pages.

@lidge-jun
lidge-jun merged commit 5ef38fe into lidge-jun:dev Aug 12, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants