fix(credentials): grant admin role to workspace admins on credential creation#5431
fix(credentials): grant admin role to workspace admins on credential creation#5431tsushanth wants to merge 1 commit into
Conversation
…creation When seeding credential_member rows for workspace-scoped credentials, the role was determined solely by whether the acting user is the creator (actingUserId === memberUserId). Workspace admin users therefore received the 'member' role and could not edit or delete secrets they should control. Fix: read permissionType from the permissions table inside getWorkspaceMembership and expose an adminUserIds set. All three creation paths (ensureWorkspaceCredentialMemberships, createWorkspaceEnvCredentials, and the POST /api/credentials handler) now use adminUserIds.has(userId) to assign 'admin' vs 'member', matching the workspace's permission structure.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview
Existing Reviewed by Cursor Bugbot for commit 999bc60. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 999bc60. Configure here.
| credentialId, | ||
| userId: memberUserId, | ||
| role: (memberUserId === actingUserId ? 'admin' : 'member') as 'admin' | 'member', | ||
| role: (adminUserIds.has(memberUserId) ? 'admin' : 'member') as 'admin' | 'member', |
There was a problem hiding this comment.
Write creator loses credential admin
Medium Severity
Replacing the acting-user check with only adminUserIds stops workspace Write members from receiving credential_member admin when they create shared secrets. Env PUT/DELETE treats existing keys as editable only when workspace permission is admin or the user has per-key credential admin, so those creators can add secrets but later edits or deletes are denied.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 999bc60. Configure here.
Greptile SummaryThis PR fixes a bug where workspace admins received
Confidence Score: 3/5The PR partially fixes the admin-role bug but introduces a regression: any workspace member with The route guard ( Both Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User (write/admin)
participant R as POST /api/credentials
participant GWM as getWorkspaceMembership
participant DB as Database
U->>R: POST env_workspace credential
R->>R: checkWorkspaceAccess → canWrite (allows write+admin)
R->>GWM: getWorkspaceMembership(workspaceId)
GWM->>DB: SELECT ownerId FROM workspace
GWM->>DB: SELECT userId, permissionType FROM permissions
GWM-->>R: "{ ownerId, memberUserIds[], adminUserIds(owner+admin-perm) }"
R->>DB: INSERT credential
loop for each memberUserId
alt memberUserId in adminUserIds
R->>DB: "INSERT credential_member (role='admin')"
else
R->>DB: "INSERT credential_member (role='member')"
Note over R,DB: write-perm creator also gets 'member'
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant U as User (write/admin)
participant R as POST /api/credentials
participant GWM as getWorkspaceMembership
participant DB as Database
U->>R: POST env_workspace credential
R->>R: checkWorkspaceAccess → canWrite (allows write+admin)
R->>GWM: getWorkspaceMembership(workspaceId)
GWM->>DB: SELECT ownerId FROM workspace
GWM->>DB: SELECT userId, permissionType FROM permissions
GWM-->>R: "{ ownerId, memberUserIds[], adminUserIds(owner+admin-perm) }"
R->>DB: INSERT credential
loop for each memberUserId
alt memberUserId in adminUserIds
R->>DB: "INSERT credential_member (role='admin')"
else
R->>DB: "INSERT credential_member (role='member')"
Note over R,DB: write-perm creator also gets 'member'
end
end
|


Fixes #4698
Problem
When seeding
credential_memberrows for workspace-scoped credentials (env_workspace,service_account), the role was determined byuserId === actingUserId— only the person performing the action receivedadmin. All other workspace members, including explicit workspace admins, gotmemberand were therefore unable to edit or delete secrets they should control.This affected three separate creation paths:
ensureWorkspaceCredentialMemberships(called fromsyncWorkspaceEnvCredentials) — hardcodedrole: 'member'for everyonecreateWorkspaceEnvCredentials—actingUserId === memberUserIdcheckPOST /api/credentialshandler —session.user.id === memberUserIdcheckFix
getWorkspaceMembershipnow also selectspermissionTypefrom thepermissionstable and returns anadminUserIds: Set<string>containing the workspace owner plus all members with explicitadminpermission. All three creation paths useadminUserIds.has(userId)to assign'admin'vs'member'.No behavior change for personal (
env_personal,oauth) credentials. Existing rows are unaffected — only new inserts receive the corrected role.