package executor import ( "bytes" "compress/gzip" "context" "encoding/base64" "encoding/json" "errors" "fmt" "io" "net/http" "net/http/httptest" "strings" "sync" "testing" "time" "github.com/andybalholm/brotli" "github.com/gin-gonic/gin" "github.com/klauspost/compress/zstd" claudeauth "github.com/router-for-me/CLIProxyAPI/v7/internal/auth/claude" "github.com/router-for-me/CLIProxyAPI/v7/internal/config" "github.com/router-for-me/CLIProxyAPI/v7/internal/registry" "github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor/helps" cliproxyauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/executor" sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator" "github.com/tidwall/gjson" "github.com/tidwall/sjson") func resetClaudeDeviceProfileCache() { helps.ResetClaudeDeviceProfileCache()} func claudeOAuthTestMetadata() map[string]any { return map[string]any{ "account_uuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", claudeauth.ClaudeDeviceIDsMetadataKey: []string{ "0000000000000000000000000000000000000000000000000000000000000000", }, }} func malformedClaudeTreeSignatureForClaudeExecutorTest() string { return base64.StdEncoding.EncodeToString([]byte{0x12, 0xFF, 0xFE, 0xFD})} func newClaudeHeaderTestRequest(t *testing.T, incoming http.Header) *http.Request { t.Helper() gin.SetMode(gin.TestMode) recorder := httptest.NewRecorder() ginCtx, _ := gin.CreateTestContext(recorder) ginReq := httptest.NewRequest(http.MethodPost, "http://localhost/v1/messages", nil) ginReq.Header = incoming.Clone() ginCtx.Request = ginReq req := httptest.NewRequest(http.MethodPost, "https://api.anthropic.com/v1/messages", nil) return req.WithContext(context.WithValue(req.Context(), "gin", ginCtx))} func assertClaudeFingerprint(t *testing.T, headers http.Header, userAgent, pkgVersion, runtimeVersion, osName, arch string) { t.Helper() if got := headers.Get("User-Agent"); got != userAgent { t.Fatalf("User-Agent = %q, want %q", got, userAgent) } if got := headers.Get("X-Stainless-Package-Version"); got != pkgVersion { t.Fatalf("X-Stainless-Package-Version = %q, want %q", got, pkgVersion) } if got := headers.Get("X-Stainless-Runtime-Version"); got != runtimeVersion { t.Fatalf("X-Stainless-Runtime-Version = %q, want %q", got, runtimeVersion) } if got := headers.Get("X-Stainless-Os"); got != osName { t.Fatalf("X-Stainless-Os = %q, want %q", got, osName) } if got := headers.Get("X-Stainless-Arch"); got != arch { t.Fatalf("X-Stainless-Arch = %q, want %q", got, arch) }} func TestApplyClaudeHeaders_FastModeBetaIsConditional(t *testing.T) { baseline := claudeCodeCLIBetas([]byte(`{"model":"claude-opus-5"}`), nil, false) betasWithoutFastMode := baseline betasWithFastMode := baseline + "," + claudeFastModeBeta tests := []struct { name string body string want string }{ { name: "omitted speed excludes fast mode beta", body: `{"model":"claude-opus-5"}`, want: betasWithoutFastMode, }, { name: "fast speed appends fast mode beta", body: `{"model":"claude-opus-5","speed":"fast"}`, want: betasWithFastMode, }, { name: "explicit body beta appends fast mode beta", body: `{"model":"claude-opus-5","betas":["fast-mode-2026-02-01"]}`, want: betasWithFastMode, }, } auth := &cliproxyauth.Auth{Attributes: map[string]string{"api_key": "key-fast-mode-beta", "cloak_mode": "always"}} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { extraBetas, body := extractAndRemoveBetas([]byte(tt.body)) req := newClaudeHeaderTestRequest(t, nil) if errApply := applyClaudeHeaders(req, auth, "key-fast-mode-beta", false, extraBetas, body, nil, nil, false); errApply != nil { t.Fatalf("applyClaudeHeaders() error = %v", errApply) } if got := req.Header.Get("Anthropic-Beta"); got != tt.want { t.Fatalf("Anthropic-Beta = %q, want %q", got, tt.want) } }) }} func assertClaudeCredentialIdentity(t *testing.T, body []byte, headers http.Header, deviceIDs []string, accountUUID string) { t.Helper() userID := gjson.GetBytes(body, "metadata.user_id").String() deviceID := gjson.Get(userID, "device_id").String() inPool := false for _, candidate := range deviceIDs { if deviceID == candidate { inPool = true break } } if !inPool { t.Fatalf("device_id = %q, want selected credential device pool entry", deviceID) } if got := gjson.Get(userID, "account_uuid").String(); got != accountUUID { t.Fatalf("account_uuid = %q, want selected credential account %q", got, accountUUID) } sessionID := gjson.Get(userID, "session_id").String() if sessionID == "" || sessionID != headers.Get("X-Claude-Code-Session-Id") { t.Fatalf("metadata session_id = %q, header session ID = %q", sessionID, headers.Get("X-Claude-Code-Session-Id")) } resigned, errResign := finalizeAnthropicMessagesBodyCCH(body, "") if errResign != nil { t.Fatalf("re-finalize Claude CCH: %v", errResign) } if !bytes.Equal(resigned, body) { t.Fatal("Claude CCH was calculated before final credential metadata rewrite") }} // assertClaudeCountTokensIdentity pins the count_tokens shape captured from real// Claude Code 2.1.220: the endpoint carries no metadata whatsoever. Anthropic// rejects the field there with "metadata: Extra inputs are not permitted", so the// credential identity travels only on the header and on the Messages endpoint.func assertClaudeCountTokensIdentity(t *testing.T, body []byte, headers http.Header) { t.Helper() if got := gjson.GetBytes(body, "metadata"); got.Exists() { t.Fatalf("count_tokens metadata = %s, want it absent", got.Raw) } if got := headers.Get("X-Claude-Code-Session-Id"); got == "" { t.Fatal("count_tokens is missing X-Claude-Code-Session-Id") } resigned, errResign := finalizeAnthropicMessagesBodyCCH(body, "") if errResign != nil { t.Fatalf("re-finalize Claude CCH: %v", errResign) } if !bytes.Equal(resigned, body) { t.Fatal("count_tokens CCH was calculated before the final body rewrite") }} func TestApplyClaudeHeaders_UsesConfiguredBaselineFingerprint(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.70 (external, cli)", PackageVersion: "0.80.0", RuntimeVersion: "v24.5.0", OS: "MacOS", Arch: "arm64", Timeout: "900", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-baseline", Attributes: map[string]string{ "api_key": "key-baseline", "cloak_mode": "always", "header:User-Agent": "evil-client/9.9", "header:X-Stainless-Os": "Linux", "header:X-Stainless-Arch": "x64", "header:X-Stainless-Package-Version": "9.9.9", }, } incoming := http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, } req := newClaudeHeaderTestRequest(t, incoming) applyClaudeHeaders(req, auth, "key-baseline", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, req.Header, "evil-client/9.9", "9.9.9", "v24.5.0", "Linux", "x64") if got := req.Header.Get("X-Stainless-Timeout"); got != "900" { t.Fatalf("X-Stainless-Timeout = %q, want %q", got, "900") }} func TestApplyClaudeHeaders_RejectsUnmeasuredClaudeCLIFingerprints(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.60 (external, cli)", PackageVersion: "0.70.0", RuntimeVersion: "v22.0.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-upgrade", Attributes: map[string]string{ "api_key": "key-upgrade", "cloak_mode": "always", }, } firstReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.62 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.74.0"}, "X-Stainless-Runtime-Version": []string{"v24.3.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(firstReq, auth, "key-upgrade", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, firstReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") thirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"lobe-chat/1.0"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Windows"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(thirdPartyReq, auth, "key-upgrade", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, thirdPartyReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") higherReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.63 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.75.0"}, "X-Stainless-Runtime-Version": []string{"v24.4.0"}, "X-Stainless-Os": []string{"MacOS"}, "X-Stainless-Arch": []string{"arm64"}, }) applyClaudeHeaders(higherReq, auth, "key-upgrade", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, higherReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") lowerReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.61 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.73.0"}, "X-Stainless-Runtime-Version": []string{"v24.2.0"}, "X-Stainless-Os": []string{"Windows"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(lowerReq, auth, "key-upgrade", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, lowerReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64")} func TestApplyClaudeHeaders_DoesNotDowngradeConfiguredBaselineOnFirstClaudeClient(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.70 (external, cli)", PackageVersion: "0.80.0", RuntimeVersion: "v24.5.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-baseline-floor", Attributes: map[string]string{ "api_key": "key-baseline-floor", }, } olderClaudeReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.62 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.74.0"}, "X-Stainless-Runtime-Version": []string{"v24.3.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(olderClaudeReq, auth, "key-baseline-floor", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, olderClaudeReq.Header, "claude-cli/2.1.70 (external, cli)", "0.80.0", "v24.5.0", "MacOS", "arm64") newerClaudeReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.71 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.81.0"}, "X-Stainless-Runtime-Version": []string{"v24.6.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(newerClaudeReq, auth, "key-baseline-floor", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, newerClaudeReq.Header, "claude-cli/2.1.70 (external, cli)", "0.80.0", "v24.5.0", "MacOS", "arm64")} func TestApplyClaudeHeaders_UpgradesCachedSoftwareFingerprintWhenBaselineAdvances(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true oldCfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.70 (external, cli)", PackageVersion: "0.80.0", RuntimeVersion: "v24.5.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } newCfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.77 (external, cli)", PackageVersion: "0.87.0", RuntimeVersion: "v24.8.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-baseline-reload", Attributes: map[string]string{ "api_key": "key-baseline-reload", "cloak_mode": "always", }, } officialReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.71 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.81.0"}, "X-Stainless-Runtime-Version": []string{"v24.6.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(officialReq, auth, "key-baseline-reload", false, nil, nil, oldCfg, nil, true) assertClaudeFingerprint(t, officialReq.Header, "claude-cli/2.1.70 (external, cli)", "0.80.0", "v24.5.0", "MacOS", "arm64") thirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(thirdPartyReq, auth, "key-baseline-reload", false, nil, nil, newCfg, nil, false) assertClaudeFingerprint(t, thirdPartyReq.Header, "claude-cli/2.1.77 (external, cli)", "0.87.0", "v24.8.0", "MacOS", "arm64")} func TestApplyClaudeHeaders_LearnsOfficialFingerprintAfterCustomBaselineFallback(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "my-gateway/1.0", PackageVersion: "custom-pkg", RuntimeVersion: "custom-runtime", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-custom-baseline-learning", Attributes: map[string]string{ "api_key": "key-custom-baseline-learning", "cloak_mode": "always", }, } thirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(thirdPartyReq, auth, "key-custom-baseline-learning", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, thirdPartyReq.Header, "my-gateway/1.0", "custom-pkg", "custom-runtime", "MacOS", "arm64") officialReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.77 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.87.0"}, "X-Stainless-Runtime-Version": []string{"v24.8.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(officialReq, auth, "key-custom-baseline-learning", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, officialReq.Header, "my-gateway/1.0", "custom-pkg", "custom-runtime", "MacOS", "arm64") postLearningThirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(postLearningThirdPartyReq, auth, "key-custom-baseline-learning", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, postLearningThirdPartyReq.Header, "my-gateway/1.0", "custom-pkg", "custom-runtime", "MacOS", "arm64")} func TestResolveClaudeDeviceProfile_RechecksCacheBeforeStoringCandidate(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.60 (external, cli)", PackageVersion: "0.70.0", RuntimeVersion: "v22.0.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-racy-upgrade", Attributes: map[string]string{ "api_key": "key-racy-upgrade", }, } lowPaused := make(chan struct{}) releaseLow := make(chan struct{}) var pauseOnce sync.Once var releaseOnce sync.Once helps.ClaudeDeviceProfileBeforeCandidateStore = func(candidate helps.ClaudeDeviceProfile) { if candidate.UserAgent != "claude-cli/2.1.60 (external, cli)" { return } pause := false pauseOnce.Do(func() { pause = true close(lowPaused) }) if pause { <-releaseLow } } t.Cleanup(func() { helps.ClaudeDeviceProfileBeforeCandidateStore = nil releaseOnce.Do(func() { close(releaseLow) }) }) lowResultCh := make(chan helps.ClaudeDeviceProfile, 1) go func() { lowResultCh <- helps.ResolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ "User-Agent": []string{"claude-cli/2.1.60 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.70.0"}, "X-Stainless-Runtime-Version": []string{"v22.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }, cfg) }() select { case <-lowPaused: case <-time.After(2 * time.Second): t.Fatal("timed out waiting for lower candidate to pause before storing") } highResult := helps.ResolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ "User-Agent": []string{"claude-cli/2.1.60 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.70.0"}, "X-Stainless-Runtime-Version": []string{"v22.0.0"}, "X-Stainless-Os": []string{"MacOS"}, "X-Stainless-Arch": []string{"arm64"}, }, cfg) releaseOnce.Do(func() { close(releaseLow) }) Lines 1–500 of 9329. Load more
package executor import ( "bytes" "compress/gzip" "context" "encoding/base64" "encoding/json" "errors" "fmt" "io" "net/http" "net/http/httptest" "strings" "sync" "testing" "time" "github.com/andybalholm/brotli" "github.com/gin-gonic/gin" "github.com/klauspost/compress/zstd" claudeauth "github.com/router-for-me/CLIProxyAPI/v7/internal/auth/claude" "github.com/router-for-me/CLIProxyAPI/v7/internal/config" "github.com/router-for-me/CLIProxyAPI/v7/internal/registry" "github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor/helps" cliproxyauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/executor" sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator" "github.com/tidwall/gjson" "github.com/tidwall/sjson" ) func resetClaudeDeviceProfileCache() { helps.ResetClaudeDeviceProfileCache() } func claudeOAuthTestMetadata() map[string]any { return map[string]any{ "account_uuid": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", claudeauth.ClaudeDeviceIDsMetadataKey: []string{ "0000000000000000000000000000000000000000000000000000000000000000", }, } } func malformedClaudeTreeSignatureForClaudeExecutorTest() string { return base64.StdEncoding.EncodeToString([]byte{0x12, 0xFF, 0xFE, 0xFD}) } func newClaudeHeaderTestRequest(t *testing.T, incoming http.Header) *http.Request { t.Helper() gin.SetMode(gin.TestMode) recorder := httptest.NewRecorder() ginCtx, _ := gin.CreateTestContext(recorder) ginReq := httptest.NewRequest(http.MethodPost, "http://localhost/v1/messages", nil) ginReq.Header = incoming.Clone() ginCtx.Request = ginReq req := httptest.NewRequest(http.MethodPost, "https://api.anthropic.com/v1/messages", nil) return req.WithContext(context.WithValue(req.Context(), "gin", ginCtx)) } func assertClaudeFingerprint(t *testing.T, headers http.Header, userAgent, pkgVersion, runtimeVersion, osName, arch string) { t.Helper() if got := headers.Get("User-Agent"); got != userAgent { t.Fatalf("User-Agent = %q, want %q", got, userAgent) } if got := headers.Get("X-Stainless-Package-Version"); got != pkgVersion { t.Fatalf("X-Stainless-Package-Version = %q, want %q", got, pkgVersion) } if got := headers.Get("X-Stainless-Runtime-Version"); got != runtimeVersion { t.Fatalf("X-Stainless-Runtime-Version = %q, want %q", got, runtimeVersion) } if got := headers.Get("X-Stainless-Os"); got != osName { t.Fatalf("X-Stainless-Os = %q, want %q", got, osName) } if got := headers.Get("X-Stainless-Arch"); got != arch { t.Fatalf("X-Stainless-Arch = %q, want %q", got, arch) } } func TestApplyClaudeHeaders_FastModeBetaIsConditional(t *testing.T) { baseline := claudeCodeCLIBetas([]byte(`{"model":"claude-opus-5"}`), nil, false) betasWithoutFastMode := baseline betasWithFastMode := baseline + "," + claudeFastModeBeta tests := []struct { name string body string want string }{ { name: "omitted speed excludes fast mode beta", body: `{"model":"claude-opus-5"}`, want: betasWithoutFastMode, }, { name: "fast speed appends fast mode beta", body: `{"model":"claude-opus-5","speed":"fast"}`, want: betasWithFastMode, }, { name: "explicit body beta appends fast mode beta", body: `{"model":"claude-opus-5","betas":["fast-mode-2026-02-01"]}`, want: betasWithFastMode, }, } auth := &cliproxyauth.Auth{Attributes: map[string]string{"api_key": "key-fast-mode-beta", "cloak_mode": "always"}} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { extraBetas, body := extractAndRemoveBetas([]byte(tt.body)) req := newClaudeHeaderTestRequest(t, nil) if errApply := applyClaudeHeaders(req, auth, "key-fast-mode-beta", false, extraBetas, body, nil, nil, false); errApply != nil { t.Fatalf("applyClaudeHeaders() error = %v", errApply) } if got := req.Header.Get("Anthropic-Beta"); got != tt.want { t.Fatalf("Anthropic-Beta = %q, want %q", got, tt.want) } }) } } func assertClaudeCredentialIdentity(t *testing.T, body []byte, headers http.Header, deviceIDs []string, accountUUID string) { t.Helper() userID := gjson.GetBytes(body, "metadata.user_id").String() deviceID := gjson.Get(userID, "device_id").String() inPool := false for _, candidate := range deviceIDs { if deviceID == candidate { inPool = true break } } if !inPool { t.Fatalf("device_id = %q, want selected credential device pool entry", deviceID) } if got := gjson.Get(userID, "account_uuid").String(); got != accountUUID { t.Fatalf("account_uuid = %q, want selected credential account %q", got, accountUUID) } sessionID := gjson.Get(userID, "session_id").String() if sessionID == "" || sessionID != headers.Get("X-Claude-Code-Session-Id") { t.Fatalf("metadata session_id = %q, header session ID = %q", sessionID, headers.Get("X-Claude-Code-Session-Id")) } resigned, errResign := finalizeAnthropicMessagesBodyCCH(body, "") if errResign != nil { t.Fatalf("re-finalize Claude CCH: %v", errResign) } if !bytes.Equal(resigned, body) { t.Fatal("Claude CCH was calculated before final credential metadata rewrite") } } // assertClaudeCountTokensIdentity pins the count_tokens shape captured from real // Claude Code 2.1.220: the endpoint carries no metadata whatsoever. Anthropic // rejects the field there with "metadata: Extra inputs are not permitted", so the // credential identity travels only on the header and on the Messages endpoint. func assertClaudeCountTokensIdentity(t *testing.T, body []byte, headers http.Header) { t.Helper() if got := gjson.GetBytes(body, "metadata"); got.Exists() { t.Fatalf("count_tokens metadata = %s, want it absent", got.Raw) } if got := headers.Get("X-Claude-Code-Session-Id"); got == "" { t.Fatal("count_tokens is missing X-Claude-Code-Session-Id") } resigned, errResign := finalizeAnthropicMessagesBodyCCH(body, "") if errResign != nil { t.Fatalf("re-finalize Claude CCH: %v", errResign) } if !bytes.Equal(resigned, body) { t.Fatal("count_tokens CCH was calculated before the final body rewrite") } } func TestApplyClaudeHeaders_UsesConfiguredBaselineFingerprint(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.70 (external, cli)", PackageVersion: "0.80.0", RuntimeVersion: "v24.5.0", OS: "MacOS", Arch: "arm64", Timeout: "900", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-baseline", Attributes: map[string]string{ "api_key": "key-baseline", "cloak_mode": "always", "header:User-Agent": "evil-client/9.9", "header:X-Stainless-Os": "Linux", "header:X-Stainless-Arch": "x64", "header:X-Stainless-Package-Version": "9.9.9", }, } incoming := http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, } req := newClaudeHeaderTestRequest(t, incoming) applyClaudeHeaders(req, auth, "key-baseline", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, req.Header, "evil-client/9.9", "9.9.9", "v24.5.0", "Linux", "x64") if got := req.Header.Get("X-Stainless-Timeout"); got != "900" { t.Fatalf("X-Stainless-Timeout = %q, want %q", got, "900") } } func TestApplyClaudeHeaders_RejectsUnmeasuredClaudeCLIFingerprints(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.60 (external, cli)", PackageVersion: "0.70.0", RuntimeVersion: "v22.0.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-upgrade", Attributes: map[string]string{ "api_key": "key-upgrade", "cloak_mode": "always", }, } firstReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.62 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.74.0"}, "X-Stainless-Runtime-Version": []string{"v24.3.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(firstReq, auth, "key-upgrade", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, firstReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") thirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"lobe-chat/1.0"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Windows"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(thirdPartyReq, auth, "key-upgrade", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, thirdPartyReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") higherReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.63 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.75.0"}, "X-Stainless-Runtime-Version": []string{"v24.4.0"}, "X-Stainless-Os": []string{"MacOS"}, "X-Stainless-Arch": []string{"arm64"}, }) applyClaudeHeaders(higherReq, auth, "key-upgrade", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, higherReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") lowerReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.61 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.73.0"}, "X-Stainless-Runtime-Version": []string{"v24.2.0"}, "X-Stainless-Os": []string{"Windows"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(lowerReq, auth, "key-upgrade", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, lowerReq.Header, "claude-cli/2.1.60 (external, cli)", "0.70.0", "v22.0.0", "MacOS", "arm64") } func TestApplyClaudeHeaders_DoesNotDowngradeConfiguredBaselineOnFirstClaudeClient(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.70 (external, cli)", PackageVersion: "0.80.0", RuntimeVersion: "v24.5.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-baseline-floor", Attributes: map[string]string{ "api_key": "key-baseline-floor", }, } olderClaudeReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.62 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.74.0"}, "X-Stainless-Runtime-Version": []string{"v24.3.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(olderClaudeReq, auth, "key-baseline-floor", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, olderClaudeReq.Header, "claude-cli/2.1.70 (external, cli)", "0.80.0", "v24.5.0", "MacOS", "arm64") newerClaudeReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.71 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.81.0"}, "X-Stainless-Runtime-Version": []string{"v24.6.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(newerClaudeReq, auth, "key-baseline-floor", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, newerClaudeReq.Header, "claude-cli/2.1.70 (external, cli)", "0.80.0", "v24.5.0", "MacOS", "arm64") } func TestApplyClaudeHeaders_UpgradesCachedSoftwareFingerprintWhenBaselineAdvances(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true oldCfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.70 (external, cli)", PackageVersion: "0.80.0", RuntimeVersion: "v24.5.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } newCfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.77 (external, cli)", PackageVersion: "0.87.0", RuntimeVersion: "v24.8.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-baseline-reload", Attributes: map[string]string{ "api_key": "key-baseline-reload", "cloak_mode": "always", }, } officialReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.71 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.81.0"}, "X-Stainless-Runtime-Version": []string{"v24.6.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(officialReq, auth, "key-baseline-reload", false, nil, nil, oldCfg, nil, true) assertClaudeFingerprint(t, officialReq.Header, "claude-cli/2.1.70 (external, cli)", "0.80.0", "v24.5.0", "MacOS", "arm64") thirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(thirdPartyReq, auth, "key-baseline-reload", false, nil, nil, newCfg, nil, false) assertClaudeFingerprint(t, thirdPartyReq.Header, "claude-cli/2.1.77 (external, cli)", "0.87.0", "v24.8.0", "MacOS", "arm64") } func TestApplyClaudeHeaders_LearnsOfficialFingerprintAfterCustomBaselineFallback(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "my-gateway/1.0", PackageVersion: "custom-pkg", RuntimeVersion: "custom-runtime", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-custom-baseline-learning", Attributes: map[string]string{ "api_key": "key-custom-baseline-learning", "cloak_mode": "always", }, } thirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(thirdPartyReq, auth, "key-custom-baseline-learning", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, thirdPartyReq.Header, "my-gateway/1.0", "custom-pkg", "custom-runtime", "MacOS", "arm64") officialReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"claude-cli/2.1.77 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.87.0"}, "X-Stainless-Runtime-Version": []string{"v24.8.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(officialReq, auth, "key-custom-baseline-learning", false, nil, nil, cfg, nil, true) assertClaudeFingerprint(t, officialReq.Header, "my-gateway/1.0", "custom-pkg", "custom-runtime", "MacOS", "arm64") postLearningThirdPartyReq := newClaudeHeaderTestRequest(t, http.Header{ "User-Agent": []string{"curl/8.7.1"}, "X-Stainless-Package-Version": []string{"0.10.0"}, "X-Stainless-Runtime-Version": []string{"v18.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }) applyClaudeHeaders(postLearningThirdPartyReq, auth, "key-custom-baseline-learning", false, nil, nil, cfg, nil, false) assertClaudeFingerprint(t, postLearningThirdPartyReq.Header, "my-gateway/1.0", "custom-pkg", "custom-runtime", "MacOS", "arm64") } func TestResolveClaudeDeviceProfile_RechecksCacheBeforeStoringCandidate(t *testing.T) { resetClaudeDeviceProfileCache() stabilize := true cfg := &config.Config{ ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ UserAgent: "claude-cli/2.1.60 (external, cli)", PackageVersion: "0.70.0", RuntimeVersion: "v22.0.0", OS: "MacOS", Arch: "arm64", StabilizeDeviceProfile: &stabilize, }, } auth := &cliproxyauth.Auth{ ID: "auth-racy-upgrade", Attributes: map[string]string{ "api_key": "key-racy-upgrade", }, } lowPaused := make(chan struct{}) releaseLow := make(chan struct{}) var pauseOnce sync.Once var releaseOnce sync.Once helps.ClaudeDeviceProfileBeforeCandidateStore = func(candidate helps.ClaudeDeviceProfile) { if candidate.UserAgent != "claude-cli/2.1.60 (external, cli)" { return } pause := false pauseOnce.Do(func() { pause = true close(lowPaused) }) if pause { <-releaseLow } } t.Cleanup(func() { helps.ClaudeDeviceProfileBeforeCandidateStore = nil releaseOnce.Do(func() { close(releaseLow) }) }) lowResultCh := make(chan helps.ClaudeDeviceProfile, 1) go func() { lowResultCh <- helps.ResolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ "User-Agent": []string{"claude-cli/2.1.60 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.70.0"}, "X-Stainless-Runtime-Version": []string{"v22.0.0"}, "X-Stainless-Os": []string{"Linux"}, "X-Stainless-Arch": []string{"x64"}, }, cfg) }() select { case <-lowPaused: case <-time.After(2 * time.Second): t.Fatal("timed out waiting for lower candidate to pause before storing") } highResult := helps.ResolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ "User-Agent": []string{"claude-cli/2.1.60 (external, cli)"}, "X-Stainless-Package-Version": []string{"0.70.0"}, "X-Stainless-Runtime-Version": []string{"v22.0.0"}, "X-Stainless-Os": []string{"MacOS"}, "X-Stainless-Arch": []string{"arm64"}, }, cfg) releaseOnce.Do(func() { close(releaseLow) })