fix(worker): replace Bitbucket Cloud user-repos endpoint removed by CHANGE-2770#1217
Conversation
…HANGE-2770
Atlassian removed GET /2.0/user/permissions/repositories on 2026-02-27
(CHANGE-2770) and the endpoint now returns HTTP 410 Gone for every
caller. Bitbucket Cloud account-driven permission sync was the only
caller of this endpoint, so it has been hard-failing on every cycle
since then.
Atlassian's stated guidance is that there is no direct replacement, and
recommends a two-step pattern instead:
1. GET /2.0/user/workspaces — list the workspaces the user is a
member of.
2. GET /2.0/repositories/{workspace}?role=member — list the repos the
user can see in each workspace.
`role=member` returns repos where the user has at least explicit read
access, including access inherited from workspace admin, project
membership, or group membership. Bitbucket enforces the filter
server-side, so a workspace admin gets the full workspace, while a user
with no grant on a repo gets nothing back for it — neither over-grants
nor under-grants.
Public-repo handling: the call is intentionally not filtered with
q=is_private=true. Sourcebot's read-side prisma extension already
short-circuits public repos to org-wide access, so an ACCOUNT_DRIVEN
row on a public repo is harmless overlay; but not filtering means that
during a public<->private visibility flip, the user never has a window
where they're missing an ACCOUNT_DRIVEN row for a repo they can see
upstream.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WalkthroughSwitch Bitbucket Cloud repository enumeration away from the removed ChangesBitbucket Cloud Endpoint Migration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/backend/src/bitbucket.ts (1)
711-730: 💤 Low valueQuery parameter merge order could allow
roleto be overwritten.On line 722,
{ role: 'member', ...query }placesrolefirst, which means ifqueryever contains arolekey (e.g., from a malformed pagination URL), it would override the intendedmembervalue. While Bitbucket pagination URLs shouldn't include query filters, reversing the order is safer and more defensive.Suggested fix
- query: { role: 'member', ...query }, + query: { ...query, role: 'member' },🤖 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/bitbucket.ts` around lines 711 - 730, The merge order for query params in the getPaginatedCloud call can allow an incoming query.role to override the intended role='member'; update the params merge so the pagination query is spread first and then role: 'member' is applied (i.e., use { ...query, role: 'member' }) inside the client.apiClient.GET call used in reposByWorkspace/fetchWithRetry/getPaginatedCloud so that role is always enforced regardless of any role in query.
🤖 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/bitbucket.ts`:
- Around line 711-730: The merge order for query params in the getPaginatedCloud
call can allow an incoming query.role to override the intended role='member';
update the params merge so the pagination query is spread first and then role:
'member' is applied (i.e., use { ...query, role: 'member' }) inside the
client.apiClient.GET call used in
reposByWorkspace/fetchWithRetry/getPaginatedCloud so that role is always
enforced regardless of any role in query.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8256326c-16e1-4014-b879-c8aa2e24beb3
📒 Files selected for processing (2)
CHANGELOG.mdpackages/backend/src/bitbucket.ts
…t-cloud-change-2770 # Conflicts: # CHANGELOG.md
Matches the GitHub and GitLab branches of accountPermissionSyncer, which both pass visibility='private' for the same reason: public repos are gated by the read-side prisma filter via isPublic, so no AccountToRepoPermission row is needed for them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/backend/src/bitbucket.ts (1)
689-704: ⚡ Quick winSpread operator ordering may allow pagination params to override filters.
The pattern
{ role: 'member', q: 'is_private=true', ...query }places explicit params before the spread, meaning any same-named keys inquery(from pagination URLs) would override them. This is inconsistent withcloudGetReposForProjects(lines 283-286) which correctly places explicit params after the spread.♻️ Suggested fix
params: { path: { workspace }, - query: { role: 'member', q: 'is_private=true', ...query }, + query: { ...query, role: 'member', q: 'is_private=true' }, },🤖 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/bitbucket.ts` around lines 689 - 704, The params spread currently places pagination query after explicit filters in the getPaginatedCloud call for reposByWorkspace, allowing pagination keys to overwrite filters; update the params ordering in the client.apiClient.GET call inside getPaginatedCloud (used by fetchWithRetry for reposByWorkspace) so that the spread comes first and explicit filters come after (i.e., use ...query then role: 'member', q: 'is_private=true') to ensure the explicit filters cannot be overridden by pagination parameters.
🤖 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/bitbucket.ts`:
- Around line 689-704: The params spread currently places pagination query after
explicit filters in the getPaginatedCloud call for reposByWorkspace, allowing
pagination keys to overwrite filters; update the params ordering in the
client.apiClient.GET call inside getPaginatedCloud (used by fetchWithRetry for
reposByWorkspace) so that the spread comes first and explicit filters come after
(i.e., use ...query then role: 'member', q: 'is_private=true') to ensure the
explicit filters cannot be overridden by pagination parameters.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a54911b9-8dfc-40a8-90e7-de8c84d4757d
📒 Files selected for processing (1)
packages/backend/src/bitbucket.ts
Fixes SOU-1179
Summary
GET /2.0/user/permissions/repositorieswas removed by Atlassian's CHANGE-2770 and now returns 410 Gone, breaking Bitbucket Cloud account-driven permission sync.There is no direct replacement. This PR rewrites
getReposForAuthenticatedBitbucketCloudUserto the two-step pattern Atlassian recommends:GET /2.0/user/workspaces— list the workspaces the user belongs to.GET /2.0/repositories/{workspace}?role=member&q=is_private=true— list the private repos the user can see in each workspace.Test plan
Verified against a live Bitbucket Cloud stack:
AccountToRepoPermissionrows for repos they actually have access to in Bitbucket.🤖 Generated with Claude Code