Skip to content

Commit 0d6eed2

Browse files
authored
Merge pull request #831 from lidge-jun/agent/fix-antigravity-refresh-skew-828
fix(oauth): normalize Antigravity refresh margin
2 parents 2491f13 + 1acc6b3 commit 0d6eed2

3 files changed

Lines changed: 17 additions & 4 deletions

File tree

src/oauth/google-antigravity.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ const SCOPES = [
3232
];
3333
const CALLBACK_PORT = 51121;
3434
const CALLBACK_PATH = "/callback";
35-
const REFRESH_SKEW_MS = 50 * 60 * 1000; // refresh proactively ~50min before nominal 1h expiry
35+
// Keep provider-side margins small: the shared OAuth freshness gate applies an additional minute.
36+
const REFRESH_SKEW_MS = 5 * 60 * 1000;
3637
const REQUEST_TIMEOUT_MS = 30_000;
3738
const ONBOARD_ATTEMPTS = 5;
3839
const ONBOARD_POLL_MS = 2_000;

src/oauth/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export interface KiroOAuthMetadata {
1313
export type OAuthCredentials = {
1414
refresh: string;
1515
access: string;
16-
expires: number; // epoch ms (already skew-adjusted by the provider flow)
16+
/** Epoch ms after any small provider-specific early-refresh margin; the shared gate adds 1 minute. */
17+
expires: number;
1718
email?: string;
1819
accountId?: string;
1920
source?: OAuthCredentialSource;

tests/google-antigravity-oauth.test.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { afterEach, describe, expect, test } from "bun:test";
1+
import { afterEach, describe, expect, spyOn, test } from "bun:test";
22
import { discoverAntigravityProject, refreshAntigravityToken } from "../src/oauth/google-antigravity";
33
import { mkdirSync, rmSync } from "node:fs";
44
import { tmpdir } from "node:os";
@@ -84,10 +84,21 @@ describe("antigravity refresh", () => {
8484
if (url.includes(":loadCodeAssist")) return new Response(JSON.stringify({ cloudaicompanionProject: "proj-R" }), { status: 200 });
8585
return new Response("no", { status: 404 });
8686
});
87-
const cred = await refreshAntigravityToken("refresh-tok");
87+
const issuedAt = 1_900_000_000_000;
88+
const nowSpy = spyOn(Date, "now").mockReturnValue(issuedAt);
89+
const cred = await (async () => {
90+
try {
91+
return await refreshAntigravityToken("refresh-tok");
92+
} finally {
93+
nowSpy.mockRestore();
94+
}
95+
})();
8896
expect(cred.access).toBe("fresh-access");
8997
expect(cred.refresh).toBe("refresh-tok");
9098
expect(cred.projectId).toBe("proj-R");
99+
// A one-hour Google token must retain roughly 55 minutes after the provider margin. The
100+
// previous 50-minute margin stored only ten minutes and caused repeated refreshes in use.
101+
expect(cred.expires - issuedAt).toBe(55 * 60 * 1000);
91102
});
92103

93104
test("refresh failure carries status only, not the response body", async () => {

0 commit comments

Comments
 (0)