fix(gateway): filter anthropic-beta on the Vertex Anthropic path + drop cch sign (#3358)#3375
Open
StarryKira wants to merge 4 commits into
Open
fix(gateway): filter anthropic-beta on the Vertex Anthropic path + drop cch sign (#3358)#3375StarryKira wants to merge 4 commits into
StarryKira wants to merge 4 commits into
Conversation
…-Shaw#3358) Vertex AI's Anthropic endpoint rejects unknown anthropic-beta tokens with HTTP 400. buildUpstreamRequestAnthropicVertex forwarded the client header verbatim via the allowedHeaders whitelist, so recent Claude Code CLIs that send advisor-tool-2026-03-01, prompt-caching-scope-2026-01-05, redact-thinking-2026-02-12 and thinking-token-count-2026-05-13 broke every Vertex service_account request, even though plain account-test requests passed. This is the only upstream builder that bypassed beta filtering: the OAuth/API-key path uses computeFinalAnthropicBeta and the Bedrock path uses filterBedrockBetaTokens. Close the gap with a Vertex-specific whitelist (vertexSupportedBetaTokens) mirroring bedrockSupportedBetaTokens, plus the existing BetaPolicy block check: - evaluateBetaPolicy block check (symmetric to resolveBedrockBetaTokensForRequest) - filterVertexBetaTokens strips policy-filtered + non-whitelisted tokens - body context_management sanitize now keys on the final beta, not the raw client value - overwrite the anthropic-beta header after the whitelist copy loop with the final value Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers the Wei-Shaw#3358 fix: - StripsUnsupportedClaudeCodeTokens reproduces the prod 400 — the four Vertex- rejected tokens (advisor-tool, prompt-caching-scope, redact-thinking, thinking-token-count) plus the identity betas are stripped while whitelisted tokens survive. Fails before the builder fix, passes after. - DropsHeaderWhenAllUnsupported: no anthropic-beta header is sent when every client token is filtered out. - BodySanitizeKeysOnFinalBeta: body.context_management is stripped based on the final beta, not the raw client value. - BlocksViaBetaPolicy: an admin block rule on a Vertex account returns BetaBlockedError. - TestFilterVertexBetaTokens unit-tests whitelist/drop-set/dedupe/empty. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recent Claude Code CLI versions no longer emit the cch=... signature field in their x-anthropic-billing-header system block (issue Wei-Shaw#3358). sub2api still injected cch=00000 when mimicking Claude Code for OAuth accounts and optionally signed it, so mimicked requests now diverge from real CLI traffic — the opposite of what the mimicry is for. - buildBillingAttributionText emits the block without the cch=00000 segment; cc_version + cc_entrypoint=cli are kept (detection and Anthropic's first-party signal rely on the block, not on cch). - Retire signing: remove the two enableCCH signBillingHeaderCCH call sites in buildUpstreamRequest / buildCountTokensRequest and delete the now-dead signBillingHeaderCCH, cchPlaceholderRe, cchSeed, xxHash64Seeded helpers. - enable_cch_signing is now a documented no-op (kept for backward compat). - Drop the obsolete signing tests (TestSignBillingHeaderCCH, TestXXHash64Seeded, TestSanitizeMustBeBeforeCCHSigning_HashConsistency) and update the prompt test to assert the injected block no longer carries cch=. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… cch) Locks in that Claude Code detection keys on the billing block prefix + cc_entrypoint=cli, not on the cch field that the new CLI (and now our own mimicry) no longer sends: - BillingBlockRecognizedWithoutCCH: an identity-prose-less sub-request whose system block is `x-anthropic-billing-header: cc_version=...; cc_entrypoint=cli;` (no cch) is still detected as Claude Code. - NoCCHBlockStillRequiresClaudeCodeUA: dropping cch did not loosen detection — a non-claude-cli UA is still rejected, so ClaudeCodeOnly groups can't be spoofed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #3358. Recent Claude Code CLI versions changed their request shape, which broke two independent gateway paths:
anthropic-betatokens break Vertex. Vertex AI's Anthropic endpoint returns HTTP 400 for unknown beta tokens (advisor-tool-2026-03-01,prompt-caching-scope-2026-01-05,redact-thinking-2026-02-12,thinking-token-count-2026-05-13).buildUpstreamRequestAnthropicVertexforwarded the clientanthropic-betaheader verbatim via theallowedHeaderswhitelist — it was the only upstream builder with no beta filtering (the OAuth/API-key path usescomputeFinalAnthropicBeta; Bedrock usesfilterBedrockBetaTokens). This is the same gap that the closed PR fix(gateway): apply BetaPolicy filter / block on the Vertex Anthropic path #3150 identified.cchsign. Newer CLIs no longer emit thecch=…signature field in theirx-anthropic-billing-headersystem block. sub2api still injectedcch=00000;(and optionally signed it) when mimicking Claude Code for OAuth accounts, so mimicked requests now diverge from real CLI traffic.Changes (4 focused commits)
fix(gateway): filter anthropic-beta on the Vertex Anthropic path— adds avertexSupportedBetaTokenswhitelist (mirrorsbedrockSupportedBetaTokens) +filterVertexBetaTokens. InbuildUpstreamRequestAnthropicVertex: runs the BetaPolicy block check (symmetric toresolveBedrockBetaTokensForRequest), strips policy-filtered + non-whitelisted tokens, drives the bodycontext_managementsanitize off the final beta, and overwrites theanthropic-betaheader after the whitelist copy loop.test(gateway): Vertex anthropic-beta filtering— reproduces the prod 400 (the four rejected tokens stripped, whitelisted ones kept), header drop when all stripped, body sanitize keyed on final beta, BetaPolicy block returnsBetaBlockedError, plus helper unit tests.fix(claude-mimicry): drop the cch sign to match new Claude Code CLI—buildBillingAttributionTextno longer emitscch=00000;(keepscc_version+cc_entrypoint=cli, which detection relies on); retires the now-deadsignBillingHeaderCCH/xxHash64Seededhelpers and both call sites;enable_cch_signingbecomes a documented no-op.test(claude-code): detection recognizes the new-CLI billing block (no cch)— locks in that detection keys oncc_entrypoint=cli, notcch, and that droppingcchdid not loosen the UA gate (ClaudeCodeOnly groups can't be spoofed).Notes
context-1m,context-management,fine-grained-tool-streaming,interleaved-thinking) and structured so tokens are trivial to add. Excludes the four 400-causing tokens and the identity betas (claude-code-20250219/oauth-2025-04-20) that Vertex service_account doesn't need.cch=field only — the billing block andcc_entrypoint=cliare retained.Test
🤖 Generated with Claude Code