Skip to content

fix: Recover GitHub installation lookup from invalid OAuth tokens - #5087

Open
mvanhorn wants to merge 2 commits into
OpenFn:mainfrom
mvanhorn:fix/4972-github-installation-auth-recovery
Open

fix: Recover GitHub installation lookup from invalid OAuth tokens#5087
mvanhorn wants to merge 2 commits into
OpenFn:mainfrom
mvanhorn:fix/4972-github-installation-auth-recovery

Conversation

@mvanhorn

Copy link
Copy Markdown

Description

Extend the existing token lifecycle in Lightning.VersionControl so an installations request rejected with 401 gets one recovery attempt when the stored grant has a usable refresh token: refresh and persist the OAuth token, rebuild the bearer client, and retry the installations request exactly once. If refresh is unavailable or fails, or the retry is also unauthorized, return the existing GithubError.invalid_oauth_token/2 contract so GithubSyncComponent renders its current profile/reconnect guidance; preserve the existing raw error behavior for non-authentication GitHub failures. Keep this logic in the production installation-fetch path rather than introducing a test-only seam, and record the user-visible fix in the changelog.

The project GitHub Sync settings load a user's installations through Lightning.VersionControl.fetch_user_installations/1, and the installation selector remains disabled when that asynchronous request fails. Locally expired access tokens are already refreshed, but a 401 returned by GitHub is reduced to an untyped response body, so the LiveComponent treats an authentication failure like a generic API outage. Users therefore receive refresh-or-contact-support guidance instead of an automatic recovery attempt or the existing invalid-token reconnect guidance.

Closes #4972

Validation steps

This PR adds unit and LiveView tests covering the cases below. They are included in the diff but were not executed in my local environment, so CI is the first run.

  1. A stored access token receives 401, its valid refresh token produces a replacement token, and the single retried installations request succeeds; asserts the replacement is persisted and installations are returned.
  2. A 401 cannot be refreshed because the grant is non-refreshable or GitHub rejects the refresh; asserts the result is an :invalid_oauth_token GithubError without repeatedly calling the installations endpoint.
  3. The retried installations request also returns 401; asserts the retry stops after one attempt and returns the typed invalid-token error.
  4. A non-authentication response such as 500 remains a generic GitHub API failure and does not trigger token refresh.
  5. Project Settings receives an unrecoverable installation authentication failure and renders the expired/invalid authentication banner with the profile reconnect link while leaving the installation selector disabled.

Additional notes for the reviewer

The retry is deliberately capped at exactly one attempt so a persistently rejected grant cannot loop against the installations endpoint. Non-authentication failures are left on their existing path so this change does not alter behavior for GitHub outages.

AI Usage

AI was used for assistance.

Pre-submission checklist

  • I have ticked a box in "AI usage" in this PR
  • I have implemented and tested all related authorization policies. (e.g., :owner, :admin, :editor, :viewer) - not applicable: this change does not touch authorization policies.

@github-project-automation github-project-automation Bot moved this to New Issues in Core Aug 21, 2026
@mvanhorn

Copy link
Copy Markdown
Author

Pushed 8c79dbe. The test asserted on a lowercase "authorization" header, but GithubClient sets {"Authorization", "Bearer ..."} capitalised (github_client.ex:145), so those assert ... in env.headers checks could never match. Casing corrected in the four places, plus one line reflowed for the formatter.

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

Labels

None yet

Projects

Status: New Issues

Development

Successfully merging this pull request may close these issues.

Improve GitHub Sync error handling when dropdown disabled

1 participant