Skip to content

feat(web): Add ability to refresh permissions from account linking settings#945

Merged
brendan-kellam merged 10 commits intomainfrom
brendan/trigger-account-permission-sync-SOU-578
Feb 26, 2026
Merged

feat(web): Add ability to refresh permissions from account linking settings#945
brendan-kellam merged 10 commits intomainfrom
brendan/trigger-account-permission-sync-SOU-578

Conversation

@brendan-kellam
Copy link
Contributor

@brendan-kellam brendan-kellam commented Feb 26, 2026

Summary

  • Introduces LinkedAccount type in ee/features/sso/actions.ts covering all OAuth providers (SSO + account_linking), replacing the narrower LinkedAccountProviderState
  • Rewrites linked accounts UI with a Linear-style Connect / "● Connected ∨" dropdown pattern; dropdown includes Disconnect and Refresh Permissions actions
  • Adds triggerAccountPermissionSync server action and backend API endpoint for per-account permission sync refresh
  • Renames settings page from "Permission Syncing" to "Linked Accounts"
  • Removes getLinkedAccountProviderStates in favour of the consolidated getLinkedAccounts
  • Moves SSO-related components and actions from ee/features/permissionSyncing/ to ee/features/sso/
  • Changes AUTH_EE_ALLOW_EMAIL_ACCOUNT_LINKING to default to true

Test plan

  • Visit settings → Linked Accounts; verify all connected OAuth providers appear
  • Verify unlinked account_linking providers show a "Connect ↗" button that initiates OAuth flow and redirects back correctly
  • Verify connected providers show a "● Connected ∨" dropdown with Disconnect and (if permission sync enabled) Refresh Permissions
  • Disconnect a provider and confirm it is removed
  • Trigger Refresh Permissions and confirm a sync job is enqueued
  • On login, verify the ConnectAccountsCard modal appears for users with unlinked required account_linking providers
  • Verify "Skip for now" is hidden when required providers are unlinked, visible otherwise

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ability to re-sync repository permissions directly from linked accounts settings page.
    • Enabled email-based account linking by default.
  • Improvements

    • Consolidated "Permission syncing" settings into unified "Linked accounts" page for streamlined account management.
    • Enhanced linked accounts UI with permission refresh functionality.

brendan-kellam and others added 2 commits February 25, 2026 18:05
…sync (SOU-578)

Adds POST /api/trigger-account-permission-sync that creates and enqueues
an AccountPermissionSyncJob for a given accountId, with entitlement and
provider validation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Introduces `LinkedAccount` type in `ee/features/sso/actions.ts` covering all OAuth providers (SSO + account_linking), replacing the narrower `LinkedAccountProviderState`
- Rewrites linked accounts UI with Linear-style Connect / Connected dropdown pattern; dropdown includes Disconnect and Refresh Permissions actions
- Adds `triggerAccountPermissionSync` server action and worker API call for per-account permission refresh
- Renames settings page from "Permission Syncing" to "Linked Accounts"
- Removes `getLinkedAccountProviderStates` in favour of `getLinkedAccounts`
- Moves SSO-related components and actions from `ee/features/permissionSyncing/` to `ee/features/sso/`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR refactors permission syncing from a provider-centric to account-centric architecture. It moves permission sync constants to the shared package, adds a new backend API endpoint for triggering account permission syncs, replaces the permission-syncing UI with a unified linked-accounts interface under SSO entitlements, and restructures frontend/backend service actions accordingly.

Changes

Cohort / File(s) Summary
Backend Permission Sync Constants
packages/backend/src/constants.ts, packages/shared/src/constants.ts
Moved PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES and PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS from backend to shared constants for cross-package reuse.
Backend Account Permission Sync API
packages/backend/src/api.ts, packages/backend/src/index.ts
Added /api/trigger-account-permission-sync endpoint with feature flag validation, provider support checks, and dependency injection of AccountPermissionSyncer. Injected syncer dependency into Api constructor.
Backend Syncer Components
packages/backend/src/ee/accountPermissionSyncer.ts, packages/backend/src/ee/repoPermissionSyncer.ts
Added schedulePermissionSyncForAccount method to AccountPermissionSyncer and updated imports to reference shared constants instead of local constants.
Frontend Settings & Navigation
packages/web/src/app/[domain]/layout.tsx, packages/web/src/app/[domain]/settings/layout.tsx, packages/web/src/app/[domain]/settings/linked-accounts/page.tsx
Switched from "permission-syncing" to "sso" entitlement checks, updated data source from provider states to linked accounts, renamed LinkedAccountsSettings to LinkedAccountsPage with default export, and changed route from /permission-syncing to /linked-accounts.
Deleted Permission-Syncing Route & Page
packages/web/src/app/[domain]/settings/permission-syncing/page.tsx
Removed deprecated permission-syncing settings page that redirected to linked accounts.
Frontend SSO Server Actions
packages/web/src/ee/features/sso/actions.ts, packages/web/src/ee/features/permissionSyncing/actions.ts
Created new sso/actions.ts with getLinkedAccounts, unlinkLinkedAccountProvider, skipOptionalProvidersLink server actions and LinkedAccount type; deleted replaced permissionSyncing/actions.ts with similar but differently-structured functionality.
Frontend SSO Components
packages/web/src/ee/features/sso/components/connectAccountsCard.tsx, packages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsx
Renamed LinkAccounts to ConnectAccountsCard with updated props and added new LinkedAccountProviderCard component supporting permission sync triggering; deleted old permissionSyncing component variants (linkButton, linkedAccountProviderCard, providerBadge, providerInfo, unlinkButton).
Frontend Account Sync Job Status API
packages/web/src/app/api/(client)/client.ts, packages/web/src/app/api/(server)/ee/accountPermissionSyncJobStatus/*
Added getAccountSyncStatus client function and new server-side api.ts/route.ts for querying account permission sync job status.
Frontend Worker API
packages/web/src/features/workerApi/actions.ts
Added triggerAccountPermissionSync function to invoke the new backend permission sync endpoint.
Auth & Configuration
packages/web/src/auth.ts, packages/shared/src/env.server.ts, docs/docs/configuration/environment-variables.mdx
Updated token refresh import path from permissionSyncing to sso, changed AUTH_EE_ALLOW_EMAIL_ACCOUNT_LINKING default from false to true, updated documentation.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as Frontend UI
    participant Action as Worker Action
    participant API as Backend API
    participant Queue as Job Queue
    participant DB as Database

    User->>UI: Click "Refresh Permissions"
    UI->>Action: triggerAccountPermissionSync(accountId)
    Action->>API: POST /api/trigger-account-permission-sync
    API->>API: Validate provider support<br/>Check feature flag & entitlement
    API->>Queue: Schedule accountPermissionSyncJob
    Queue->>DB: Create AccountPermissionSyncJob record
    DB-->>Queue: Return jobId
    Queue-->>API: Job enqueued
    API-->>Action: Return jobId
    Action-->>UI: jobId received
    UI->>UI: Poll getAccountSyncStatus(jobId)
    DB->>UI: Return isSyncing status
    UI->>User: Show sync progress
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

  • sourcebot-dev/sourcebot#588 — Directly modifies PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES constant that this PR moves to shared constants
  • sourcebot-dev/sourcebot#840 — Modifies AccountPermissionSyncer concurrency configuration affecting the same syncer component being enhanced here
  • sourcebot-dev/sourcebot#849 — Modifies AUTH_EE_ALLOW_EMAIL_ACCOUNT_LINKING environment variable default value also changed in this PR

Suggested labels

sourcebot-team

Suggested reviewers

  • msukkari
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the primary change: adding the ability to refresh/sync permissions directly from the account linking settings page, which is the core feature introduced in this changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch brendan/trigger-account-permission-sync-SOU-578

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/backend/src/ee/accountPermissionSyncer.ts (1)

118-132: Validation already occurs at the API endpoint level.

The triggerAccountPermissionSync endpoint in packages/backend/src/api.ts (lines 128–131) validates that account.provider is in PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS before calling schedulePermissionSyncForAccount. This prevents unsupported providers from reaching the method.

Adding validation within the method would provide defense-in-depth, but it is not required since the only caller currently validates. If this method is intended for internal use only and always called through the validated endpoint, the refactor is optional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/backend/src/ee/accountPermissionSyncer.ts` around lines 118 - 132,
The reviewer notes validation already happens in the API endpoint, so you can
leave schedulePermissionSyncForAccount as-is; if you prefer defense-in-depth,
add a guard at the start of schedulePermissionSyncForAccount that checks
account.provider against PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS and throw
a clear error (or return early) when unsupported; reference the
schedulePermissionSyncForAccount method, the triggerAccountPermissionSync
caller, and the PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS constant when
implementing the optional check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/backend/src/api.ts`:
- Around line 119-134: The handler currently fetches an account by raw accountId
without validating ownership; update the account lookup to require the
requesting user's id (e.g. include userId: req.user.id in the Prisma where
clause) so the query mirrors unlinkLinkedAccountProvider's pattern and returns
404 if no matching record is found; after that keep the existing provider
support check (PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS) and call
accountPermissionSyncer.schedulePermissionSyncForAccount(account) only for a
validated account.

In `@packages/web/src/ee/features/sso/components/connectAccountsCard.tsx`:
- Around line 52-53: The list renderer in connectAccountsCard.tsx uses
account.provider as the React key which can duplicate if a user links multiple
accounts for the same provider; update the key to a unique, stable identifier
from the account object (e.g., account.id or account.providerAccountId) where
the element uses key={account.provider} and passes linkedAccount={account} so
React reconciliation remains correct.

---

Nitpick comments:
In `@packages/backend/src/ee/accountPermissionSyncer.ts`:
- Around line 118-132: The reviewer notes validation already happens in the API
endpoint, so you can leave schedulePermissionSyncForAccount as-is; if you prefer
defense-in-depth, add a guard at the start of schedulePermissionSyncForAccount
that checks account.provider against
PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS and throw a clear error (or return
early) when unsupported; reference the schedulePermissionSyncForAccount method,
the triggerAccountPermissionSync caller, and the
PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS constant when implementing the
optional check.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 355d7c0 and 491d3fe.

📒 Files selected for processing (26)
  • CHANGELOG.md
  • packages/backend/src/api.ts
  • packages/backend/src/constants.ts
  • packages/backend/src/ee/accountPermissionSyncer.ts
  • packages/backend/src/ee/repoPermissionSyncer.ts
  • packages/backend/src/index.ts
  • packages/shared/src/constants.ts
  • packages/web/src/app/[domain]/layout.tsx
  • packages/web/src/app/[domain]/settings/layout.tsx
  • packages/web/src/app/[domain]/settings/linked-accounts/page.tsx
  • packages/web/src/app/[domain]/settings/permission-syncing/page.tsx
  • packages/web/src/app/api/(server)/ee/permissionSyncStatus/route.ts
  • packages/web/src/auth.ts
  • packages/web/src/ee/features/permissionSyncing/actions.ts
  • packages/web/src/ee/features/permissionSyncing/components/linkButton.tsx
  • packages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsx
  • packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx
  • packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx
  • packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx
  • packages/web/src/ee/features/permissionSyncing/types.ts
  • packages/web/src/ee/features/sso/actions.ts
  • packages/web/src/ee/features/sso/components/connectAccountsCard.tsx
  • packages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsx
  • packages/web/src/ee/features/sso/components/providerIcon.tsx
  • packages/web/src/ee/features/sso/tokenRefresh.ts
  • packages/web/src/features/workerApi/actions.ts
💤 Files with no reviewable changes (8)
  • packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx
  • packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx
  • packages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsx
  • packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx
  • packages/web/src/ee/features/permissionSyncing/actions.ts
  • packages/web/src/app/[domain]/settings/permission-syncing/page.tsx
  • packages/web/src/ee/features/permissionSyncing/components/linkButton.tsx
  • packages/web/src/ee/features/permissionSyncing/types.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web/src/ee/features/sso/sso.ts`:
- Around line 159-160: Remove the unsafe hardcoded
allowDangerousEmailAccountLinking: true in the SSO provider options (references:
allowDangerousEmailAccountLinking in sso.ts) or, alternatively, add a signIn
callback to your NextAuth configuration (NextAuthOptions in auth.ts) that
prevents account linking unless the provider asserts email verification;
implement signIn to inspect account.provider and account/email_verified /
id_token claims and return false when the provider did not assert a verified
email, otherwise return true. Ensure the change is applied for all providers
currently using allowDangerousEmailAccountLinking (the instances in sso.ts) so
the safer behavior is enforced consistently.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 491d3fe and a2d29f2.

📒 Files selected for processing (3)
  • docs/docs/configuration/environment-variables.mdx
  • packages/shared/src/env.server.ts
  • packages/web/src/ee/features/sso/sso.ts
💤 Files with no reviewable changes (1)
  • docs/docs/configuration/environment-variables.mdx

@brendan-kellam brendan-kellam changed the title feat(web): generalize linked accounts with Linear-style UI feat(web): Add ability to refresh permissions from account linking settings Feb 26, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web/src/app/api/`(client)/client.ts:
- Line 23: Change the value imports to type-only imports for server-only types:
replace the current import that brings in AccountSyncStatusResponse (and the
similar PermissionSyncStatusResponse on the adjacent line) with an "import type"
form so the client module only imports types from the "(server)" module and
avoids client/server boundary build issues.

In
`@packages/web/src/app/api/`(server)/ee/accountPermissionSyncJobStatus/route.ts:
- Around line 9-11: The schema currently allows empty jobId because z.string()
accepts "", so update the validator to reject empty values by adding .min(1) to
the jobId string schema; specifically modify queryParamsSchema (the const
queryParamsSchema = z.object({ jobId: z.string(), })) to use jobId:
z.string().min(1) and do the same for the identical rawParams extraction schema
(the other z.object that defines jobId) so empty jobId values produce a 400
validation error instead of reaching the DB and returning 404.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2d29f2 and 200ef24.

📒 Files selected for processing (5)
  • packages/web/src/app/api/(client)/client.ts
  • packages/web/src/app/api/(server)/ee/accountPermissionSyncJobStatus/api.ts
  • packages/web/src/app/api/(server)/ee/accountPermissionSyncJobStatus/route.ts
  • packages/web/src/app/api/(server)/ee/permissionSyncStatus/route.ts
  • packages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/web/src/app/api/(server)/ee/permissionSyncStatus/route.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/web/src/ee/features/sso/components/linkedAccountProviderCard.tsx

@brendan-kellam brendan-kellam merged commit d1a9747 into main Feb 26, 2026
9 checks passed
@brendan-kellam brendan-kellam deleted the brendan/trigger-account-permission-sync-SOU-578 branch February 26, 2026 05:47
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.

1 participant