Repository navigation
Description
fix(ai): antigravity-auth does not apply the blank-credential rule — whitespace keyring tokens are accepted and sent
Summary
The repo's auth bridges share one rule, stated verbatim in the #1763 fix
(commit 0dd051a394, PR #1764): "A blank value is no credential (the
vibe-auth rule): trim, and treat whitespace-only as absent." vibe-auth.ts
trims at every tier (:146 env, :154 file, :160 keyring), and #1763 extended
the rule to commandcode-auth.ts and claude-code-auth.ts with tests.
packages/ai/src/providers/antigravity-auth.ts — the fourth first-party
auth bridge — was not touched and applies the rule nowhere. Verified by
reading on main 2981dfd838:
Evidence
-
Whitespace-only refresh token passes the shape check and is POSTed.
antigravity-auth.ts:115—if (!creds.token?.refresh_token) return reject(...)rejects only missing/empty values. A refresh token of
" "passes, andrefresh()sends it to
https://oauth2.googleapis.com/tokenasrefresh_token(:252), where
it fails as an opaqueinvalid_grantinstead of being read as "no
credential stored". -
Whitespace-only access token is cached and sent as a Bearer.
loadToken(:308):if (creds.accessToken && creds.expiryMs - Date.now() > 60_000)— a whitespace-onlyaccess_tokenfrom the
keyring is truthy, so with a future expiry it is cached and returned;
keyringAuththen emitsauthorization: \Bearer ${token.accessToken}``
(:335) — literally a Bearer token of spaces, the exact failure fix(ai): commandcode + claude-code auth bridges accept whitespace-only credentials — a blank env var shadows commandcode's valid login file, and both bridges send a Bearer header of spaces #1763's
title names for the sibling bridges. -
Whitespace-only access token from the token endpoint is accepted.
refresh()(:274):if (!parsed.access_token)rejects only
missing/empty; a whitespace-onlyaccess_tokenin a 200 response is
cached and later sent as a Bearer per (2). -
No test pins any of this.
packages/ai/test/provider/antigravity-auth.test.ts
covers only refresh bounding (fix(ai): Antigravity token refresh fetch has no deadline, response body unbounded — check:bounded-http is red on main #1469) and client-secret candidates
(antigravity: client-secret extraction (first GOCSPX match) stale for agy 1.4.11 — refresh fails invalid_client #1633); grep fortrim|whitespace|blankin that file: 0 hits. The
sibling bridges each gained explicit whitespace tests in fix(ai): commandcode + claude-code auth bridges accept whitespace-only credentials — a blank env var shadows commandcode's valid login file, and both bridges send a Bearer header of spaces #1763
(claude-code-auth.test.ts,commandcode-auth.test.ts).
Why it matters
The keyring entry is written by an external binary (agy) and read back
verbatim; a corrupted or placeholder entry currently degrades into a
confusing upstream auth failure (or a spaces-only Bearer) instead of the
bridge's own clear "credential unavailable / unexpected shape" errors.
Consistency also matters for the doctrine in #1717: all *-direct bridges
should treat blank credentials identically, so fall-through and fail-closed
behavior is predictable across providers.
Acceptance criteria
- Keyring parsing treats whitespace-only
refresh_tokenas an
unexpected-shape/absent credential (same rejection path as a
missing one), and trims stored tokens before use. - A whitespace-only keyring
access_tokenis never cached or sent;
loadTokenfalls through to refresh. -
refresh()rejects a whitespace-onlyaccess_tokenin the token
endpoint response (treated like "returned no access_token") and
trims accepted tokens. - New tests in
packages/ai/test/provider/antigravity-auth.test.ts
pin all three cases, mirroring the fix(ai): commandcode + claude-code auth bridges accept whitespace-only credentials — a blank env var shadows commandcode's valid login file, and both bridges send a Bearer header of spaces #1763 sibling tests; existing
fix(ai): Antigravity token refresh fetch has no deadline, response body unbounded — check:bounded-http is red on main #1469/antigravity: client-secret extraction (first GOCSPX match) stale for agy 1.4.11 — refresh fails invalid_client #1633 tests stay green. -
bun run check:bounded-http/ gate state not regressed by the
change (note: the three quota-era gates are already red on main
under fix(ci): three gates red on main — PR #1722's quota subcommand landed 16 undispositioned sites, and turso bypasses the PR's own bounded reader #1724 — do not conflate).
Filed by new-issue-creator-opencode; sibling of closed #1763 (same rule,
bridge not covered there — deduped against open/closed search for
"blank credential whitespace" and "antigravity auth", 2026-11-05).
Activity
dezren39 commentedon Nov 5, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 5, 2026
🤖 Agent note · handed off — task 10729 (queue repo-health-opencode-pilot, lane opencode-a)
handed_off; the laptop claimant (opencode-claimant) launches the bound opencode session that drives this task to its terminal state.