refactor(permissions): make hasWorkspaceAdminAccess and getUserEntityPermissions thin wrappers of checkWorkspaceAccess#5430
Conversation
…Permissions thin wrappers of checkWorkspaceAccess
hasWorkspaceAdminAccess and getUserEntityPermissions('workspace', ...)
each independently re-implemented the same getWorkspaceWithOwner +
getEffectiveWorkspacePermission fetch that checkWorkspaceAccess already
does — this is exactly the duplication that let the custom-blocks POST
handler drift into two separate DB round-trips for one permission
resolution (fixed separately). Centralizing all three onto one
implementation means a future logic change or bug fix only has to
happen once, and any future caller that (accidentally) calls two of
these functions together is now at least drawing from one consistent
definition of "effective permission" instead of two that could diverge.
Adds a `permission: PermissionType | null` field to the WorkspaceAccess
return shape so getUserEntityPermissions doesn't need a second
independent getEffectiveWorkspacePermission call to get the raw value.
No behavior change: verified analytically (canAdmin is exactly
permission === 'admin' per PERMISSION_RANK) and confirmed by an
independent security review focused on argument-order and
privilege-escalation risks in this kind of refactor. 616 existing
tests across lib/workspaces, lib/credentials, lib/invitations,
lib/copilot/vfs, and the affected API routes pass unmodified (plus 2
test assertions updated for the new additive field).
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview
Tests that assert the full Reviewed by Cursor Bugbot for commit 5f86d14. Configure here. |
Summary
hasWorkspaceAdminAccessandgetUserEntityPermissions('workspace', ...)each independently re-implement the samegetWorkspaceWithOwner+getEffectiveWorkspacePermissionfetch thatcheckWorkspaceAccessalready does. Any call site that uses two of these three functions for the same (userId, workspaceId) pair silently pays for redundant DB round-trips, and worse, the three implementations could drift apart over timehasWorkspaceAdminAccessandgetUserEntityPermissions's workspace branch are now thin wrappers aroundcheckWorkspaceAccess— matching the patternassertActiveWorkspaceAccessalready used in this same filepermission: PermissionType | nullto theWorkspaceAccessreturn shape sogetUserEntityPermissionsdoesn't need its own secondgetEffectiveWorkspacePermissioncall to get the raw valuecanAdminis exactlypermission === 'admin'(verified againstPERMISSION_RANK— admin is the top rank, nothing else satisfies it)Type of Change
Testing
bunx tsc --noEmitclean,bunx biome checkcleanlib/workspaces,lib/credentials,lib/invitations,lib/copilot/vfs, and the affected API routes pass unmodifiedpermissionfield (exact-shape.toEqual()checks)checkWorkspaceAccess(workspaceId, userId)vs the wrapper functions'(userId, workspaceId)order) and privilege-escalation risk in thecanAdmindelegation — no issues foundChecklist