fix(rbac): add app preview API key role#2698
Conversation
📝 WalkthroughWalkthroughThe change introduces app-only preview API keys with dedicated RBAC roles, app-scoped binding enforcement, preview channel and bundle ownership controls, updated API key management UI, CLI lifecycle handling, database types, translations, and broad automated coverage. ChangesApp Preview API Key
Estimated code review effort: 5 (Critical) | ~120 minutes Suggested labels: Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant AdminUI
participant ApiKeyAPI
participant RBACDatabase
participant ChannelAPI
participant PreviewCLI
AdminUI->>ApiKeyAPI: create app-only preview key
ApiKeyAPI->>RBACDatabase: store app_preview binding
PreviewCLI->>ChannelAPI: create and promote preview channel
ChannelAPI->>RBACDatabase: create channel_preview child binding
PreviewCLI->>ChannelAPI: delete preview channel and bundle
ChannelAPI->>RBACDatabase: validate ownership and delete resources
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
f513784 to
7d29c2d
Compare
Visual diff failedVisual diff did not produce a report. Check the workflow logs and artifacts. Commit: Open |
ad195b4 to
7064018
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_5e8cdbb9-13e3-4f4d-9369-9ab2fa6c5118) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key binding change exceeds the low-risk approval threshold. Assigned Dalanir and WcaleNieWolny for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
supabase/functions/_backend/public/apikey/put.ts (1)
102-103: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winMove the
app_previewgate ahead of the org role precheck.replaceApiKeyBindings()already requiresorg.update_user_rolesfor every affected org before callingassertApiKeyManagerCanAssignBindings(), so the new deny list in that helper never runs on this PUT path.🤖 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 `@supabase/functions/_backend/public/apikey/put.ts` around lines 102 - 103, Move the app_preview deny-list gate before the org role precheck in the PUT flow, specifically before assertApiKeyManagerCanAssignBindings and its call to replaceApiKeyBindings. Ensure app_preview requests are rejected before org.update_user_roles validation can short-circuit the new gate.
🤖 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.
Inline comments:
In `@src/pages/ApiKeys.vue`:
- Around line 992-1017: Update validateApiKeyScope so the appOnlyScope branch
uses a dedicated “select at least one app” translation key when selectedAppIds
is empty, and add the corresponding select-at-least-one-app entry to
messages/en.json. Keep the existing role and organization validation messages
unchanged.
In `@supabase/migrations/20260708000000_prod_baseline.sql`:
- Around line 10111-10115: Remove the process_all_cron_tasks scheduler
registration from the prod baseline migration and add it to a new forward
migration using the same cron.schedule configuration. Ensure the new migration
creates the job for environments that have already applied the baseline.
In `@supabase/migrations/20260715175642_repair_rbac_function_grants.sql`:
- Line 10: Wrap the long REVOKE/GRANT statements in the migration, including the
function signatures and role lists, to comply with SQLFluff LT05 line-length
limits. Update the statements at the referenced ranges while preserving their
existing functions, privileges, and roles.
---
Outside diff comments:
In `@supabase/functions/_backend/public/apikey/put.ts`:
- Around line 102-103: Move the app_preview deny-list gate before the org role
precheck in the PUT flow, specifically before
assertApiKeyManagerCanAssignBindings and its call to replaceApiKeyBindings.
Ensure app_preview requests are rejected before org.update_user_roles validation
can short-circuit the new gate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 098ef471-c4bc-4257-9873-2a1909e6bfc7
📒 Files selected for processing (26)
.github/pr-screenshots/app-preview-api-key.webpmessages/en.jsonplaywright/e2e/apikeys.spec.tsplaywright/visual-diff.config.tsread_replicate/schema_replicate.catalog.jsonread_replicate/schema_replicate.sqlscripts/visual-diff.tssrc/components/connect/ConnectAppPicker.vuesrc/components/permissions/ChannelPermissionOverridesPanel.vuesrc/pages/ApiKeys.vuesrc/services/apikeys.tssrc/stores/organization.tssupabase/functions/_backend/private/role_bindings.tssupabase/functions/_backend/public/apikey/post.tssupabase/functions/_backend/public/apikey/put.tssupabase/functions/_backend/public/apikey/scope.tssupabase/migrations/20260708000000_prod_baseline.sqlsupabase/migrations/20260715164834_add_app_preview_role.sqlsupabase/migrations/20260715175642_repair_rbac_function_grants.sqlsupabase/seed.sqltests/apikey-scope.unit.test.tstests/apikeys-service.unit.test.tstests/apikeys.test.tstests/cli-preview-lifecycle.test.tstests/frontend-channel-rbac-scope.test.tstests/rbac-permissions.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
💤 Files with no reviewable changes (1)
- read_replicate/schema_replicate.sql
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_bb9abcb9-1840-423f-a939-e0c333f6c4fa) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key change exceeds the low-risk approval threshold. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), so the automated review signal is incomplete for this RBAC/API-key change. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c4374092-4f55-4f87-b519-7de8fef29259) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key change exceeds the low-risk approval threshold. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f6bc7119-9223-432e-bfe4-2d7cafaa35c1) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key migration exceeds the low-risk approval threshold. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), so the automated review signal is incomplete for this RBAC/API-key change. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e3435d4c-f4ab-48c5-ab04-292876260ea5) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key migration exceeds the low-risk approval threshold. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), so the automated review signal is incomplete for this RBAC/API-key change. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_03608654-4ef6-4c1b-a982-f1249a2c5ce2) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key migration exceeds the low-risk approval threshold. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), so the automated review signal is incomplete for this RBAC/API-key change. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_090e2636-721d-4560-8356-e46a06075a70) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), and this RBAC/API-key migration exceeds the low-risk approval threshold. Human reviewers are already assigned (Dalanir, WcaleNieWolny).
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot did not complete (check skipped; usage limit reached), so the automated review signal is incomplete for this RBAC/API-key change. Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_6ebed600-26b5-49b9-a19f-c23a394af332) |
|





Summary
org_id); app-only keys do not receive an organization-wide rolechannel_previewchild rolechannel delete --delete-bundleatomically remove only the preview key's own channel and bundle while retaining the existing generic admin cleanup behavioruserstypes with the social-username columns already introduced by the mergedmainmigrationSecurity boundary
An App Preview key can upload a bundle and create a channel in its selected app. Creating that channel gives the same key
channel.read,channel.promote_bundle, andchannel.deleteonly for that created channel.It cannot promote, delete, or otherwise manage the default/main channel, a pre-existing channel, or a channel created by another preview key. It also cannot mutate its own bundle after that bundle is referenced by a channel it does not manage.
The selected organization remains part of the binding. It does not grant organization-wide permissions. App-level read permissions remain available to resolve the selected app and can expose channel metadata; the boundary delivered here is mutation and lifecycle isolation, not strict read isolation.
Procedure after release
channel delete --delete-bundlefor the atomic preview cleanup path.Migration
Exactly one forward-only migration is included:
20260715213729_app_preview_api_key_role.sql.Validation
tests/rbac-permissions.test.ts— 26 passedbun lintbun typecheckbun test:unit— 1,047 passedVisual
Summary by CodeRabbit
Note
High Risk
Changes authentication/authorization across migrations, triggers, API key binding rules, and channel/bundle lifecycle endpoints—security-critical paths with transactional locking and new preview isolation semantics.
Overview
Introduces App Preview as a narrow CI/CD path: API keys can be limited to selected apps only (no org-wide role), with a new
app_previewapp role and UI copy that treats org selection as binding validation, not org-wide access.Database and RBAC: A large migration adds
app_preview/channel_previewroles,parent_binding_idon role bindings, andcreated_by_apikey_rbac_idon bundles. Creating a channel under an app-preview key auto-grants a childchannel_previewbinding tied to that parent; permission checks and triggers enforce that preview keys only promote/delete their own bundles and only on channels they created. The automaticapikey_org_readercompatibility binding on app-only keys is removed.Edge functions & CLI: New-channel + bundle promotion runs in a transaction via
channelPOST; preview cleanup useschannelDELETE withdelete_bundle. Upload preflight no longer requireschannel.promote_bundleto create a channel; creating a new channel on upload goes through thechannelfunction instead of direct DB updates.API key service/UI: Create/update flows support app-only bindings; member AI keys require at least one app binding. Tests and visual-diff tooling cover the new API Keys dialog and preview lifecycle.
Reviewed by Cursor Bugbot for commit 8c79a02. Bugbot is set up for automated code reviews on this repo. Configure here.