package lua import ( "testing" ) // ★ P1-3(**只确认不改**):channels-gemini 的「静态身份五头 + 内核兜底 Bearer」 // 本来就是**对的**,不需要像 zcode 那样补 x-api-key。 // // 这是本轮唯一一个"看起来同型、实际不是缺陷"的渠道,所以把它钉成判据, // 免得下一轮有人照 P1-1 的模子给它也改一遍(那会把它弄坏)。 // // 证据链(两条独立来源一致): // // ① 参考实现 vendor/channel-pack/src/gemini.ts:353-366 geminiHeaders() // headers.set('Authorization', `Bearer ${credential.access_token}`) // 再逐字注入 GEMINI_IDENTITY_HEADERS 五头 // 并**刻意不注入** x-goog-api-key(源注释:原版不带) // ② 参考 src/gemini.ts:110-117 的 GEMINI_IDENTITY_HEADERS 与我们 // adapter.headers 的五头逐字相同(UA / x-client-name / x-client-version / // x-machine-id / x-vscode-sessionid) // // 也就是说:gemini 走的是 **OAuth Bearer**(Cloud Code 凭据),不是 // Anthropic 那种 x-api-key,也不是 Cline 那种 workos: 前缀。它的鉴权 // 由内核兜底 `Authorization: Bearer ` 提供 —— 而 gemini 未声明 // credential_shape ⇒ api_key = 凭据里的 access_token ⇒ 兜底值正确。 // // ⇒ **结论:不改。** 本判据把这个结论钉住:一旦有人给 channels-gemini 加上 // // build_headers 发别的鉴权头(例如照 zcode 改成 x-api-key),这里会红。 func TestChannelsGeminiAuthIsBearerByDesign(t *testing.T) { vm, _ := zcodeHarness(t) // ① 适配器不该自己发鉴权头:静态头里**不得**出现 Authorization / // x-api-key / x-goog-api-key。鉴权交给内核兜底 Bearer。 hdrs, err := vm.BuildHeaders("channels-gemini", map[string]interface{}{ "api_key": "GA-OAUTH-TOKEN", "url": "https://cloudcode-pa.googleapis.com/v1internal:generateContent", "method": "POST", "body": `{}`, }) if err != nil { t.Fatalf("BuildHeaders: %v", err) } for _, forbidden := range []string{"Authorization", "x-api-key", "x-goog-api-key"} { if v, has := hdrs[forbidden]; has { t.Fatalf("★ channels-gemini 不该自己发 %s(实得 %q)—— "+ "Cloud Code 走 OAuth Bearer,由内核兜底发;"+ "自己发会让它与兜底冲突或改变鉴权方案(P1-3 结论是「不改」)", forbidden, v) } } // ② 身份五头必须还在(它们是准入条件,与鉴权无关) for k, want := range map[string]string{ "User-Agent": "antigravity/4.3.0 (cmdc-pak)", "x-client-name": "antigravity", "x-client-version": "4.3.0", "x-machine-id": "cmdc-pak", "x-vscode-sessionid": "proxy", } { if got := hdrs[k]; got != want { t.Fatalf("身份头 %s 应为 %q,实得 %q(参考 GEMINI_IDENTITY_HEADERS 逐字)", k, want, got) } } t.Logf("✓ channels-gemini 只发身份五头、不自带鉴权(兜底 Bearer 即正确): %v", keysOf(hdrs)) } // 配对判据:经**内核**装出来的头必须真的是 `Authorization: Bearer `。 // // 这条在 internal/provider 侧另有一条同型判据(build_headers_fallback_test.go), // 这里从「适配器没抢鉴权」推到「兜底确实补上了」,把 P1-3 的结论补成闭环。 func TestChannelsGeminiKernelFallbackSendsBearer(t *testing.T) { vm, _ := zcodeHarness(t) // 适配器产出:不含任何鉴权头(见上一条) hdrs, err := vm.BuildHeaders("channels-gemini", map[string]interface{}{ "api_key": "GA-OAUTH-TOKEN", }) if err != nil { t.Fatal(err) } if _, has := hdrs["Authorization"]; has { t.Fatalf("适配器不该发 Authorization,实得 %v", hdrs) } // 于是内核兜底条件成立(Authorization 与 x-api-key 都为空)⇒ 会补 Bearer。 // 这里断言**条件成立**,而不是重复实现兜底逻辑(兜底本身由 provider 判据咬)。 if hdrs["x-api-key"] != "" { t.Fatalf("x-api-key 必须为空(否则内核兜底不会补 Bearer),实得 %v", hdrs) } t.Log("✓ 适配器不装鉴权 ⇒ 内核兜底条件成立 ⇒ 发 Authorization: Bearer ") }