Repository navigation
feat(integrations): Add a provider access token RPC for cells - #128490
Merged
Merged
Conversation
Code outside control that hands a provider token on, such as the git endpoint, can't mint or refresh one, and can't retry after a 401. get_access_token mints or refreshes the token in control and returns only it and its expiry, for GitHub, GitHub Enterprise, GitLab and Cursor Origin. Refresh tokens and app keys stay in control, unlike with refresh_github_access_token, which returns the whole integration with its metadata. GitHub's client now also returns the expiry from get_access_token, as Cursor Origin's already does. Refs CW-2222
This was referenced Oct 22, 2026
… refreshes early On master GitLab's client returns its stored token without checking its expiry, so the RPC couldn't promise a valid GitLab token; GitLab joins once its client refreshes ahead of expiry. With the remaining providers all taking a minimum validity, pass the same five minutes to each instead of relying on their defaults. Also log when a client returns no token, let an unparseable expiry raise instead of reading as never expiring, catch an install removed during the call, and test GitHub Enterprise minting. Refs CW-2222
vaind
added this pull request to stack #128492
October 22, 2026 07:39
vaind
marked this pull request as ready for review
October 22, 2026 07:47
giovanni-guidini
approved these changes
Oct 22, 2026
…e minutes Refs CW-2222
vaind
added a commit
that referenced
this pull request
Oct 22, 2026
…a token (#128443) Minting a Cursor Origin token saved the whole integration row as it was read before the request to Origin. A rename or an uninstall that landed during the request was therefore undone, and a row deleted meanwhile came back. The provider access token RPC in #128490 mints on demand for git requests, which makes that overlap likely. The row is now re-read after the request, and only `metadata` and `date_updated` are written, with a single `UPDATE` like `update_integration` uses. Nothing is stored if the row is gone. There's no row lock, since a `select_for_update` on a control table has stalled the control database before. The only change that can still be lost is a metadata write that lands between the re-read and the update, a window of a few milliseconds rather than the whole request. A mint response that isn't an object, or lacks a token or an expiry, now raises `ApiError` instead of `KeyError` or `AttributeError`, so callers handle it like any other failed mint.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sentry's upcoming git endpoint (CW-2222) runs in a cell and forwards git requests to the provider with an installation's access token. A cell can't mint or refresh a token, because the app keys and refresh tokens live in control. Git also can't recover from a 401. So the cell asks control for a token that's still valid.
This adds
integration_service.get_access_token(integration_id, organization_id) -> RpcAccessToken | Nonefor GitHub, GitHub Enterprise and Cursor Origin. Control uses each provider's client to return the stored token if it has at least five minutes left, and otherwise mints a new one. It sends back only the token and when it expires. The token is kept out ofrepr, and the expiry lets a caller hold on to the token until shortly before then.Like
refresh_github_access_token, it's scoped to an organization: it returns None unless that organization has an active install of an active integration with that id. It also returns None when the provider refuses or fails, and logs why without including the provider's response. Unlikerefresh_github_access_token, which returns the whole integration with its metadata (for GitHub Enterprise that includes the App's private key), only the access token leaves control. GitHub's client now also returnsexpires_atfromget_access_token, as Cursor Origin's already does.GitLab joins in a follow-up once #128442 lands. Today GitLab's client hands out its stored token without checking whether it has expired, so this RPC couldn't promise a usable one. #128443 fixes how Cursor Origin stores a newly minted token, and lands independently.