Skip to content

fix(api): RBAC follow-ups for PR #2403#2548

Open
riderx wants to merge 5 commits into
codex/rbac-apikey-management-hardeningfrom
fix/rbac-apikey-hardening-followups
Open

fix(api): RBAC follow-ups for PR #2403#2548
riderx wants to merge 5 commits into
codex/rbac-apikey-management-hardeningfrom
fix/rbac-apikey-hardening-followups

Conversation

@riderx

@riderx riderx commented Jun 19, 2026

Copy link
Copy Markdown
Member

Summary (AI generated)

  • Added org.manage_apikeys permission and assignable apikey_manager role; granted it to org_admin / org_super_admin so migrated legacy all keys keep sibling key management in CI.
  • Allowed POST /apikey via API key auth when the caller has org.manage_apikeys (bindings/global-permission updates remain JWT-only; self-update remains blocked).
  • Removed 2FA/password-policy enforcement from API-key branches of rbac_check_permission_direct.
  • Mapped legacy channel write/upload memberships to channel_admin instead of nonexistent channel_developer / channel_uploader.
  • Granted app_uploader channel promote/read without channel.update_settings.
  • Restored fast RLS for app_versions + manifest via app_versions_readable_app_ids() (bundle read permission).
  • Updated seed.sql so post-seed RBAC repopulation keeps the new permission/grants.
  • Added SQL + vitest coverage for API-key create/manage and 2FA bypass behavior.

Motivation (AI generated)

PR #2403 correctly hardened RBAC, but review follow-ups asked to preserve CI/API-key management for migrated broad keys, add a dedicated manage-keys permission, skip 2FA on API keys, fix channel legacy mapping, and reduce manifest RLS cost.

Business Impact (AI generated)

Customers with legacy broad API keys in GitHub Actions/Fastlane can keep provisioning and rotating sibling keys without JWT sessions, while scoped upload keys still cannot escalate privileges.

Test Plan (AI generated)

Generated with AI

Made with Cursor

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a88a13d7-82a7-4fb8-98e8-1a63a148b427

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@codspeed-hq

codspeed-hq Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing fix/rbac-apikey-hardening-followups (a4fa688) with codex/rbac-apikey-management-hardening (789881a)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf02583c3a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread supabase/migrations/20260616183501_harden_rbac_compat_cleanup.sql

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08a0488357

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread supabase/functions/_backend/public/apikey/post.ts
Comment thread supabase/migrations/20260616183501_harden_rbac_compat_cleanup.sql Outdated
Comment thread supabase/seed.sql
public.rbac_perm_app_create_channel(), public.rbac_perm_app_read_channels(), public.rbac_perm_app_read_logs(), public.rbac_perm_app_manage_devices(), public.rbac_perm_app_read_devices(),
public.rbac_perm_app_build_native(), public.rbac_perm_app_read_audit(), public.rbac_perm_app_update_user_roles(),
public.rbac_perm_channel_read(), public.rbac_perm_channel_update_settings(), public.rbac_perm_channel_read_history(),
public.rbac_perm_channel_read(), public.rbac_perm_channel_read_history(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

org_admin seed migration drift

Medium Severity

The seed.sql RBAC repopulation block removes the channel.update_settings permission for the org_admin role. This makes org_admin users in fresh db reset environments unable to update channel settings, while existing production environments still allow it due to prior migrations. This inconsistency can lead to local failures for actions that succeed in production.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bad1237. Configure here.

ON role_permissions.role_id = role_closure.effective_role_id
INNER JOIN public.permissions
ON permissions.id = role_permissions.permission_id
WHERE permissions.key = public.rbac_perm_app_read()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bundle RLS ignores JWT key owner

Medium Severity

The rewritten app_versions_readable_app_ids() treats a present capgkey header as the RBAC principal without requiring auth.uid() to match the key owner. That differs from rbac_check_permission_direct, which rejects mismatched user and API key on the same request.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bad1237. Configure here.

riderx and others added 4 commits June 23, 2026 12:58
Introduce org.manage_apikeys and apikey_manager so legacy broad keys and
dedicated CI keys can create and manage sibling keys without user-role
assignment rights. Skip 2FA enforcement on API-key auth paths, optimize
manifest/app_versions RLS with readable app id helpers, and align seed
data with app_uploader channel promote and channel_admin legacy mapping.

Co-authored-by: Cursor <cursoragent@cursor.com>
Seed API key 113 with the apikey_manager role and add vitest/SQL checks
that CI keys can manage siblings without role escalation privileges.

Co-authored-by: Cursor <cursoragent@cursor.com>
Re-apply org-scoped RBAC bindings for the dedicated apikey management
seed keys after permissions are repopulated, and assert by key UUID in
the SQL test instead of a fixed apikeys.id.

Co-authored-by: Cursor <cursoragent@cursor.com>
Grant apikey_manager org.read for expiration policy enforcement, block
admin-tier role assignment from apikey_manager callers, and restore
narrow channel_developer/uploader legacy mappings with first-class roles.

Co-authored-by: Cursor <cursoragent@cursor.com>
@riderx riderx force-pushed the fix/rbac-apikey-hardening-followups branch from bad1237 to 7ee64b2 Compare June 23, 2026 11:04
Only evaluate denied assignable roles for bindings in orgs where the
caller lacks org.update_user_roles.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a4fa688. Configure here.

if (APIKEY_MANAGER_DENIED_ASSIGNABLE_ROLES.has(binding.role_name)) {
throw quickError(403, 'forbidden_binding', `Forbidden - API key managers cannot assign the ${binding.role_name} role`)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Client allowSystemRole bypasses deny

High Severity

The assertApiKeyManagerCanAssignBindings function allows client-supplied allowSystemRole: true in POST /apikey requests to bypass the denied roles check. This enables an apikey_manager to create sibling API keys with roles like app_admin or channel_admin, which are otherwise forbidden.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a4fa688. Configure here.

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