mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
Context: experiment `minimum-implicit-member ` added the ability to set the default member-roles at a per-organization level. This, along with the related PR stacked listed below, will be used to enable "gateway accounts", which are accounts that are entitled to use the AI Gateway but not create or use workspaces. The Workspaces tab is intentionally left visible for now. Hides the "New workspace" button and the empty-state creation CTA on the Workspaces page for users who cannot create a workspace in any organization, and guards the creation page itself. Adds a shared `createWorkspace` authorization check (`workspace` resource, `create` action, `owner_id: me`, `any_org: true`) to `site/permissions.json` and threads the result through `WorkspacesPageView`, `WorkspacesTable`, and `WorkspacesEmpty`. Users without the permission see an empty state explaining they don't have permission to create workspaces instead of a dead-end CTA. The create CTAs on the Templates pages were already gated by per-organization checks; this brings the Workspaces page in line. `CreateWorkspacePage` is also gated: it adds an org-scoped `createWorkspaceForUserID` check to its existing authorization batch and wraps the view in `RequirePermission`, so a direct URL shows the standard denial dialog instead of a form that 403s on submit. Users who can create workspaces for others (`createWorkspaceForAny`) still see the form. To see this behavior, enable the experiment. As an admin, visit Organization -> Roles, and remove "Organization Workspace Access" from the default roles. Login as a user that is not granted workspace access via a member role. Storybook coverage: `CannotCreateWorkspace` (empty state + hidden button), `CannotCreateWorkspaceWithWorkspaces` (button hidden while the table renders), `CannotCreateWorkspaceWithFilter` (pins the filter empty state's priority over the no-permission one), and `PermissionDenied` for the CreateWorkspacePage gate. The Go SSR permissions test also asserts the new `createWorkspace` entry. ## Stack This PR is independent but related to the gateway-accounts stack: 1. **#27279**: permission-based license seat counting. Behind the `permission-based-licensing` experiment and gated on the AI Governance add-on, `user_limit` counts only users the RBAC engine authorizes to create workspaces. 2. **#27280**: adds the `organization-ai-gateway-access` org role carrying the AI Bridge interception permissions (extracted from the member floors, backfilled into org default roles by migration) and enforces it at AI Gateway authentication; bridge usage stops claiming AI Governance seats under the experiment. 3. ~~**#27281**: gates workspace ACL grants on matching member-level capability (each granted action only takes effect while the recipient holds that action in the org), so workspace sharing is ineffective for (and rejected toward) users without workspace capabilities, evaluated live on every authorization.~~ Tabled - excluded from the gateway-accounts MVP. This PR (#27278) stands alone: it hides the Workspaces page create CTAs for users without workspace-create permission and can merge in any order.
143 lines
3.4 KiB
JSON
143 lines
3.4 KiB
JSON
{
|
|
"viewAllUsers": {
|
|
"object": { "resource_type": "user" },
|
|
"action": "read"
|
|
},
|
|
"updateUsers": {
|
|
"object": { "resource_type": "user" },
|
|
"action": "update"
|
|
},
|
|
"createUser": {
|
|
"object": { "resource_type": "user" },
|
|
"action": "create"
|
|
},
|
|
"createTemplates": {
|
|
"object": { "resource_type": "template", "any_org": true },
|
|
"action": "create"
|
|
},
|
|
"createWorkspace": {
|
|
"object": {
|
|
"resource_type": "workspace",
|
|
"any_org": true,
|
|
"owner_id": "me"
|
|
},
|
|
"action": "create"
|
|
},
|
|
"updateTemplates": {
|
|
"object": { "resource_type": "template" },
|
|
"action": "update"
|
|
},
|
|
"deleteTemplates": {
|
|
"object": { "resource_type": "template" },
|
|
"action": "delete"
|
|
},
|
|
"viewDeploymentConfig": {
|
|
"object": { "resource_type": "deployment_config" },
|
|
"action": "read"
|
|
},
|
|
"editDeploymentConfig": {
|
|
"object": { "resource_type": "deployment_config" },
|
|
"action": "update"
|
|
},
|
|
"viewDeploymentStats": {
|
|
"object": { "resource_type": "deployment_stats" },
|
|
"action": "read"
|
|
},
|
|
"readWorkspaceProxies": {
|
|
"object": { "resource_type": "workspace_proxy" },
|
|
"action": "read"
|
|
},
|
|
"editWorkspaceProxies": {
|
|
"object": { "resource_type": "workspace_proxy" },
|
|
"action": "create"
|
|
},
|
|
"createOrganization": {
|
|
"object": { "resource_type": "organization" },
|
|
"action": "create"
|
|
},
|
|
"viewAnyGroup": {
|
|
"object": { "resource_type": "group" },
|
|
"action": "read"
|
|
},
|
|
"createGroup": {
|
|
"object": { "resource_type": "group" },
|
|
"action": "create"
|
|
},
|
|
"viewAllLicenses": {
|
|
"object": { "resource_type": "license" },
|
|
"action": "read"
|
|
},
|
|
"viewNotificationTemplate": {
|
|
"object": { "resource_type": "notification_template" },
|
|
"action": "read"
|
|
},
|
|
"viewOrganizationIDPSyncSettings": {
|
|
"object": { "resource_type": "idpsync_settings" },
|
|
"action": "read"
|
|
},
|
|
"viewAnyMembers": {
|
|
"object": { "resource_type": "organization_member", "any_org": true },
|
|
"action": "read"
|
|
},
|
|
"editAnyGroups": {
|
|
"object": { "resource_type": "group", "any_org": true },
|
|
"action": "update"
|
|
},
|
|
"assignAnyRoles": {
|
|
"object": { "resource_type": "assign_org_role", "any_org": true },
|
|
"action": "assign"
|
|
},
|
|
"viewAnyIdpSyncSettings": {
|
|
"object": { "resource_type": "idpsync_settings", "any_org": true },
|
|
"action": "read"
|
|
},
|
|
"editAnySettings": {
|
|
"object": { "resource_type": "organization", "any_org": true },
|
|
"action": "update"
|
|
},
|
|
"viewAnyAuditLog": {
|
|
"object": { "resource_type": "audit_log", "any_org": true },
|
|
"action": "read"
|
|
},
|
|
"viewAnyConnectionLog": {
|
|
"object": { "resource_type": "connection_log", "any_org": true },
|
|
"action": "read"
|
|
},
|
|
"viewDebugInfo": {
|
|
"object": { "resource_type": "debug_info" },
|
|
"action": "read"
|
|
},
|
|
"viewAnyAIBridgeInterception": {
|
|
"object": { "resource_type": "aibridge_interception", "any_org": true },
|
|
"action": "read"
|
|
},
|
|
"viewAnyAIProvider": {
|
|
"object": { "resource_type": "ai_provider" },
|
|
"action": "read"
|
|
},
|
|
"viewAIGatewayKeys": {
|
|
"object": { "resource_type": "ai_gateway_key" },
|
|
"action": "read"
|
|
},
|
|
"createOAuth2App": {
|
|
"object": { "resource_type": "oauth2_app" },
|
|
"action": "create"
|
|
},
|
|
"editOAuth2App": {
|
|
"object": { "resource_type": "oauth2_app" },
|
|
"action": "update"
|
|
},
|
|
"deleteOAuth2App": {
|
|
"object": { "resource_type": "oauth2_app" },
|
|
"action": "delete"
|
|
},
|
|
"viewOAuth2AppSecrets": {
|
|
"object": { "resource_type": "oauth2_app_secret" },
|
|
"action": "read"
|
|
},
|
|
"createChat": {
|
|
"object": { "resource_type": "chat", "any_org": true, "owner_id": "me" },
|
|
"action": "create"
|
|
}
|
|
}
|