Skip to content

improvement(governance): org-ws-credential roles clarity#5134

Open
icecrasher321 wants to merge 4 commits into
stagingfrom
improvement/gov-model-guarantees
Open

improvement(governance): org-ws-credential roles clarity#5134
icecrasher321 wants to merge 4 commits into
stagingfrom
improvement/gov-model-guarantees

Conversation

@icecrasher321

Copy link
Copy Markdown
Collaborator

Summary

Org Admins are auto Workspace Admins. And workspace admins are auto credential admins.

Type of Change

  • Other: UX improvement

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 19, 2026 5:26pm

Request Review

@cursor

cursor Bot commented Jun 19, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Wide changes to authorization across credentials, workspace membership, logs, and org APIs; incorrect inheritance or listing logic could grant or deny access incorrectly.

Overview
Replaces @sim/workflow-authz with @sim/platform-authz (subpaths for workflow, workspace, and predicates) and rewires sim, realtime, tests, and docs to import from it.

Access model is aligned end-to-end: organization owners/admins are treated as workspace admins on that org’s workspaces (including workspaces they never received an explicit invite for), and workspace admins are credential admins on shared OAuth, service accounts, and workspace env secrets. APIs now use getCredentialActorContext / deriveCredentialAdmin, broaden credential listing and OAuth pickers for workspace admins, block demoting or removing inherited admins, and surface roleSource plus RoleLockTooltip in teammates and credential member UIs. Workspace env value visibility follows the same rule (workspace admin or per-secret credential admin).

Many routes stop joining the permissions table directly and instead use listAccessibleWorkspaceRowsForUser, checkWorkspaceAccess, getEffectiveWorkspacePermission, and shared permissionSatisfies / isOrgAdminRole so org-derived access matches listing, logs, copilot chats, MCP discover, and v1 APIs. Platform permissions docs and FAQs are expanded to describe credential roles and org-admin behavior.

Reviewed by Cursor Bugbot for commit a301eb8. Configure here.

Comment thread apps/sim/app/api/credentials/route.ts
@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR implements a governance inheritance model where organization owners/admins automatically become workspace admins, and workspace admins automatically become credential admins for shared credential types. A new @sim/platform-authz package centralises the predicate and workspace-permission resolver logic so both the Next.js app and the realtime server share a single source of truth.

  • Shared resolver: resolveEffectiveWorkspacePermission in packages/platform-authz/src/workspace.ts replaces hand-rolled === 'owner' || === 'admin' ladders across the codebase; checkWorkspaceAccess gains a canAdmin flag used throughout credential and OAuth routes.
  • Credential access: deriveCredentialAdmin and isSharedCredentialType in lib/credentials/access.ts drive the new derived-admin logic; the creation flow no longer grants explicit admin rows to workspace admins, and the last-admin guard is correctly scoped to personal credentials only.
  • UI clarity: New RoleLockTooltip, workspaceRoleLockReason, and credentialRoleLockReason helpers show role-inheritance explanations on disabled controls in the Teammates and Credential Members panels.

Confidence Score: 4/5

The governance inheritance model is implemented consistently across all credential, workspace, and OAuth credential paths; the only unresolved gap is the multi-org membership query in getOrgAdminWorkspaceRows, already flagged in a prior review thread.

The multi-org .limit(1) without a role filter in getOrgAdminWorkspaceRows can silently return empty for a user who is an org admin in one org but a regular member in another, hiding their derived workspace-admin workspaces and credential access.

apps/sim/lib/workspaces/utils.ts — getOrgAdminWorkspaceRows needs the role filter moved inside the WHERE clause before the .limit(1) call.

Important Files Changed

Filename Overview
packages/platform-authz/src/workspace.ts New shared resolver resolveEffectiveWorkspacePermission that derives workspace-admin status from org owner/admin role; logic is clean and forms the single source of truth for both the Next.js app and the realtime server.
packages/platform-authz/src/predicates.ts New dependency-free predicate helpers (permissionSatisfies, isOrgAdminRole, PERMISSION_RANK, ORG_ADMIN_ROLES) that centralise the permission comparison logic shared across the monorepo.
apps/sim/lib/credentials/access.ts Adds deriveCredentialAdmin, isSharedCredentialType, and SHARED_CREDENTIAL_TYPES; simplifies revokeWorkspaceCredentialMembershipsTx by removing the now-unnecessary promote-workspace-owner fallback.
apps/sim/lib/workspaces/permissions/utils.ts Core permission utility refactored to delegate to resolveEffectiveWorkspacePermission; adds canAdmin to WorkspaceAccess and upgrades getUsersWithPermissions to include org-admin derived members.
apps/sim/lib/workspaces/utils.ts Adds getOrgAdminWorkspaceRows and listAccessibleWorkspaceRowsForUser; the single-row membership query without a role filter in getOrgAdminWorkspaceRows is a known gap already flagged in a prior review thread.
apps/sim/app/api/credentials/[id]/members/route.ts Augments GET members list to include workspace-admin derived members for shared credentials; fixes the previously-broken last-admin guard for shared credential types.
apps/sim/app/api/credentials/route.ts GET now surfaces all shared credentials to workspace admins via leftJoin + derived role; POST no longer grants explicit admin rows to workspace admins at credential-creation time.
apps/sim/app/api/workspaces/[id]/permissions/route.ts Adds a guard that rejects permission updates targeting org-admin users; fires for the entire batch even when the requested role would be harmless.
apps/sim/app/api/auth/oauth/credentials/route.ts OAuth credential listing updated to use leftJoin; workspace admins bypass the membership filter via requesterCanAdmin ? undefined : isNotNull(credentialMember.id).
apps/sim/components/permissions/role-lock.tsx New RoleLockTooltip, workspaceRoleLockReason, and credentialRoleLockReason — clean, well-scoped client component.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User] -->|member of| B[Organization]
    B -->|has role| C{Org Role}
    C -->|owner / admin| D[Derived Workspace Admin]
    C -->|member| E[No Derived WS Access]
    A -->|explicit permission row| F[Workspace Permission]
    F --> G{Effective WS Permission}
    D --> G
    G -->|resolveEffectiveWorkspacePermission| H[admin / write / read / null]
    H -->|admin| I[Derived Credential Admin for shared credentials]
    H -->|write / read| J[No Credential Admin Derivation]
    A -->|explicit credentialMember row| K[Credential Member Role]
    K --> L{deriveCredentialAdmin}
    I --> L
    L -->|memberRole=admin OR workspaceCanAdmin + sharedType| M[Credential Admin]
    L -->|otherwise| N[Credential Member / No Access]
Loading
%%{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"}}}%%
flowchart TD
    A[User] -->|member of| B[Organization]
    B -->|has role| C{Org Role}
    C -->|owner / admin| D[Derived Workspace Admin]
    C -->|member| E[No Derived WS Access]
    A -->|explicit permission row| F[Workspace Permission]
    F --> G{Effective WS Permission}
    D --> G
    G -->|resolveEffectiveWorkspacePermission| H[admin / write / read / null]
    H -->|admin| I[Derived Credential Admin for shared credentials]
    H -->|write / read| J[No Credential Admin Derivation]
    A -->|explicit credentialMember row| K[Credential Member Role]
    K --> L{deriveCredentialAdmin}
    I --> L
    L -->|memberRole=admin OR workspaceCanAdmin + sharedType| M[Credential Admin]
    L -->|otherwise| N[Credential Member / No Access]
Loading

Reviews (3): Last reviewed commit: "address comments" | Re-trigger Greptile

Comment thread apps/sim/lib/workspaces/utils.ts
@icecrasher321 icecrasher321 requested a review from a team as a code owner June 19, 2026 04:14
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

bugbot run

Comment thread apps/sim/app/api/credentials/[id]/members/route.ts
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

bugbot run

@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 and found 1 potential issue.

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 a301eb8. Configure here.

) {
logger.warn(`[${requestId}] Execution access denied: ${executionId}`)
return NextResponse.json({ error: 'Workflow execution not found' }, { status: 404 })
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Archived workspace logs blocked

Medium Severity

Log and metrics routes now gate access with checkWorkspaceAccess, which loads workspaces only when they are not archived. Users who still hold explicit permission rows on archived workspaces are treated as having no access, so executions, exports, and stats that previously worked now return empty results or 404.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a301eb8. 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