What's wrong
MakeGitHubRequestAsync(name, action, owner) in BuildMonitor/Providers/GitHub.cs uses the owner's override token when owner.HasToken is true. But on an AuthorizationException, or a 403 that isn't a rate limit (around lines 701-706 and 716-721), it always calls BuildProvider.OnAuthenticationFailure() (BuildProvider.cs:269). That clears the provider-level AccountId and Token, whichever credential the request actually used.
Why it matters
- An owner-scoped failure takes every other owner offline. One owner with an expired or revoked override token clears the global provider credentials.
- The broken token is never removed. The owner token that caused the failure stays in the store, so
HasValidCredentials(owner) stays true and that owner keeps sending requests that get 401 every cycle.
- A single 403 erases the global token. One request the token isn't permitted to make, such as a workflow dispatch on a repository where the token lacks
actions: write, is treated the same way.
Reproduction (ran against an in-memory TokenStorage)
- Set a provider token and an owner override token.
- Call
MakeGitHubRequestAsync with that owner and an action that throws AuthorizationException.
- Result: the provider token is empty and the owner token is still set.
Expected: the owner token is cleared (or flagged) and the provider token is untouched.
Suggested fix / acceptance criteria
- When the failing request used
owner.HasToken, clear only owner.Token, set that owner's status, and leave the provider credentials alone.
- Treat a non-rate-limit 403 as a per-request error (report it on that action) rather than as a credential failure.
- Add tests for both paths.
What's wrong
MakeGitHubRequestAsync(name, action, owner)inBuildMonitor/Providers/GitHub.csuses the owner's override token whenowner.HasTokenis true. But on anAuthorizationException, or a 403 that isn't a rate limit (around lines 701-706 and 716-721), it always callsBuildProvider.OnAuthenticationFailure()(BuildProvider.cs:269). That clears the provider-levelAccountIdandToken, whichever credential the request actually used.Why it matters
HasValidCredentials(owner)stays true and that owner keeps sending requests that get 401 every cycle.actions: write, is treated the same way.Reproduction (ran against an in-memory
TokenStorage)MakeGitHubRequestAsyncwith that owner and an action that throwsAuthorizationException.Expected: the owner token is cleared (or flagged) and the provider token is untouched.
Suggested fix / acceptance criteria
owner.HasToken, clear onlyowner.Token, set that owner's status, and leave the provider credentials alone.