fix(worker): classify permission sync failures by provider context#1482
Conversation
Replace generic HTTP status fail-closed handling with typed upstream permission-sync errors so ambiguous forbidden and gone responses preserve cached permissions. Fixes SOU-1560 Fixes SOU-1177
WalkthroughPermission synchronization now normalizes HTTP error metadata, classifies upstream failures by provider and operation, wraps provider API calls, and clears cached permissions only for classified credential rejection or insufficient scope failures. ChangesPermission sync classification
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant syncAccountPermissions
participant withPermissionSyncUpstreamError
participant classifyPermissionSyncUpstreamError
participant classifyPermissionSyncFailure
syncAccountPermissions->>withPermissionSyncUpstreamError: run provider scope or repository operation
withPermissionSyncUpstreamError->>classifyPermissionSyncUpstreamError: classify thrown upstream error
classifyPermissionSyncUpstreamError-->>withPermissionSyncUpstreamError: return PermissionSyncUpstreamError
withPermissionSyncUpstreamError-->>classifyPermissionSyncFailure: propagate classified failure
classifyPermissionSyncFailure-->>syncAccountPermissions: clear or preserve cached permissions
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This comment has been minimized.
This comment has been minimized.
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/backend/src/ee/permissionSyncError.ts (1)
45-51: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winBroad
TypeErrormatch risks masking internal bugs as "provider unavailable".Any
TypeErrorthrown inside a wrapped callback (including unrelated coding bugs, not justfetchnetwork failures) gets classified asupstream_unavailable, producing a misleading "provider is temporarily unavailable" log/kind for what could be an internal defect. Since bothupstream_unavailableandunknowncurrently map topreserve_permissionsdownstream, there's no behavioral difference today, but it does reduce the accuracy of the errorkindfor incident triage.Consider narrowing the check to more specific network-failure signals (e.g.,
error.cause instanceof Error && error.cause.message.includes('fetch failed'), or checking forECONNRESET/ETIMEDOUTstyle codes from undici) rather than anyTypeError.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/backend/src/ee/permissionSyncError.ts` around lines 45 - 51, Narrow isNetworkOrTimeoutError so it does not classify every TypeError as an upstream outage; rely on specific network or timeout indicators such as fetch-failure causes or recognized undici connection error codes, while preserving AbortError and TimeoutError handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/backend/src/ee/permissionSyncError.ts`:
- Around line 45-51: Narrow isNetworkOrTimeoutError so it does not classify
every TypeError as an upstream outage; rely on specific network or timeout
indicators such as fetch-failure causes or recognized undici connection error
codes, while preserving AbortError and TimeoutError handling.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d5d503ae-a1b0-4ab5-9c97-e73741dd87df
📒 Files selected for processing (7)
CHANGELOG.mdpackages/backend/src/ee/accountPermissionSyncer.test.tspackages/backend/src/ee/accountPermissionSyncer.tspackages/backend/src/ee/permissionSyncError.test.tspackages/backend/src/ee/permissionSyncError.tspackages/backend/src/errors.test.tspackages/backend/src/errors.ts
Replace generic HTTP status fail-closed handling with typed upstream permission-sync errors so ambiguous forbidden and gone responses preserve cached permissions.
Fixes SOU-1560
Fixes SOU-1177
Stack created with GitHub Stacks CLI • Give Feedback 💬
Note
Medium Risk
Changes when cached repository permissions are wiped during sync failures, which affects authorization visibility until the next successful sync; the new preserve-on-ambiguous-error behavior is safer but is still security-sensitive EE logic.
Overview
Replaces fail-closed cleanup on raw HTTP 401/403/410 during account permission sync with typed upstream errors that record provider and operation before deciding whether to clear cached repo permissions.
Adds
PermissionSyncUpstreamErrorand wraps GitHub, GitLab, and Bitbucket scope checks and repo listing inwithPermissionSyncUpstreamError, which classifies responses (e.g. 401 → credential rejected, rate limits via status/headers, 5xx/timeouts → transient). Missing OAuth scopes are raised asinsufficient_scopeinstead of generic errors.classifyPermissionSyncFailurenow clears permissions only foroauth_invalid_grant,credential_rejected, andinsufficient_scope; 403 forbidden, rate limits, 410, and other unclassified HTTP errors preserve the last good permission set.errors.tsgainsgetErrorStatus/getErrorHeaderso classification works across Octokit, GitLab, and Bitbucket error shapes.Reviewed by Cursor Bugbot for commit a985fac. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit