Merge pull request #3254 from sususu98/fix/antigravity-project-id-onboard

fix: require antigravity project id
This commit is contained in:
Luis Pater
2026-05-21 02:52:32 +08:00
committed by GitHub
10 changed files with 666 additions and 109 deletions
@@ -4,7 +4,10 @@ import (
"context"
"encoding/json"
"io"
"net/http"
"strings"
"testing"
"time"
cliproxyauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
)
@@ -90,6 +93,82 @@ func TestAntigravityBuildRequest_SkipsSchemaSanitizationWithEmptyToolsArray(t *t
assertNonSchemaRequestPreserved(t, body)
}
func TestAntigravityBuildRequest_UsesAuthProjectID(t *testing.T) {
body := buildRequestBodyFromRawPayload(t, "gemini-3.1-pro", []byte(`{
"request": {
"contents": [
{
"role": "user",
"parts": [{"text": "hello"}]
}
]
}
}`))
if got, ok := body["project"].(string); !ok || got != "project-1" {
t.Fatalf("project should come from auth metadata, got=%v", body["project"])
}
}
func TestAntigravityPrepareRequestAuth_FetchesMissingProjectID(t *testing.T) {
executor := &AntigravityExecutor{}
auth := &cliproxyauth.Auth{Metadata: map[string]any{
"access_token": "token",
"expired": time.Now().Add(1 * time.Hour).Format(time.RFC3339),
}}
ctx := context.WithValue(context.Background(), "cliproxy.roundtripper", roundTripperFunc(func(req *http.Request) (*http.Response, error) {
if req.URL.String() != "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist" {
t.Fatalf("unexpected project discovery request: %s", req.URL.String())
}
if got := req.Header.Get("X-Goog-Api-Client"); got != "" {
t.Fatalf("X-Goog-Api-Client = %q, want empty", got)
}
raw, errRead := io.ReadAll(req.Body)
if errRead != nil {
t.Fatalf("read discovery body: %v", errRead)
}
if !strings.Contains(string(raw), `"ideType":"ANTIGRAVITY"`) {
t.Fatalf("unexpected discovery body: %s", string(raw))
}
return &http.Response{
StatusCode: http.StatusOK,
Header: make(http.Header),
Body: io.NopCloser(strings.NewReader(`{"cloudaicompanionProject":"fetched-project"}`)),
}, nil
}))
updated, err := executor.PrepareRequestAuth(ctx, auth)
if err != nil {
t.Fatalf("PrepareRequestAuth error: %v", err)
}
if updated == nil {
t.Fatalf("PrepareRequestAuth returned nil auth")
}
if _, ok := auth.Metadata["project_id"]; ok {
t.Fatalf("original auth metadata should not be mutated")
}
if got, ok := updated.Metadata["project_id"].(string); !ok || got != "fetched-project" {
t.Fatalf("updated auth metadata project_id = %v, want fetched-project", updated.Metadata["project_id"])
}
}
func TestAntigravityBuildRequest_RejectsMissingProjectID(t *testing.T) {
executor := &AntigravityExecutor{}
auth := &cliproxyauth.Auth{Metadata: map[string]any{}}
_, err := executor.buildRequest(context.Background(), auth, "token", "gemini-3.1-pro", []byte(`{"request":{}}`), false, "", "https://example.com")
if err == nil {
t.Fatalf("buildRequest should fail when auth has no project_id")
}
status, ok := err.(interface{ StatusCode() int })
if !ok {
t.Fatalf("error should expose status code, got %T", err)
}
if got := status.StatusCode(); got != http.StatusBadRequest {
t.Fatalf("status code = %d, want %d", got, http.StatusBadRequest)
}
}
func assertNonSchemaRequestPreserved(t *testing.T, body map[string]any) {
t.Helper()
@@ -172,13 +251,19 @@ func buildRequestBodyFromRawPayload(t *testing.T, modelName string, payload []by
t.Helper()
executor := &AntigravityExecutor{}
auth := &cliproxyauth.Auth{}
auth := &cliproxyauth.Auth{Metadata: map[string]any{"project_id": "project-1"}}
req, err := executor.buildRequest(context.Background(), auth, "token", modelName, payload, false, "", "https://example.com")
if err != nil {
t.Fatalf("buildRequest error: %v", err)
}
return requestBody(t, req)
}
func requestBody(t *testing.T, req *http.Request) map[string]any {
t.Helper()
raw, err := io.ReadAll(req.Body)
if err != nil {
t.Fatalf("read request body error: %v", err)