Skip to content

Clear only the credential GitHub rejected, and stop treating a plain 403 as one [patch] - #316

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/297-owner-token-auth-failure
Sep 29, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/297-owner-token-auth-failure

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #297

What was wrong

MakeGitHubRequestAsync always called BuildProvider.OnAuthenticationFailure() on an AuthorizationException or on a 403 that wasn't a rate limit. That cleared the provider-level AccountId and Token, whichever credential the request had actually used. This had three effects:

  • An owner with an expired override token took every other owner offline.
  • The owner token that actually failed stayed in the store, so HasValidCredentials(owner) stayed true and that owner was rejected again every cycle.
  • A single forbidden request, such as a dispatch without actions: write, erased the global token.

The fix

  • MakeGitHubRequestAsync records which credential the request is sent with. If an AuthorizationException comes back for a request sent with an owner's override token, only that owner's token is cleared. That owner then falls back to the provider token, the provider credentials are left alone, and the status reads AuthFailed with the owner's name.
  • A rejected provider token still clears the provider credentials, as before.
  • A 403 that isn't a rate limit is now reported as a per-request error (ProviderStatus.Error, "Forbidden: "), and the request returns false. No credentials are touched.

Tests

These run in GitHubRequestOutcomeTests against the in-memory TokenStorage:

  • New ARejectedOwnerTokenClearsOnlyThatOwnersToken: the owner token is cleared and the provider token survives.
  • New APlain403LeavesTheCredentialsInPlace: both the provider and owner tokens survive a plain 403.
  • New ARejectedProviderTokenStillClearsTheProviderCredentials: the unchanged path, pinned down.
  • APlain403ReportsFailure now expects Error instead of AuthFailed.

With GitHub.cs reverted to main, three of these fail: the two new tests that cover changed behaviour, plus the updated APlain403ReportsFailure. The provider-token test passes either way by design. With the fix in place, dotnet test passes 75 of 75.

This is independent of #315 (#298). Both branch from main and touch different files.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XkEHuDnqdEMrwMy3iu9Kyr


Generated by Claude Code

…lain 403 as one [patch]

MakeGitHubRequestAsync called OnAuthenticationFailure on any
AuthorizationException, clearing the provider-level AccountId and Token even
when the request had been sent with an owner's override token. One owner with
an expired token took every other owner offline, while the token that actually
failed stayed in the store and was rejected again every cycle.

A rejected owner token now clears that owner's token only, so the owner falls
back to the provider token, and the provider credentials are left alone. A
rejected provider token still clears the provider credentials as before.

A non-rate-limit 403 means the token may not make this one request, such as a
workflow dispatch without actions: write. It is now reported as an error on the
request and no longer erases any credentials.

Fixes #297

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XkEHuDnqdEMrwMy3iu9Kyr
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 16d1184 into main Sep 29, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the fix/297-owner-token-auth-failure branch September 29, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A revoked per-owner GitHub token wipes the provider's working credentials, while the bad owner token stays in place

1 participant