Skip to content

fix(connectors): persist the scopes Google actually granted on reconnect - #3865

Merged
kovtcharov-amd merged 2 commits into
mainfrom
autofix/issue-3851
Sep 28, 2026
Merged

kovtcharov-amd merged 2 commits into
mainfrom
autofix/issue-3851

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Reconnecting a Google account to add a second scope still ended with GAIA asking for yet another reconnect. Google hands back every scope the account already granted, but GAIA threw away anything it hadn't asked for in that particular flow, so the stored connection understated what the refresh token could actually do and the coverage check kept reporting missing scopes. The connection now records the scope set the token really carries, so a scope granted on an earlier connect stays usable. What each agent may use is unchanged — agent grants are still limited to the scopes that flow asked for.

Closes #3851

Test plan

  • python -m pytest tests/unit/connectors/ -x passes
  • python util/lint.py --all passes
  • Live Google round-trip: connect with Gmail scopes, then reconnect requesting Calendar only, and confirm gaia connectors list shows both scope sets and no CONNECTION_MISSING_SCOPES on a Gmail call
  • Confirm the per-agent grant from that second connect still covers only Calendar
🔍 Technical details

Root cause: _resolve_granted_scopes (src/gaia/connectors/flow.py:543) intersected the token response's scope with the originally-requested list, so any scope Google folded in via include_granted_scopes=true (#3786) was dropped before save_connection. check_scopes (src/gaia/connectors/api.py:239) then read the truncated record and raised CONNECTION_MISSING_SCOPES for scopes the token demonstrably held.

Change: the returned scope list is persisted as-is (order-preserving, deduped). The two other branches are untouched — an absent scope still means "as requested" per RFC 6749 §5.1, an explicitly empty one still means nothing was granted. Both the loopback exchange (flow.py:613) and the device-code path (flow.py:842) pick this up.

Grant narrowing is unaffected: _commit_grants_for_provider filters each agent's requested scopes against the granted set, so a wider granted set cannot widen a grant. Covered by the existing test_commit_grants_intersects_token_scopes.

Verified: tests/unit/connectors/ — 806 passed. New test_wider_returned_scope_is_what_gets_persisted fails on the pre-fix implementation (the extra scope is missing from the record) and passes after. Lint: black/isort clean on the touched files; the three pre-existing util/lint.py --all failures reproduce unchanged on main and are in files this PR does not touch.

Docs: docs/security/connections.mdx gained one sentence distinguishing the connection record (token's full authority) from grants (per-agent subset) — the existing grant sentence there was already correct.

⚠️ Needs manual validation — the unit tests confirm the persistence logic, but only a live Google OAuth round-trip can show the over-grant actually surviving end to end (#2605's own acceptance criterion). A maintainer should run the connect/reconnect sequence above before merging.

… the ones asked for

Reconnecting to add a scope left the connection record claiming less
authority than the refresh token carries, so coverage checks kept
demanding a reconnect the user had already completed. include_granted_scopes
(#3786) made over-grant the normal case on every reconnect, which turned
this from a latent edge case into live behavior.

The token response's scope set is now persisted as returned. Per-agent
grants still narrow to what that flow requested.

Closes #3851
@github-actions github-actions Bot added documentation Documentation changes tests Test changes labels Sep 28, 2026
@kovtcharov-amd
kovtcharov-amd marked this pull request as ready for review September 28, 2026 22:15
@kovtcharov-amd
kovtcharov-amd self-requested a review as a code owner September 28, 2026 22:15
@kovtcharov-amd
kovtcharov-amd added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 722f821 Sep 28, 2026
58 of 63 checks passed
@kovtcharov-amd
kovtcharov-amd deleted the autofix/issue-3851 branch September 28, 2026 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Documentation changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Google OAuth over-grant is still discarded — include_granted_scopes flag doesn't deliver the fix

1 participant