fix(google): print Gemini OAuth URL before browser launch (#71469)

This commit is contained in:
ZC
2026-05-23 06:35:32 +08:00
committed by GitHub
parent b3622beecb
commit 2d5bda9199
2 changed files with 71 additions and 1 deletions

View File

@@ -0,0 +1,69 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth?state=state-123";
const exchangeCodeForTokensMock = vi.hoisted(() =>
vi.fn(async () => ({
access: "access-token",
refresh: "refresh-token",
expires: 123,
})),
);
const waitForLocalCallbackMock = vi.hoisted(() =>
vi.fn(async () => ({ code: "oauth-code", state: "state-123" })),
);
vi.mock("./oauth.flow.js", () => ({
buildAuthUrl: () => AUTH_URL,
generateOAuthState: () => "state-123",
generatePkce: () => ({ challenge: "pkce-challenge", verifier: "pkce-verifier" }),
parseCallbackInput: vi.fn(),
shouldUseManualOAuthFlow: (isRemote: boolean) => isRemote,
waitForLocalCallback: waitForLocalCallbackMock,
}));
vi.mock("./oauth.token.js", () => ({
exchangeCodeForTokens: exchangeCodeForTokensMock,
}));
describe("loginGeminiCliOAuth local browser flow", () => {
beforeEach(() => {
exchangeCodeForTokensMock.mockClear();
waitForLocalCallbackMock.mockClear();
});
it("prints the auth URL before attempting best-effort browser launch", async () => {
const events: string[] = [];
const { loginGeminiCliOAuth } = await import("./oauth.js");
const openUrl = vi.fn(async () => {
events.push("open");
});
const log = vi.fn((message: string) => {
events.push(`log:${message}`);
});
const result = await loginGeminiCliOAuth({
isRemote: false,
openUrl,
log,
note: async () => {},
prompt: async () => "",
progress: { update: () => {}, stop: () => {} },
});
expect(result).toEqual({
access: "access-token",
refresh: "refresh-token",
expires: 123,
});
expect(log).toHaveBeenCalledWith(expect.stringContaining(AUTH_URL));
expect(openUrl).toHaveBeenCalledWith(AUTH_URL);
expect(events.findIndex((event) => event.startsWith("log:"))).toBeLessThan(
events.indexOf("open"),
);
expect(waitForLocalCallbackMock).toHaveBeenCalledWith(
expect.objectContaining({ expectedState: "state-123" }),
);
expect(exchangeCodeForTokensMock).toHaveBeenCalledWith("oauth-code", "pkce-verifier");
});
});

View File

@@ -42,10 +42,11 @@ export async function loginGeminiCliOAuth(
}
ctx.progress.update("Complete sign-in in browser...");
ctx.log(`\nOpen this URL in your browser:\n\n${authUrl}\n`);
try {
await ctx.openUrl(authUrl);
} catch {
ctx.log(`\nOpen this URL in your browser:\n\n${authUrl}\n`);
// The URL is already visible; browser launch is best-effort.
}
try {