fix: gracefully skip enterprise features when using GitHub App auth#141
Conversation
The consumed-licenses API is not accessible via GitHub App installation tokens, so syncing with --enterprises and App auth would fail hard. Now enterprise role sync and SAML email enrichment degrade gracefully with a debug log instead of aborting the entire sync. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @madison-c-evans's task in 2m 1s —— View job PR Review: Graceful Enterprise Degradation for GitHub App Auth
Overall: The core idea is sound — Issues Found
What looks good
|
pkg/connector/enterprise_role.go
Outdated
| if err != nil { | ||
| return fmt.Errorf("baton-github: error listing enterprise consumed licenses for %s: %w", enterprise, err) | ||
| l.Debug("baton-github: enterprise features (--enterprises) require a Personal Access Token. "+ | ||
| "GitHub App authentication cannot access the consumed-licenses API. "+ | ||
| "Either switch to PAT auth or remove the --enterprises flag.", | ||
| zap.String("enterprise", enterprise), | ||
| zap.Error(err)) | ||
| return nil |
There was a problem hiding this comment.
Bug (medium): Catches all errors, not just auth errors.
This catches every error — network timeouts, rate limits, 500s, context cancellation — and treats them all as "GitHub App can't access this endpoint." A transient failure mid-sync will silently produce zero (or partial) enterprise role data with only a debug log.
Two concerns:
-
Overly broad catch: Consider checking for 403/404 status codes to distinguish auth failures from transient errors. The
ListEnterpriseConsumedLicensesclient wraps the HTTP status in the error string, so you could match on that, or propagate the status code from the client. -
Mid-pagination data loss: If pages 1–3 succeed but page 4 fails, this returns
nilwith a partial cache. Enterprise roles from the first 3 pages will appear in sync results while the rest silently vanish. Consider only applying the graceful skip on the first page (wherepage == 1), and propagating errors on subsequent pages.
Suggestion (minor): Log level. When a user explicitly passes --enterprises, silently returning zero enterprise roles at Debug level could be confusing. Consider Warn here (vs the validation path where Debug makes sense as a pre-check).
| l.Debug("baton-github: enterprise features (--enterprises) require a Personal Access Token. "+ | ||
| "GitHub App authentication cannot access the consumed-licenses API. "+ | ||
| "Either switch to PAT auth or remove the --enterprises flag.", | ||
| zap.Error(err)) |
There was a problem hiding this comment.
Nit: The PAT validation path at line 215 still has the old wording.
The PR description mentions "consistent, actionable wording across all three callsites," but the PAT validation check at connector.go:215 still reads:
"enterprise consumed licenses API is not accessible — enterprise SAML email enrichment and enterprise role sync may fail at sync time"
Should be updated to match this new wording for consistency.
Address review feedback: only gracefully skip enterprise role sync when the first page returns a 403 (PermissionDenied), indicating GitHub App auth lacks access. Transient errors (timeouts, 500s, rate limits) and mid-pagination failures still propagate as hard errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @madison-c-evans's task in 2m 43s —— View job PR Review: Graceful Enterprise Degradation for GitHub App Auth
Overall: The second commit (959be01) addresses the most important concern from the prior review — narrowing the catch to first-page permission errors only. The core approach is correct: Error detection works correctly (verified)I traced the full error chain:
The Remaining issues
What looks good
Neither issue is a blocker — this is a clear improvement over the hard-failure behavior on |
| "Either switch to PAT auth or remove the --enterprises flag.", | ||
| zap.String("enterprise", enterprise), | ||
| zap.Error(err)) | ||
| return nil |
There was a problem hiding this comment.
The goal is to disable consumed-licenses API using github app authentication,
we still should return error if the connector is configured with PAT, but the pat is not in admin scope.
maybe we should check if appClient is nil.
baton-github/pkg/connector/connector.go
Line 99 in c8b04dd
There was a problem hiding this comment.
Now passes appClient through to enterpriseRoleResourceType and gate the graceful skip on appClient != nil. PAT with insufficient scope will still return a hard error
Pass appClient to enterpriseRoleResourceType and gate the graceful skip on appClient != nil. PAT auth with insufficient enterprise admin scope still returns a hard error. Also updates PAT validate path wording for consistency. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @madison-c-evans's task in 2m 14s —— View job PR Review: Graceful Enterprise Degradation for GitHub App Auth
Overall: This is a solid, well-scoped fix. The three commits show good iterative refinement in response to review feedback. The core approach — skip enterprise role sync with a log message when GitHub App auth can't access the consumed-licenses API — is correct and well-implemented. One remaining item worth addressing. Verified: Error detection chain is correctI traced the full path:
Verified:
|
Summary
/enterprises/{slug}/consumed-licenses) is not accessible via GitHub App installation tokens — it requires a PAT with enterprise admin scope.--enterpriseswith GitHub App auth caused the sync to fail hard when the enterprise role builder tried to call this API.enterpriseRoleBuilder.fillCache()logs a debug message and returns an empty cache (zero enterprise role resources) instead of aborting.validateAppCredentials()debug message to use consistent, actionable wording across all three callsites.What changed
pkg/connector/enterprise_role.go—fillCache()catches the consumed-licenses error, logs a debug-level message, and returnsnil(empty cache) so the sync continues.pkg/connector/connector.go—validateAppCredentials()debug log updated to match the same wording.Test plan
go test ./...— all pass--enterprises mevans-test+--log-level debug— sync completed successfully, debug messages appeared at validate time and at enterprise role list time, all other resource types synced normally🤖 Generated with Claude Code