Skip to content

antigravity: client-secret extraction (first GOCSPX match) stale for agy 1.4.11 — refresh fails invalid_client #1633

Closed

Description

@dezren39

antigravity: OAuth client-secret extraction (first GOCSPX match) is stale for agy 1.4.11 — refresh fails invalid_client

Found 2026-11-04 during the #1414 native repoint verification (deploy-gated sequence on #1146).

Symptom

With the native provider live (config repoint merged in code), the first call failed:

route_attempt 227773 | antigravity-direct | gemini-3.8-flash | failure
provider.auth: Antigravity keyring credential unavailable: token endpoint HTTP 401:
invalid_client — "The provided client secret is invalid."

The door (bin/antigravity-direct.mjs in developing-today/code, same extraction design) fails identically on :18751, so this is a shared extraction defect, not a provider wiring defect.

Root cause (verified live against Google's token endpoint)

binaryIntel() in packages/ai/src/providers/antigravity-auth.ts takes the FIRST match of /GOCSPX-[A-Za-z0-9_-]{10,}/ and slices 35 chars, per the layout of the agy binary it was verified against. That layout changed:

  • agy 1.4.8 (nix build): 2 GOCSPX runs, lengths [70, 40]. run0[:35] is the 70-char concatenated pair's first half — token endpoint answers invalid_grant for a bogus grant (= client secret ACCEPTED).
  • agy 1.4.11 (~/.gemini/bin/agy, self-updated 2026-10-30): 3 runs, lengths [40, 43, 40]. run0[:35] -> invalid_client (rejected). run1[:35] -> invalid_grant (accepted). run2[:35] -> invalid_client.

So in the 1.4.11 binary the pairing secret is the SECOND run's first 35 chars; the first-match heuristic picks a decoy/other-client secret. Probe method note: with an intentionally bogus refresh_token, Google answers invalid_client when the secret is wrong and invalid_grant when the secret is right — a safe oracle that never touches the real grant.

Impact

Any consumer refreshing through this extraction is down whenever the stored access token expires: the native provider AND the remaining door. Lane traffic survived until the stored token aged out (last success 2026-11-04 09:00 UTC); the 05:47 CST reboot stopped the CLI from refreshing it, and every refresh since has hit invalid_client.

Interim workaround (applied live, 2026-11-04)

AGY_BIN=/run/current-system/sw/bin/agy on the opencode.service unit (drop-in), so extraction reads the 1.4.8 binary whose layout the heuristic matches. Verified: route_attempt 227942, antigravity-direct/gemini-3.8-flash, success through the native provider; the same AGY_BIN drop-in restored the door (chat completion via :18751 OK).

Fix direction

Do not trust position: collect ALL candidate secrets (each run's [:35], plus [35:70] for >=70-char runs, deduped), and on a token-endpoint invalid_client response try the next candidate (cache the winner in memory). Add a test with both binary layouts (1.4.8-style 70-char pair first; 1.4.11-style decoy first, pairing secret second). The door carries the same logic in code's bin/antigravity-direct.mjs but retires under #1414; the fork fix is the durable one.

Activity

  1. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    Triage evidence — issue-sweep-rotating feeder, 2026-11-04

    Verdict: CONFIRMED on current main 63c50eec0d27139b6ebdc57ed85d4d3ace35b5b3 (verified twice with fresh gh api reads this run).

    What I checked (reads only; the live token-endpoint oracle evidence is already in the issue body):

    Done looks like (the issue's fix direction):

    • Extraction collects ALL candidate secrets (each run's [:35], plus [35:70] for >=70-char runs, deduped) instead of trusting position.
    • On a token-endpoint invalid_client response, refresh tries the next candidate and caches the winner in memory.
    • Tests cover both binary layouts: 1.4.8-style (70-char pair first) and 1.4.11-style (decoy first, pairing secret second).
    • The AGY_BIN=1.4.8 workaround described in the issue can be retired once the fix verifies against a 1.4.11 binary.

    Cross-repo note: the door copy in developing-today/code (bin/antigravity-direct.mjs) carries the same extraction design but retires under #1414 per this issue, so no separate port is filed — the fork fix here is the durable one.

    Priority: high — refresh is broken for the current agy binary; only the interim AGY_BIN pin keeps the native provider and the door alive.

  2. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    agent-note:v1
    state: queued
    Agent: issue-sweep-rotating (triage feeder)
    Session/ID: issue-sweep-rotating run 2026-11-04 09:24 CST
    Found via: rotating feeder pick (developing-today/opencode this run)
    Task: enqueued triage packet as queue task 9664 in repo-health-opencode-pilot (dedupe repo-health:v1:triage:developing-today/opencode:issue:1633)
    Evidence: feeder triage CONFIRMED on main 63c50ee — antigravity-auth.ts:153 first-match GOCSPX regex, :156 slice(0,35); see evidence comment #1633 (comment)
    Expectation: triage confirms the candidate-collection fix design (all runs, try-next on invalid_client, cache winner) and routes a fix packet; both binary layouts covered by tests.

  3. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    Triage verdict — task 9664 (lane opencode-a): CONFIRMED, fix design confirmed, fix routed

    Re-verified fresh on main 63c50eec0d27139b6ebdc57ed85d4d3ace35b5b3 this shift (code reads only; no secret values inspected or recorded):

    • packages/ai/src/providers/antigravity-auth.ts binaryIntel() still takes the FIRST /GOCSPX-[A-Za-z0-9_-]{10,}/ match and slices [0, 35]; the header comment (lines 17–18) and the inline comment at the match still assert the stale 1.4.8 pairing ("the first 35 chars pair with OAUTH_CLIENT_ID").
    • The refresh path has no invalid_client retry/next-candidate handling (no occurrence in the module), and binaryIntelCache caches the single extracted secret — so the decoy is sticky for the process lifetime.
    • Live oracle evidence is already on this issue: on agy 1.4.11 only run1[:35] is accepted (invalid_grant on a bogus grant); run0/run2 are rejected (invalid_client).

    Fix design (as directed on the issue, confirmed feasible against the code): collect ALL candidates — each run's [:35], plus [35:70] for runs ≥70 chars, deduped — return the candidate list from binaryIntel() instead of a single secret; the refresh exchange tries candidates in order, advancing only on an invalid_client response (other failures — network, invalid_grant from a bad stored grant with an accepted secret, 5xx — must NOT advance or mask the real error), and caches the winning candidate in memory only. Never log or persist candidate values. Update the stale comments. Tests in packages/ai/test/provider/antigravity-auth.test.ts with synthetic fixture binaries for both layouts (1.4.8-style 70-char concatenated pair first; 1.4.11-style decoy first, pairing secret second), using fake GOCSPX strings — no real secret material in fixtures.

    Fix routed as a queue task (see the agent note that follows). The interim AGY_BIN pin to the 1.4.8 binary stays necessary until the fix lands. Out of scope per the packet: the door copy in developing-today/code (retires under #1414).

  4. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    agent-note:v1
    state: triage-complete
    Agent: repo-queue-worker-shift-opencode (lane opencode-a)
    Task: triage task 9664 completed — verdict CONFIRMED (see comment above); fix enqueued as queue task 9666 in repo-health-opencode-pilot (dedupe repo-health:v1:fix:developing-today/opencode:issue:1633).

  5. added
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  6. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    PR #1642 opened — fix task 9666 (lane opencode-a), parked on CI/Codex: binaryIntel() collects all GOCSPX candidates and refresh() advances only on invalid_client, winner cached in memory only. Tests: both binary layouts + non-advance case, 6/6 in file; antigravity suite 18/18; tsgo clean. Resume: disposition Codex, verify CI, merge, complete task 9666, clean labels here; the interim AGY_BIN pin can then be dropped.

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/claimedA queue worker has claimed the task for this item
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 4, 2026
  8. added a commit that references this issue on Nov 4, 2026
  9. removed
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 4, 2026
  10. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    PR #1642 merged (merge commit 94c4461). Task 9666 completed. Re-verified at merge time: antigravity-auth tests 6/6 and the full packages/ai provider suite green (0 fail, 1349 tests) at the PR tree; mergeable clean. No Codex review arrived despite the request (repo-wide pattern; zero findings to disposition), so the merge proceeded under the standing merge directive.

    agent-note:v1 — repo-queue-worker-shift-opencode lane A, task 9666 done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions