Skip to content

refactor,feat(dashboard): allow adding permissions to specific project#6226

Open
ogzhanolguncu wants to merge 9 commits into
mainfrom
project-level-permissions
Open

refactor,feat(dashboard): allow adding permissions to specific project#6226
ogzhanolguncu wants to merge 9 commits into
mainfrom
project-level-permissions

Conversation

@ogzhanolguncu
Copy link
Copy Markdown
Collaborator

@ogzhanolguncu ogzhanolguncu commented May 21, 2026

Fixes #6014.

This PR allows us to configure permissions for specific projects instead of selecting them workspace level. Also refactors way we handle permission logic in the UI.

Note

Adjusted RBAC ID regex (web/internal/rbac/src/permissions.ts) ([0-9A-Za-z]). Some project IDs containing 0/O/I/l were rejected by unkeyPermissionValidation, surfacing as "You need to add at least one permission" on root key create.

Screen.Recording.2026-05-21.at.16.19.19.mov

How to test

  • Create project
  • Try to add permissions to that specific project
  • Make sure no regressions

@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard Ready Ready Preview, Comment May 22, 2026 11:58am
design Ready Ready Preview, Comment May 22, 2026 11:58am

Request Review

Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

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

ℹ️ Minor suggestions only — the ADT refactor is clean and the regex widening is justified, but a couple of rough edges below.

Reviewed changes — adds project-scoped permission rows to the root-key dialog and refactors the dashboard permission UI from a type + apiId pair to a PermissionScope discriminated union (workspace | api | project). Also widens the RBAC ID regex in web/internal/rbac/src/permissions.ts from Crockford base32 to full [0-9A-Za-z], fixing rejections on backend-generated proj_ IDs.

  • PermissionScope ADT in dialog/permissions.ts — discriminated union plus getScopedPermissions(scope) replaces the workspace-sentinel string and the type === "workspace" ? ... : apiId branching scattered across the badge list, content list, and usePermissions.
  • projectPermissions(projectId) factory — mirrors apiPermissions, exposes the three actions defined in projectActions (create_deployment, read_deployment, generate_upload_url).
  • usePermissionSheet refactor — extracts rebuildScopedPerms and collectPermissions(list, build, skipId) so the "preserve other scopes' selections" logic is shared between handleApiPermissionChange and the new handleProjectPermissionChange.
  • useRootKeyDialog — adds trpc.deploy.project.list query, exposes allProjects/projectsLoading; canUpdate now waits for both API + project lists in create mode.
  • PermissionContentList / PermissionBadgeList — both take scope directly; permission-list.tsx uses @unkey/match for scope-header dispatch.
  • buildIdSchema regex — relaxed from Crockford base32 (no 0/O/I/l) to [0-9A-Za-z]{8,32}. Justified: Go's pkg/uid/new.go uses base62, so ctrl.project.createProject emits IDs the old TS regex would reject.

ℹ️ Underlying TS/Go ID-alphabet divergence

The regex widening here is the right fix for the symptom, but the root cause is that the two ID generators in this repo disagree on alphabet.

  • web/internal/id/src/generate.ts:3 — TS newId uses Crockford base32 (123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz), explicitly excluding 0/O/I/l.
  • pkg/uid/new.go:8 — Go uid.New uses full base62 (abc..xyzABC..XYZ0..9), so any proj_ (or future resource) created via the ctrl service can contain the confusable characters Crockford skips.

Today the only resource hitting unkeyPermissionValidation from the Go side is proj_, so widening the regex is sufficient. Worth a follow-up issue to unify the alphabets so this doesn't bite the next resource the ctrl service mints.

Technical details
# Underlying TS/Go ID-alphabet divergence

## Affected sites
- `pkg/uid/new.go:8``defaultAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"` (base62)
- `web/internal/id/src/generate.ts:3``customAlphabet("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")` (Crockford base32)
- `web/internal/rbac/src/permissions.ts:17` — regex now `[0-9A-Za-z]{8,32}` to accept both

## Required outcome
- Decide on one canonical alphabet for prefixed IDs across the codebase, or document why the two paths diverge.

## Suggested approach (optional)
- Easiest: switch Go's `uid.New` to Crockford to match TS, then revert the regex to the stricter Crockford allowlist. Crockford was presumably chosen on the TS side to avoid human-confusable characters in dashboard-visible IDs — that rationale applies equally to backend-minted IDs.
- Alternative: switch TS to base62 to match Go. Loses confusable-character protection but unifies the system.

## Open questions for the human
- Was Crockford a deliberate choice for dashboard-visible IDs (e.g. copy/paste UX), or incidental?

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment thread web/internal/rbac/src/permissions.test.ts
Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — addresses the two open suggestions from the initial pullfrog review; no new behavior.

  • WORKSPACE_SCOPE dedup — extracted from permission-sheet.tsx and root-key-dialog.tsx into a single exported const in dialog/permissions.ts. Both call sites now import it.
  • Gated deploy.project.list queryuseRootKeyDialog takes a new isOpen: boolean prop and passes { enabled: isOpen } to the tRPC query, so non-deploy workspaces (and unopened dialogs) no longer pay the round-trip on mount.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@ogzhanolguncu ogzhanolguncu enabled auto-merge May 22, 2026 14:23
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.

Allow keys to have deploy permissions for certain projects

2 participants