mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
fix(channels): buddy 计费请求缺身份头 → 上游 401(逐行移植参考 checkinHeaders)
修好凭据读取后,余额端点仍报 HTTP 401。逐行核对参考 checkinHeaders (credits.ts) 后发现我们只发了 Authorization,而 buddy 要求身份标识头齐全: X-Domain: copilot.tencent.com (以产品配置为准,不用凭据里的 domain 快照) X-Product: SaaS (部署类型) X-Product-Code: codebuddy (产品码) User-Agent: CodeBuddyIDE/1.106.1 X-User-Id / X-Enterprise-Id / X-Tenant-Id(凭据携带时) 参考的注释特别警告 X-Domain 的方向:凭据里的 domain 是「登录时那个域名」的 快照,跨产品迁移后会指错区域,所以必须以产品端点为准。 ## 实现 - 平台级声明 headers_fn(accessToken, cred) → 返回请求头表;buddy 据此逐行移植。 - fetchAccountJSON 增加头钩子位:spec 自己的 headers_fn 优先,否则回退平台级。 未声明的平台仍走通用默认头(Bearer + JSON),不改变既有行为。 - set_endpoints 补齐 checkin_status / balance 端点覆盖(此前只覆盖旧的 plat.checkin,buddy 这类平台无从改指,自动化测试也指不到假上游)。 端点覆盖是参考明确的产品配置能力,也是测试缝。 ## 判据 TestBuddyBillingHeadersMatchReference:把 buddy 余额端点指到本地假上游, 断言四个必备身份头逐字段正确。变异:改名 headers_fn → 立即 FAIL(已实测)。 go test ./internal/core/ 与 ./internal/lua/ 全绿。
This commit is contained in:
@ -5,6 +5,10 @@ import (
|
||||
"testing"
|
||||
|
||||
"llmsproxy/internal/lua"
|
||||
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
// channels_pool_test:对齐参考 account.* / model.* / provider.* 契约的行为测试。
|
||||
@ -320,3 +324,47 @@ func TestChannelsExtendedRPCBehavior(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestBuddyBillingHeadersMatchReference 锁定 buddy 计费请求的头(逐行移植参考
|
||||
// checkinHeaders)。真实缺陷:实现只发 Authorization,上游直接 401 —— 修好后
|
||||
// 账号能读到凭据但余额仍失败,运维看到的仍是「拿不到账号信息」。
|
||||
func TestBuddyBillingHeadersMatchReference(t *testing.T) {
|
||||
_, ps := poolCore(t)
|
||||
|
||||
var got map[string]string
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
got = map[string]string{}
|
||||
for k := range r.Header {
|
||||
got[k] = r.Header.Get(k)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprint(w, `{"data":{"totalCredit":42}}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
// 把 buddy 的余额/签到端点指到本地假上游
|
||||
invoke(t, ps, "set_endpoints", fmt.Sprintf(
|
||||
`{"platform":"buddy","balance":{"url":%q,"method":"POST","body":"{}"}}`, ts.URL))
|
||||
m := invoke(t, ps, "account_add", `{"platform":"buddy","credential":"BD-AT","nickname":"b"}`)
|
||||
if m["ok"] != true {
|
||||
t.Fatalf("account_add: %v", m)
|
||||
}
|
||||
invoke(t, ps, "credits_balances", `{"platform":"buddy"}`)
|
||||
|
||||
if got == nil {
|
||||
t.Fatal("余额请求未发出")
|
||||
}
|
||||
// 参考 checkinHeaders 的必备身份头(缺一个上游就 401)
|
||||
want := map[string]string{
|
||||
"Authorization": "Bearer BD-AT",
|
||||
"X-Domain": "copilot.tencent.com",
|
||||
"X-Product": "SaaS",
|
||||
"X-Product-Code": "codebuddy",
|
||||
"User-Agent": "CodeBuddyIDE/1.106.1",
|
||||
}
|
||||
for k, v := range want {
|
||||
if got[k] != v {
|
||||
t.Errorf("头 %s = %q, 期望 %q(buddy 计费端点缺它会被上游 401)", k, got[k], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user