mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-21 05:45:26 +08:00
Recent Claude Code CLI versions no longer emit the cch=... signature field in their x-anthropic-billing-header system block (issue #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>
68 lines
2.1 KiB
Go
68 lines
2.1 KiB
Go
package service
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestSyncBillingHeaderVersion(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
body string
|
|
userAgent string
|
|
wantSub string // substring expected in result
|
|
unchanged bool // expect body to remain the same
|
|
}{
|
|
{
|
|
name: "replaces cc_version preserving message-derived suffix",
|
|
body: `{"system":[{"type":"text","text":"x-anthropic-billing-header: cc_version=2.1.81.df2; cc_entrypoint=cli; cch=00000;"},{"type":"text","text":"You are Claude Code.","cache_control":{"type":"ephemeral"}}],"messages":[]}`,
|
|
userAgent: "claude-cli/2.1.22 (external, cli)",
|
|
wantSub: "cc_version=2.1.22.df2",
|
|
},
|
|
{
|
|
name: "no billing header in system",
|
|
body: `{"system":[{"type":"text","text":"You are Claude Code."}],"messages":[]}`,
|
|
userAgent: "claude-cli/2.1.22",
|
|
unchanged: true,
|
|
},
|
|
{
|
|
name: "no system field",
|
|
body: `{"messages":[]}`,
|
|
userAgent: "claude-cli/2.1.22",
|
|
unchanged: true,
|
|
},
|
|
{
|
|
name: "user-agent without version",
|
|
body: `{"system":[{"type":"text","text":"x-anthropic-billing-header: cc_version=2.1.81; cc_entrypoint=cli; cch=00000;"}],"messages":[]}`,
|
|
userAgent: "Mozilla/5.0",
|
|
unchanged: true,
|
|
},
|
|
{
|
|
name: "empty user-agent",
|
|
body: `{"system":[{"type":"text","text":"x-anthropic-billing-header: cc_version=2.1.81; cc_entrypoint=cli; cch=00000;"}],"messages":[]}`,
|
|
userAgent: "",
|
|
unchanged: true,
|
|
},
|
|
{
|
|
name: "version already matches",
|
|
body: `{"system":[{"type":"text","text":"x-anthropic-billing-header: cc_version=2.1.22; cc_entrypoint=cli; cch=00000;"}],"messages":[]}`,
|
|
userAgent: "claude-cli/2.1.22",
|
|
unchanged: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := syncBillingHeaderVersion([]byte(tt.body), tt.userAgent)
|
|
if tt.unchanged {
|
|
assert.Equal(t, tt.body, string(result), "body should remain unchanged")
|
|
} else {
|
|
assert.Contains(t, string(result), tt.wantSub)
|
|
// Ensure old semver is gone
|
|
assert.NotContains(t, string(result), "cc_version=2.1.81")
|
|
}
|
|
})
|
|
}
|
|
}
|