Skip to content

fix(cli): support v2 RBAC API keys for setVersionInChannel#2081

Merged
WcaleNieWolny merged 1 commit intomainfrom
fix/cli-set-channel-rbac-v2
May 8, 2026
Merged

fix(cli): support v2 RBAC API keys for setVersionInChannel#2081
WcaleNieWolny merged 1 commit intomainfrom
fix/cli-set-channel-rbac-v2

Conversation

@WcaleNieWolny
Copy link
Copy Markdown
Contributor

@WcaleNieWolny WcaleNieWolny commented May 8, 2026

Summary

  • Replace the is_allowed_capgkey({ apikey, keymode: ['write','all'] }) gate in setVersionInChannel with hasCliPermission(supabase, apikey, 'app.create_channel', { appId: appid }).
  • v2 RBAC keys (mode IS NULL since migration 20260505163356_apikey_nullable_mode_with_bindings) were silently denied here because mode = ANY(keymode) evaluates to NULL for v2 keys.
  • cli_check_permission (called via hasCliPermission) goes through rbac_check_permission_direct, which natively handles both v1 (legacy mode fallback) and v2 (RBAC bindings). app.create_channel is the canonical "write tier" probe — get_org_perm_for_apikey_v2 already uses it to detect perm_write.

Behavior matrix

Key Before After
v2 app_developer (or higher) warning shown ❌ channel set ✅
v2 app_uploader / app_reader warning shown warning shown (correct — uploader tier intentionally cannot promote)
v1 all mode channel set channel set
v1 write mode channel set channel set
v1 upload mode warning shown warning shown
v1 read mode warning shown warning shown
v1 with limited_to_apps excluding target passed gate, then RLS error warning shown (improvement)

Why this approach

The CLI already has hasCliPermission (see cli/src/utils.ts:1630) and uses cli_check_permission for every other RBAC-aware gate (org.create_app, app.build_native, …). This brings setVersionInChannel in line with that pattern instead of being the only call site still using legacy is_allowed_capgkey.

No SQL migration. Single CLI file changed (2 insertions, 4 deletions).

Test plan

  • v2 key with app_developer role on Updater Example → npx @capgo/cli@next bundle upload sets the channel
  • v2 key with app_uploader role → bundle uploads, warning shown (no regression)
  • v1 all mode key → channel still set (no regression)
  • v1 write mode key → channel still set (no regression)
  • v1 upload mode key → warning still shown (no regression)
  • v1 key with limited_to_apps excluding the target app → warning shown at gate instead of RLS failure on channel upsert

Related

Summary by CodeRabbit

  • Refactor
    • Enhanced the permission validation mechanism for CLI uploads to use an improved utility for API key permission checks.

The setChannel gate used `is_allowed_capgkey`, which evaluates
`api_key.mode = ANY(keymode)`. v2 RBAC keys have `mode IS NULL`
(since migration 20260505163356), so the comparison returns NULL
and v2 keys are always denied at this gate, even when their role
bindings grant write access.

Switch to `hasCliPermission` with `app.create_channel` — the same
permission `get_org_perm_for_apikey_v2` uses to detect write tier.
The underlying `rbac_check_permission_direct` handles both the v2
RBAC path (bindings) and the v1 legacy fallback (mode-based keys),
so read/upload/write/all keys keep their existing behavior.

Side benefit: the gate is now app-scoped, so v1 keys with
`limited_to_apps` excluding the target app get the friendly warning
instead of a confusing RLS failure on `updateOrCreateChannel`.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates cli/src/bundle/upload.ts to replace a Supabase RPC-based permission check with the centralized hasCliPermission utility. The utility is imported and then used in setVersionInChannel to verify whether an upload API key can create or update an app channel, now validated against the app.create_channel capability instead of RPC keymode values.

Changes

Permission Check Utility Migration

Layer / File(s) Summary
Utility Import
cli/src/bundle/upload.ts
hasCliPermission is added to the utilities import statement.
Permission Check Implementation
cli/src/bundle/upload.ts
setVersionInChannel replaces the Supabase RPC call with hasCliPermission(supabase, apikey, 'app.create_channel', { appId: appid }) for app channel creation authorization.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • Cap-go/capgo#2061: Centralizes CLI authorization by replacing direct Supabase RPC permission checks with the hasCliPermission utility, directly aligning with this PR's changes to the upload API key validation.
  • Cap-go/capgo#1965: Tightens RPC access control for API-key helper functions and requires coordinated CLI changes to migrate permission checks away from RPC calls.

Poem

🐰 The upload now checks with grace,
No RPC calls in this place,
hasCliPermission leads the way,
Cleaner code, a brighter day! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Description check ❓ Inconclusive The PR description includes a comprehensive summary explaining the fix, behavior matrix, and rationale. However, the test plan section in the description has unchecked checkboxes and lacks specific completion status, and the description template requires screenshots for CLI behavior changes which are not provided. Complete the test plan checkboxes to indicate which tests were performed, and consider adding screenshots/videos demonstrating the CLI behavior change if applicable per template requirements.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(cli): support v2 RBAC API keys for setVersionInChannel' directly summarizes the main change: extending setVersionInChannel to support v2 RBAC API keys.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cli-set-channel-rbac-v2

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq Bot commented May 8, 2026

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing fix/cli-set-channel-rbac-v2 (bda7271) with main (14c5362)

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.

Copy link
Copy Markdown
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cli/src/bundle/upload.ts (1)

695-695: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace legacy “use the all key” wording with capability-based guidance

Line 695 still tells users to “use the all” key, which is outdated after moving to RBAC capability checks and can mislead v2-key users.

💡 Suggested message update
-      uploadFail(`Cannot set channel, the upload key is not allowed to do that, use the "all" for this. ${formatError(dbError3)}`)
+      uploadFail(`Cannot set channel: missing permission to manage channels for this app. ${formatError(dbError3)}`)
🤖 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 `@cli/src/bundle/upload.ts` at line 695, The error message passed to uploadFail
still suggests using the legacy "all" key; update the message in the
uploadFail(...) call so it refers to RBAC capabilities instead (e.g., instruct
the user to ensure their API key has the required channel:set or equivalent
capability) and include formatError(dbError3) as before; modify the string in
the uploadFail invocation that contains formatError(dbError3) (located where
uploadFail is called with formatError(dbError3)) to replace "use the \"all\" for
this" with capability-based guidance mentioning the specific capability to
enable.
🧹 Nitpick comments (1)
cli/src/bundle/upload.ts (1)

23-23: ⚡ Quick win

Use ~/ alias instead of relative src import on this changed line

Line 23 still imports from '../utils'. Please switch this changed import to the ~/ alias for consistency with repo rules.

As per coding guidelines, "use path alias ~/ to reference src/ directory".

🤖 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 `@cli/src/bundle/upload.ts` at line 23, The import on the changed line still
uses a relative path ('../utils')—replace it with the project path alias (use
'~/utils') so the file imports baseKeyV2, BROTLI_MIN_UPDATER_VERSION_V5,
BROTLI_MIN_UPDATER_VERSION_V6, BROTLI_MIN_UPDATER_VERSION_V7,
canPromptInteractively, checkChecksum, checkCompatibilityCloud,
checkPlanValidUpload, checkRemoteCliMessages, createSupabaseClient,
deletedFailedVersion, findRoot, findSavedKey, formatError, getAppId,
getBundleVersion, getCompatibilityDetails, getConfig, getInstalledVersion,
getLocalConfig, getLocalDependencies, getOrganizationId, getPMAndCommand,
getRemoteFileConfig, hasCliPermission, hasOrganizationPerm, isCompatible,
isDeprecatedPluginVersion, OrganizationPerm, regexSemver,
resolveUserIdFromApiKey, sendEvent, updateConfigUpdater, updateOrCreateChannel,
updateOrCreateVersion, UPLOAD_TIMEOUT, uploadTUS, uploadUrl, zipFile from
'~/utils' instead of '../utils'.
🤖 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.

Outside diff comments:
In `@cli/src/bundle/upload.ts`:
- Line 695: The error message passed to uploadFail still suggests using the
legacy "all" key; update the message in the uploadFail(...) call so it refers to
RBAC capabilities instead (e.g., instruct the user to ensure their API key has
the required channel:set or equivalent capability) and include
formatError(dbError3) as before; modify the string in the uploadFail invocation
that contains formatError(dbError3) (located where uploadFail is called with
formatError(dbError3)) to replace "use the \"all\" for this" with
capability-based guidance mentioning the specific capability to enable.

---

Nitpick comments:
In `@cli/src/bundle/upload.ts`:
- Line 23: The import on the changed line still uses a relative path
('../utils')—replace it with the project path alias (use '~/utils') so the file
imports baseKeyV2, BROTLI_MIN_UPDATER_VERSION_V5, BROTLI_MIN_UPDATER_VERSION_V6,
BROTLI_MIN_UPDATER_VERSION_V7, canPromptInteractively, checkChecksum,
checkCompatibilityCloud, checkPlanValidUpload, checkRemoteCliMessages,
createSupabaseClient, deletedFailedVersion, findRoot, findSavedKey, formatError,
getAppId, getBundleVersion, getCompatibilityDetails, getConfig,
getInstalledVersion, getLocalConfig, getLocalDependencies, getOrganizationId,
getPMAndCommand, getRemoteFileConfig, hasCliPermission, hasOrganizationPerm,
isCompatible, isDeprecatedPluginVersion, OrganizationPerm, regexSemver,
resolveUserIdFromApiKey, sendEvent, updateConfigUpdater, updateOrCreateChannel,
updateOrCreateVersion, UPLOAD_TIMEOUT, uploadTUS, uploadUrl, zipFile from
'~/utils' instead of '../utils'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 17d7cd47-2351-4a13-b1e4-3cd05fc7f55a

📥 Commits

Reviewing files that changed from the base of the PR and between 14c5362 and bda7271.

📒 Files selected for processing (1)
  • cli/src/bundle/upload.ts

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 8, 2026

@WcaleNieWolny WcaleNieWolny merged commit 746a02f into main May 8, 2026
50 of 52 checks passed
@WcaleNieWolny WcaleNieWolny deleted the fix/cli-set-channel-rbac-v2 branch May 8, 2026 15:10
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