From 1cffd11619e14609e6778f70830b6a4d38d00c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=B1=E3=82=A4=E3=83=A9?= Date: Thu, 31 Jul 2025 09:05:09 -0600 Subject: [PATCH 1/3] feat: add workspace sharing page (#19107) --- coderd/apidoc/docs.go | 77 ++++++++- coderd/apidoc/swagger.json | 67 +++++++- coderd/coderd.go | 6 + coderd/coderdtest/swaggerparser.go | 3 +- coderd/database/db2sdk/db2sdk.go | 24 +++ coderd/database/dbauthz/dbauthz.go | 12 ++ coderd/database/dbauthz/dbauthz_test.go | 16 ++ coderd/database/dbmetrics/querymetrics.go | 7 + coderd/database/dbmock/dbmock.go | 14 ++ coderd/database/modelmethods.go | 4 +- coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 21 +++ coderd/database/queries/workspaces.sql | 9 + coderd/database/types.go | 11 ++ coderd/rbac/regosql/acl_mapping_var.go | 19 ++- coderd/workspaces.go | 159 ++++++++++++++++++ codersdk/workspaces.go | 27 +++ docs/reference/api/enterprise.md | 8 +- docs/reference/api/schemas.md | 40 +++++ docs/reference/api/workspaces.md | 43 +++++ enterprise/coderd/templates.go | 65 ++++--- site/src/api/api.ts | 7 + site/src/api/queries/workspaces.ts | 9 + site/src/api/typesGenerated.ts | 11 ++ .../pages/WorkspaceSettingsPage/Sidebar.tsx | 17 +- .../WorkspaceSharingPage.tsx | 36 ++++ site/src/router.tsx | 7 + site/static/kirby.gif | Bin 0 -> 32512 bytes 28 files changed, 668 insertions(+), 52 deletions(-) create mode 100644 site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPage.tsx create mode 100644 site/static/kirby.gif diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index c30248734171a..fa2aad745ec5a 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5289,7 +5289,7 @@ const docTemplate = `{ "required": true }, { - "description": "Update template request", + "description": "Update template ACL request", "name": "request", "in": "body", "required": true, @@ -9942,6 +9942,50 @@ const docTemplate = `{ } } }, + "/workspaces/{workspace}/acl": { + "patch": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Workspaces" + ], + "summary": "Update workspace ACL", + "operationId": "update-workspace-acl", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Workspace ID", + "name": "workspace", + "in": "path", + "required": true + }, + { + "description": "Update workspace ACL request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.UpdateWorkspaceACL" + } + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/workspaces/{workspace}/autostart": { "put": { "security": [ @@ -17233,6 +17277,24 @@ const docTemplate = `{ } } }, + "codersdk.UpdateWorkspaceACL": { + "type": "object", + "properties": { + "group_roles": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/codersdk.WorkspaceRole" + } + }, + "user_roles": { + "description": "Keys must be valid UUIDs. To remove a user/group from the ACL use \"\" as the\nrole name (available as a constant named ` + "`" + `codersdk.WorkspaceRoleDeleted` + "`" + `)", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/codersdk.WorkspaceRole" + } + } + } + }, "codersdk.UpdateWorkspaceAutomaticUpdatesRequest": { "type": "object", "properties": { @@ -18965,6 +19027,19 @@ const docTemplate = `{ } } }, + "codersdk.WorkspaceRole": { + "type": "string", + "enum": [ + "admin", + "use", + "" + ], + "x-enum-varnames": [ + "WorkspaceRoleAdmin", + "WorkspaceRoleUse", + "WorkspaceRoleDeleted" + ] + }, "codersdk.WorkspaceStatus": { "type": "string", "enum": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 2212d91e35650..e1bcc5bf1013c 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -4658,7 +4658,7 @@ "required": true }, { - "description": "Update template request", + "description": "Update template ACL request", "name": "request", "in": "body", "required": true, @@ -8792,6 +8792,44 @@ } } }, + "/workspaces/{workspace}/acl": { + "patch": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Workspaces"], + "summary": "Update workspace ACL", + "operationId": "update-workspace-acl", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Workspace ID", + "name": "workspace", + "in": "path", + "required": true + }, + { + "description": "Update workspace ACL request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.UpdateWorkspaceACL" + } + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/workspaces/{workspace}/autostart": { "put": { "security": [ @@ -15731,6 +15769,24 @@ } } }, + "codersdk.UpdateWorkspaceACL": { + "type": "object", + "properties": { + "group_roles": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/codersdk.WorkspaceRole" + } + }, + "user_roles": { + "description": "Keys must be valid UUIDs. To remove a user/group from the ACL use \"\" as the\nrole name (available as a constant named `codersdk.WorkspaceRoleDeleted`)", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/codersdk.WorkspaceRole" + } + } + } + }, "codersdk.UpdateWorkspaceAutomaticUpdatesRequest": { "type": "object", "properties": { @@ -17363,6 +17419,15 @@ } } }, + "codersdk.WorkspaceRole": { + "type": "string", + "enum": ["admin", "use", ""], + "x-enum-varnames": [ + "WorkspaceRoleAdmin", + "WorkspaceRoleUse", + "WorkspaceRoleDeleted" + ] + }, "codersdk.WorkspaceStatus": { "type": "string", "enum": [ diff --git a/coderd/coderd.go b/coderd/coderd.go index 9115888fc566b..26bf4a7bf9b63 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1413,6 +1413,12 @@ func New(options *Options) *API { r.Delete("/", api.deleteWorkspaceAgentPortShare) }) r.Get("/timings", api.workspaceTimings) + r.Route("/acl", func(r chi.Router) { + r.Use( + httpmw.RequireExperiment(api.Experiments, codersdk.ExperimentWorkspaceSharing)) + + r.Patch("/", api.patchWorkspaceACL) + }) }) }) r.Route("/workspacebuilds/{workspacebuild}", func(r chi.Router) { diff --git a/coderd/coderdtest/swaggerparser.go b/coderd/coderdtest/swaggerparser.go index d7d46711a9df6..7cef0d8d9f9cb 100644 --- a/coderd/coderdtest/swaggerparser.go +++ b/coderd/coderdtest/swaggerparser.go @@ -360,7 +360,8 @@ func assertProduce(t *testing.T, comment SwaggerComment) { (comment.router == "/workspaceagents/me/startup/logs" && comment.method == "patch") || (comment.router == "/licenses/{id}" && comment.method == "delete") || (comment.router == "/debug/coordinator" && comment.method == "get") || - (comment.router == "/debug/tailnet" && comment.method == "get") { + (comment.router == "/debug/tailnet" && comment.method == "get") || + (comment.router == "/workspaces/{workspace}/acl" && comment.method == "patch") { return // Exception: HTTP 200 is returned without response entity } diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index 320a90b09430b..48f6ff44af70f 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -24,6 +24,7 @@ import ( "github.com/coder/coder/v2/coderd/rbac/policy" "github.com/coder/coder/v2/coderd/render" "github.com/coder/coder/v2/coderd/util/ptr" + "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/coderd/workspaceapps/appurl" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/provisionersdk/proto" @@ -781,6 +782,29 @@ func TemplateRoleActions(role codersdk.TemplateRole) []policy.Action { return []policy.Action{} } +func WorkspaceRoleActions(role codersdk.WorkspaceRole) []policy.Action { + switch role { + case codersdk.WorkspaceRoleAdmin: + return slice.Omit( + // Small note: This intentionally includes "create" because it's sort of + // double purposed as "can edit ACL". That's maybe a bit "incorrect", but + // it's what templates do already and we're copying that implementation. + rbac.ResourceWorkspace.AvailableActions(), + // Don't let anyone delete something they can't recreate. + policy.ActionDelete, + ) + case codersdk.WorkspaceRoleUse: + return []policy.Action{ + policy.ActionApplicationConnect, + policy.ActionRead, + policy.ActionSSH, + policy.ActionWorkspaceStart, + policy.ActionWorkspaceStop, + } + } + return []policy.Action{} +} + func ConnectionLogConnectionTypeFromAgentProtoConnectionType(typ agentproto.Connection_Type) (database.ConnectionType, error) { switch typ { case agentproto.Connection_SSH: diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 72489ea92d572..402097f13deae 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -4919,6 +4919,18 @@ func (q *querier) UpdateWorkspace(ctx context.Context, arg database.UpdateWorksp return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateWorkspace)(ctx, arg) } +func (q *querier) UpdateWorkspaceACLByID(ctx context.Context, arg database.UpdateWorkspaceACLByIDParams) error { + fetch := func(ctx context.Context, arg database.UpdateWorkspaceACLByIDParams) (database.WorkspaceTable, error) { + w, err := q.db.GetWorkspaceByID(ctx, arg.ID) + if err != nil { + return database.WorkspaceTable{}, err + } + return w.WorkspaceTable(), nil + } + + return fetchAndExec(q.log, q.auth, policy.ActionCreate, fetch, q.db.UpdateWorkspaceACLByID)(ctx, arg) +} + func (q *querier) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error { if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil { return err diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 14ab09bada09a..9e4f1f80fe05f 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -2146,6 +2146,22 @@ func (s *MethodTestSuite) TestWorkspace() { // no asserts here because SQLFilter check.Args([]uuid.UUID{}, emptyPreparedAuthorized{}).Asserts() })) + s.Run("UpdateWorkspaceACLByID", s.Subtest(func(db database.Store, check *expects) { + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: o.ID, + TemplateID: tpl.ID, + }) + check.Args(database.UpdateWorkspaceACLByIDParams{ + ID: ws.ID, + }).Asserts(ws, policy.ActionCreate) + })) s.Run("GetLatestWorkspaceBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) o := dbgen.Organization(s.T(), db, database.Organization{}) diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 3fffb29966735..574eeb069e47f 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -3029,6 +3029,13 @@ func (m queryMetricsStore) UpdateWorkspace(ctx context.Context, arg database.Upd return workspace, err } +func (m queryMetricsStore) UpdateWorkspaceACLByID(ctx context.Context, arg database.UpdateWorkspaceACLByIDParams) error { + start := time.Now() + r0 := m.s.UpdateWorkspaceACLByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceACLByID").Observe(time.Since(start).Seconds()) + return r0 +} + func (m queryMetricsStore) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error { start := time.Now() err := m.s.UpdateWorkspaceAgentConnectionByID(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 20bc17117e0eb..30589c9fbb8bf 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -6461,6 +6461,20 @@ func (mr *MockStoreMockRecorder) UpdateWorkspace(ctx, arg any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspace", reflect.TypeOf((*MockStore)(nil).UpdateWorkspace), ctx, arg) } +// UpdateWorkspaceACLByID mocks base method. +func (m *MockStore) UpdateWorkspaceACLByID(ctx context.Context, arg database.UpdateWorkspaceACLByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceACLByID", ctx, arg) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceACLByID indicates an expected call of UpdateWorkspaceACLByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceACLByID(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceACLByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceACLByID), ctx, arg) +} + // UpdateWorkspaceAgentConnectionByID mocks base method. func (m *MockStore) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error { m.ctrl.T.Helper() diff --git a/coderd/database/modelmethods.go b/coderd/database/modelmethods.go index 5347e8de37ebe..caf7ccce4c6a7 100644 --- a/coderd/database/modelmethods.go +++ b/coderd/database/modelmethods.go @@ -276,7 +276,9 @@ func (w WorkspaceTable) RBACObject() rbac.Object { return rbac.ResourceWorkspace.WithID(w.ID). InOrg(w.OrganizationID). - WithOwner(w.OwnerID.String()) + WithOwner(w.OwnerID.String()). + WithGroupACL(w.GroupACL.RBACACL()). + WithACLUserList(w.UserACL.RBACACL()) } func (w WorkspaceTable) DormantRBAC() rbac.Object { diff --git a/coderd/database/querier.go b/coderd/database/querier.go index a2c6cda1afc4b..d812ff1a96de9 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -628,6 +628,7 @@ type sqlcQuerier interface { UpdateUserThemePreference(ctx context.Context, arg UpdateUserThemePreferenceParams) (UserConfig, error) UpdateVolumeResourceMonitor(ctx context.Context, arg UpdateVolumeResourceMonitorParams) error UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (WorkspaceTable, error) + UpdateWorkspaceACLByID(ctx context.Context, arg UpdateWorkspaceACLByIDParams) error UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error UpdateWorkspaceAgentLogOverflowByID(ctx context.Context, arg UpdateWorkspaceAgentLogOverflowByIDParams) error diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 6033ab728007d..a7b61d6eabd50 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -20872,6 +20872,27 @@ func (q *sqlQuerier) UpdateWorkspace(ctx context.Context, arg UpdateWorkspacePar return i, err } +const updateWorkspaceACLByID = `-- name: UpdateWorkspaceACLByID :exec +UPDATE + workspaces +SET + group_acl = $1, + user_acl = $2 +WHERE + id = $3 +` + +type UpdateWorkspaceACLByIDParams struct { + GroupACL WorkspaceACL `db:"group_acl" json:"group_acl"` + UserACL WorkspaceACL `db:"user_acl" json:"user_acl"` + ID uuid.UUID `db:"id" json:"id"` +} + +func (q *sqlQuerier) UpdateWorkspaceACLByID(ctx context.Context, arg UpdateWorkspaceACLByIDParams) error { + _, err := q.db.ExecContext(ctx, updateWorkspaceACLByID, arg.GroupACL, arg.UserACL, arg.ID) + return err +} + const updateWorkspaceAutomaticUpdates = `-- name: UpdateWorkspaceAutomaticUpdates :exec UPDATE workspaces diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index 783cbc56e488c..b6b4f2de0888f 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -873,3 +873,12 @@ GROUP BY workspaces.id, workspaces.name, latest_build.job_status, latest_build.j -- name: GetWorkspacesByTemplateID :many SELECT * FROM workspaces WHERE template_id = $1 AND deleted = false; + +-- name: UpdateWorkspaceACLByID :exec +UPDATE + workspaces +SET + group_acl = @group_acl, + user_acl = @user_acl +WHERE + id = @id; diff --git a/coderd/database/types.go b/coderd/database/types.go index 11a0613965b8d..01a7cce231061 100644 --- a/coderd/database/types.go +++ b/coderd/database/types.go @@ -91,6 +91,17 @@ func (t *WorkspaceACL) Scan(src interface{}) error { return xerrors.Errorf("unexpected type %T", src) } +//nolint:revive +func (w WorkspaceACL) RBACACL() map[string][]policy.Action { + // Convert WorkspaceACL to a map of string to []policy.Action. + // This is used for RBAC checks. + rbacACL := make(map[string][]policy.Action, len(w)) + for id, entry := range w { + rbacACL[id] = entry.Permissions + } + return rbacACL +} + func (t WorkspaceACL) Value() (driver.Value, error) { return json.Marshal(t) } diff --git a/coderd/rbac/regosql/acl_mapping_var.go b/coderd/rbac/regosql/acl_mapping_var.go index 172ac4cc56915..301da929adfbd 100644 --- a/coderd/rbac/regosql/acl_mapping_var.go +++ b/coderd/rbac/regosql/acl_mapping_var.go @@ -15,14 +15,18 @@ var ( _ sqltypes.Node = ACLMappingVar{} ) -// ACLMappingVar is a variable matcher that handles group_acl and user_acl. -// The sql type is a jsonb object with the following structure: +// ACLMappingVar is a variable matcher that matches ACL map variables to their +// SQL storage. Usually the actual backing implementation is a pair of `jsonb` +// columns named `group_acl` and `user_acl`. Each column contains an object that +// looks like... // -// "group_acl": { -// "": [""] +// ```json +// +// { +// "": ["", ""] // } // -// This is a custom variable matcher as json objects have arbitrary complexity. +// ``` type ACLMappingVar struct { // SelectSQL is used to `SELECT` the ACL mapping from the table for the // given resource. ie. if the full query might look like `SELECT group_acl @@ -59,9 +63,10 @@ func (g ACLMappingVar) UsingSubfield(subfield string) ACLMappingVar { func (ACLMappingVar) UseAs() sqltypes.Node { return ACLMappingVar{} } func (g ACLMappingVar) ConvertVariable(rego ast.Ref) (sqltypes.Node, bool) { - // "left" will be a map of group names to actions in rego. + // left is the rego variable that maps the actor's id to the actions they + // are allowed to take. // { - // "all_users": ["read"] + // "": ["", ""] // } left, err := sqltypes.RegoVarPath(g.StructPath, rego) if err != nil { diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 0f3f0a24c75d3..2080926b44089 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -2041,6 +2041,104 @@ func (api *API) workspaceTimings(rw http.ResponseWriter, r *http.Request) { httpapi.Write(ctx, rw, http.StatusOK, timings) } +// @Summary Update workspace ACL +// @ID update-workspace-acl +// @Security CoderSessionToken +// @Accept json +// @Produce json +// @Tags Workspaces +// @Param workspace path string true "Workspace ID" format(uuid) +// @Param request body codersdk.UpdateWorkspaceACL true "Update workspace ACL request" +// @Success 204 +// @Router /workspaces/{workspace}/acl [patch] +func (api *API) patchWorkspaceACL(rw http.ResponseWriter, r *http.Request) { + var ( + ctx = r.Context() + workspace = httpmw.WorkspaceParam(r) + auditor = api.Auditor.Load() + aReq, commitAudit = audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ + Audit: *auditor, + Log: api.Logger, + Request: r, + Action: database.AuditActionWrite, + OrganizationID: workspace.OrganizationID, + }) + ) + defer commitAudit() + aReq.Old = workspace.WorkspaceTable() + + var req codersdk.UpdateWorkspaceACL + if !httpapi.Read(ctx, rw, r, &req) { + return + } + + validErrs := validateWorkspaceACLPerms(ctx, api.Database, req.UserRoles, "user_roles") + validErrs = append(validErrs, validateWorkspaceACLPerms( + ctx, + api.Database, + req.GroupRoles, + "group_roles", + )...) + + if len(validErrs) > 0 { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Invalid request to update template metadata!", + Validations: validErrs, + }) + return + } + + err := api.Database.InTx(func(tx database.Store) error { + var err error + workspace, err = tx.GetWorkspaceByID(ctx, workspace.ID) + if err != nil { + return xerrors.Errorf("get template by ID: %w", err) + } + + for id, role := range req.UserRoles { + if role == codersdk.WorkspaceRoleDeleted { + delete(workspace.UserACL, id) + continue + } + workspace.UserACL[id] = database.WorkspaceACLEntry{ + Permissions: db2sdk.WorkspaceRoleActions(role), + } + } + + for id, role := range req.GroupRoles { + if role == codersdk.WorkspaceRoleDeleted { + delete(workspace.GroupACL, id) + continue + } + workspace.GroupACL[id] = database.WorkspaceACLEntry{ + Permissions: db2sdk.WorkspaceRoleActions(role), + } + } + + err = tx.UpdateWorkspaceACLByID(ctx, database.UpdateWorkspaceACLByIDParams{ + ID: workspace.ID, + UserACL: workspace.UserACL, + GroupACL: workspace.GroupACL, + }) + if err != nil { + return xerrors.Errorf("update workspace ACL by ID: %w", err) + } + workspace, err = tx.GetWorkspaceByID(ctx, workspace.ID) + if err != nil { + return xerrors.Errorf("get updated workspace by ID: %w", err) + } + return nil + }, nil) + if err != nil { + httpapi.InternalServerError(rw, err) + return + } + + aReq.New = workspace.WorkspaceTable() + + rw.WriteHeader(http.StatusNoContent) +} + type workspaceData struct { templates []database.Template builds []codersdk.WorkspaceBuild @@ -2379,3 +2477,64 @@ func (api *API) publishWorkspaceAgentLogsUpdate(ctx context.Context, workspaceAg api.Logger.Warn(ctx, "failed to publish workspace agent logs update", slog.F("workspace_agent_id", workspaceAgentID), slog.Error(err)) } } + +func validateWorkspaceACLPerms(ctx context.Context, db database.Store, perms map[string]codersdk.WorkspaceRole, field string) []codersdk.ValidationError { + // nolint:gocritic // Validate requires full read access to users and groups + ctx = dbauthz.AsSystemRestricted(ctx) + var validErrs []codersdk.ValidationError + for idStr, role := range perms { + if err := validateWorkspaceRole(role); err != nil { + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: err.Error()}) + continue + } + + id, err := uuid.Parse(idStr) + if err != nil { + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: idStr + "is not a valid UUID."}) + continue + } + + switch field { + case "user_roles": + // TODO(lilac): put this back after Kirby button shenanigans are over + // This could get slow if we get a ton of user perm updates. + // _, err = db.GetUserByID(ctx, id) + // if err != nil { + // validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: fmt.Sprintf("Failed to find resource with ID %q: %v", idStr, err.Error())}) + // continue + // } + case "group_roles": + // This could get slow if we get a ton of group perm updates. + _, err = db.GetGroupByID(ctx, id) + if err != nil { + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: fmt.Sprintf("Failed to find resource with ID %q: %v", idStr, err.Error())}) + continue + } + default: + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: "invalid field"}) + } + } + + return validErrs +} + +func validateWorkspaceRole(role codersdk.WorkspaceRole) error { + actions := db2sdk.WorkspaceRoleActions(role) + if len(actions) == 0 && role != codersdk.WorkspaceRoleDeleted { + return xerrors.Errorf("role %q is not a valid Workspace role", role) + } + + return nil +} + +// TODO: This will go here +// func convertToWorkspaceRole(actions []policy.Action) codersdk.TemplateRole { +// switch { +// case len(actions) == 2 && slice.SameElements(actions, []policy.Action{policy.ActionUse, policy.ActionRead}): +// return codersdk.TemplateRoleUse +// case len(actions) == 1 && actions[0] == policy.WildcardSymbol: +// return codersdk.TemplateRoleAdmin +// } + +// return "" +// } diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index dee2e1b838cb9..13cb778ab0ae0 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -662,3 +662,30 @@ func (c *Client) WorkspaceTimings(ctx context.Context, id uuid.UUID) (WorkspaceB var timings WorkspaceBuildTimings return timings, json.NewDecoder(res.Body).Decode(&timings) } + +type UpdateWorkspaceACL struct { + // Keys must be valid UUIDs. To remove a user/group from the ACL use "" as the + // role name (available as a constant named `codersdk.WorkspaceRoleDeleted`) + UserRoles map[string]WorkspaceRole `json:"user_roles,omitempty"` + GroupRoles map[string]WorkspaceRole `json:"group_roles,omitempty"` +} + +type WorkspaceRole string + +const ( + WorkspaceRoleAdmin WorkspaceRole = "admin" + WorkspaceRoleUse WorkspaceRole = "use" + WorkspaceRoleDeleted WorkspaceRole = "" +) + +func (c *Client) UpdateWorkspaceACL(ctx context.Context, workspaceID uuid.UUID, req UpdateWorkspaceACL) error { + res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/workspaces/%s/acl", workspaceID), req) + if err != nil { + return err + } + defer res.Body.Close() + if res.StatusCode != http.StatusNoContent { + return ReadBodyAsError(res) + } + return nil +} diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index c9b65a97d2f03..0ffae1116097d 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -3582,10 +3582,10 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template}/acl \ ### Parameters -| Name | In | Type | Required | Description | -|------------|------|--------------------------------------------------------------------|----------|-------------------------| -| `template` | path | string(uuid) | true | Template ID | -| `body` | body | [codersdk.UpdateTemplateACL](schemas.md#codersdkupdatetemplateacl) | true | Update template request | +| Name | In | Type | Required | Description | +|------------|------|--------------------------------------------------------------------|----------|-----------------------------| +| `template` | path | string(uuid) | true | Template ID | +| `body` | body | [codersdk.UpdateTemplateACL](schemas.md#codersdkupdatetemplateacl) | true | Update template ACL request | ### Example responses diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 5d9866658c71c..581743ea7cc22 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -8149,6 +8149,30 @@ Restarts will only happen on weekdays in this list on weeks which line up with W The schedule must be daily with a single time, and should have a timezone specified via a CRON_TZ prefix (otherwise UTC will be used). If the schedule is empty, the user will be updated to use the default schedule.| +## codersdk.UpdateWorkspaceACL + +```json +{ + "group_roles": { + "property1": "admin", + "property2": "admin" + }, + "user_roles": { + "property1": "admin", + "property2": "admin" + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|--------------------|--------------------------------------------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| `group_roles` | object | false | | | +| » `[any property]` | [codersdk.WorkspaceRole](#codersdkworkspacerole) | false | | | +| `user_roles` | object | false | | Keys must be valid UUIDs. To remove a user/group from the ACL use "" as the role name (available as a constant named `codersdk.WorkspaceRoleDeleted`) | +| » `[any property]` | [codersdk.WorkspaceRole](#codersdkworkspacerole) | false | | | + ## codersdk.UpdateWorkspaceAutomaticUpdatesRequest ```json @@ -10548,6 +10572,22 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `sensitive` | boolean | false | | | | `value` | string | false | | | +## codersdk.WorkspaceRole + +```json +"admin" +``` + +### Properties + +#### Enumerated Values + +| Value | +|---------| +| `admin` | +| `use` | +| `` | + ## codersdk.WorkspaceStatus ```json diff --git a/docs/reference/api/workspaces.md b/docs/reference/api/workspaces.md index d7187259b5bb6..70338fdeb1814 100644 --- a/docs/reference/api/workspaces.md +++ b/docs/reference/api/workspaces.md @@ -1514,6 +1514,49 @@ curl -X PATCH http://coder-server:8080/api/v2/workspaces/{workspace} \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Update workspace ACL + +### Code samples + +```shell +# Example request using curl +curl -X PATCH http://coder-server:8080/api/v2/workspaces/{workspace}/acl \ + -H 'Content-Type: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`PATCH /workspaces/{workspace}/acl` + +> Body parameter + +```json +{ + "group_roles": { + "property1": "admin", + "property2": "admin" + }, + "user_roles": { + "property1": "admin", + "property2": "admin" + } +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +|-------------|------|----------------------------------------------------------------------|----------|------------------------------| +| `workspace` | path | string(uuid) | true | Workspace ID | +| `body` | body | [codersdk.UpdateWorkspaceACL](schemas.md#codersdkupdateworkspaceacl) | true | Update workspace ACL request | + +### Responses + +| Status | Meaning | Description | Schema | +|--------|-----------------------------------------------------------------|-------------|--------| +| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Update workspace autostart schedule by ID ### Code samples diff --git a/enterprise/coderd/templates.go b/enterprise/coderd/templates.go index 4514ba928e21a..438a7cfd5c65f 100644 --- a/enterprise/coderd/templates.go +++ b/enterprise/coderd/templates.go @@ -184,7 +184,7 @@ func (api *API) templateACL(rw http.ResponseWriter, r *http.Request) { // @Produce json // @Tags Enterprise // @Param template path string true "Template ID" format(uuid) -// @Param request body codersdk.UpdateTemplateACL true "Update template request" +// @Param request body codersdk.UpdateTemplateACL true "Update template ACL request" // @Success 200 {object} codersdk.Response // @Router /templates/{template}/acl [patch] func (api *API) patchTemplateACL(rw http.ResponseWriter, r *http.Request) { @@ -208,9 +208,13 @@ func (api *API) patchTemplateACL(rw http.ResponseWriter, r *http.Request) { return } - validErrs := validateTemplateACLPerms(ctx, api.Database, req.UserPerms, "user_perms", true) - validErrs = append(validErrs, - validateTemplateACLPerms(ctx, api.Database, req.GroupPerms, "group_perms", false)...) + validErrs := validateTemplateACLPerms(ctx, api.Database, req.UserPerms, "user_perms") + validErrs = append(validErrs, validateTemplateACLPerms( + ctx, + api.Database, + req.GroupPerms, + "group_perms", + )...) if len(validErrs) > 0 { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -227,28 +231,20 @@ func (api *API) patchTemplateACL(rw http.ResponseWriter, r *http.Request) { return xerrors.Errorf("get template by ID: %w", err) } - if len(req.UserPerms) > 0 { - for id, role := range req.UserPerms { - // A user with an empty string implies - // deletion. - if role == "" { - delete(template.UserACL, id) - continue - } - template.UserACL[id] = db2sdk.TemplateRoleActions(role) + for id, role := range req.UserPerms { + if role == codersdk.TemplateRoleDeleted { + delete(template.UserACL, id) + continue } + template.UserACL[id] = db2sdk.TemplateRoleActions(role) } - if len(req.GroupPerms) > 0 { - for id, role := range req.GroupPerms { - // An id with an empty string implies - // deletion. - if role == "" { - delete(template.GroupACL, id) - continue - } - template.GroupACL[id] = db2sdk.TemplateRoleActions(role) + for id, role := range req.GroupPerms { + if role == codersdk.TemplateRoleDeleted { + delete(template.GroupACL, id) + continue } + template.GroupACL[id] = db2sdk.TemplateRoleActions(role) } err = tx.UpdateTemplateACLByID(ctx, database.UpdateTemplateACLByIDParams{ @@ -277,38 +273,39 @@ func (api *API) patchTemplateACL(rw http.ResponseWriter, r *http.Request) { }) } -// nolint TODO fix stupid flag. -func validateTemplateACLPerms(ctx context.Context, db database.Store, perms map[string]codersdk.TemplateRole, field string, isUser bool) []codersdk.ValidationError { - // Validate requires full read access to users and groups - // nolint:gocritic +func validateTemplateACLPerms(ctx context.Context, db database.Store, perms map[string]codersdk.TemplateRole, field string) []codersdk.ValidationError { + // nolint:gocritic // Validate requires full read access to users and groups ctx = dbauthz.AsSystemRestricted(ctx) var validErrs []codersdk.ValidationError - for k, v := range perms { - if err := validateTemplateRole(v); err != nil { + for idStr, role := range perms { + if err := validateTemplateRole(role); err != nil { validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: err.Error()}) continue } - id, err := uuid.Parse(k) + id, err := uuid.Parse(idStr) if err != nil { - validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: "ID " + k + "must be a valid UUID."}) + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: idStr + "is not a valid UUID."}) continue } - if isUser { + switch field { + case "user_perms": // This could get slow if we get a ton of user perm updates. _, err = db.GetUserByID(ctx, id) if err != nil { - validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: fmt.Sprintf("Failed to find resource with ID %q: %v", k, err.Error())}) + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: fmt.Sprintf("Failed to find resource with ID %q: %v", idStr, err.Error())}) continue } - } else { + case "group_perms": // This could get slow if we get a ton of group perm updates. _, err = db.GetGroupByID(ctx, id) if err != nil { - validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: fmt.Sprintf("Failed to find resource with ID %q: %v", k, err.Error())}) + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: fmt.Sprintf("Failed to find resource with ID %q: %v", idStr, err.Error())}) continue } + default: + validErrs = append(validErrs, codersdk.ValidationError{Field: field, Detail: "invalid field"}) } } diff --git a/site/src/api/api.ts b/site/src/api/api.ts index cd70bfaf00600..2b21ddf1e8a08 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1896,6 +1896,13 @@ class ApiMethods { return response.data; }; + updateWorkspaceACL = async ( + workspaceId: string, + data: TypesGen.UpdateWorkspaceACL, + ): Promise => { + await this.axios.patch(`/api/v2/workspaces/${workspaceId}/acl`, data); + }; + getApplicationsHost = async (): Promise => { const response = await this.axios.get("/api/v2/applications/host"); return response.data; diff --git a/site/src/api/queries/workspaces.ts b/site/src/api/queries/workspaces.ts index 05fb09314d741..536925a97390f 100644 --- a/site/src/api/queries/workspaces.ts +++ b/site/src/api/queries/workspaces.ts @@ -3,6 +3,7 @@ import { DetailedError, isApiValidationError } from "api/errors"; import type { CreateWorkspaceRequest, ProvisionerLogLevel, + UpdateWorkspaceACL, UsageAppName, Workspace, WorkspaceAgentLog, @@ -421,3 +422,11 @@ export const workspacePermissions = (workspace?: Workspace) => { staleTime: Number.POSITIVE_INFINITY, }; }; + +export const updateWorkspaceACL = (workspaceId: string) => { + return { + mutationFn: async (patch: UpdateWorkspaceACL) => { + await API.updateWorkspaceACL(workspaceId, patch); + }, + }; +}; diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index bd14a6edf0267..db901630b71cf 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -3230,6 +3230,12 @@ export interface UpdateUserQuietHoursScheduleRequest { readonly schedule: string; } +// From codersdk/workspaces.go +export interface UpdateWorkspaceACL { + readonly user_roles?: Record; + readonly group_roles?: Record; +} + // From codersdk/workspaces.go export interface UpdateWorkspaceAutomaticUpdatesRequest { readonly automatic_updates: AutomaticUpdates; @@ -3970,6 +3976,11 @@ export interface WorkspaceResourceMetadata { readonly sensitive: boolean; } +// From codersdk/workspaces.go +export type WorkspaceRole = "admin" | "" | "use"; + +export const WorkspaceRoles: WorkspaceRole[] = ["admin", "", "use"]; + // From codersdk/workspacebuilds.go export type WorkspaceStatus = | "canceled" diff --git a/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx b/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx index 91aea9ac9cf12..32261577da9b2 100644 --- a/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx +++ b/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx @@ -5,9 +5,13 @@ import { SidebarHeader, SidebarNavItem, } from "components/Sidebar/Sidebar"; -import { CodeIcon as ParameterIcon } from "lucide-react"; -import { SettingsIcon as GeneralIcon } from "lucide-react"; -import { TimerIcon as ScheduleIcon } from "lucide-react"; +import { + SettingsIcon as GeneralIcon, + CodeIcon as ParameterIcon, + TimerIcon as ScheduleIcon, + Users as SharingIcon, +} from "lucide-react"; +import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; interface SidebarProps { @@ -16,6 +20,8 @@ interface SidebarProps { } export const Sidebar: FC = ({ username, workspace }) => { + const { experiments } = useDashboard(); + return ( = ({ username, workspace }) => { Schedule + {experiments.includes("workspace-sharing") && ( + + Sharing + + )} ); }; diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPage.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPage.tsx new file mode 100644 index 0000000000000..74f240050c601 --- /dev/null +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPage.tsx @@ -0,0 +1,36 @@ +import { updateWorkspaceACL } from "api/queries/workspaces"; +import { Button } from "components/Button/Button"; +import { ExternalImage } from "components/ExternalImage/ExternalImage"; +import type { FC } from "react"; +import { useMutation } from "react-query"; +import { useWorkspaceSettings } from "../WorkspaceSettingsLayout"; + +const localKirbyId = "1ce34e51-3135-4720-8bfc-eabce178eafb"; +const devKirbyId = "7a4319a5-0dc1-41e1-95e4-f31e312b0ecc"; + +const WorkspaceSharingPage: FC = () => { + const workspace = useWorkspaceSettings(); + const shareWithKirbyMutation = useMutation(updateWorkspaceACL(workspace.id)); + + const onClick = () => { + shareWithKirbyMutation.mutate({ + user_roles: { + [localKirbyId]: "admin", + [devKirbyId]: "admin", + }, + }); + }; + + return ( + + ); +}; + +export default WorkspaceSharingPage; diff --git a/site/src/router.tsx b/site/src/router.tsx index 90a8bda22c1f3..9f92c80f35f0f 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -86,6 +86,12 @@ const WorkspaceParametersExperimentRouter = lazy( "./pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersExperimentRouter" ), ); +const WorkspaceSharingPage = lazy( + () => + import( + "./pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPage" + ), +); const TerminalPage = lazy(() => import("./pages/TerminalPage/TerminalPage")); const TemplatePermissionsPage = lazy( () => @@ -547,6 +553,7 @@ export const router = createBrowserRouter( element={} /> } /> + } /> diff --git a/site/static/kirby.gif b/site/static/kirby.gif new file mode 100644 index 0000000000000000000000000000000000000000..b6fe7e93e1fa1f22d1dd85c3d8da48eb49365752 GIT binary patch literal 32512 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 Date: Thu, 31 Jul 2025 18:46:39 +0100 Subject: [PATCH 2/3] docs: remove deprecated JFrog Xray integration documentation (#19113) --- docs/admin/integrations/jfrog-xray.md | 68 ------------------ .../guides/xray-integration/example.png | Bin 116060 -> 0 bytes docs/manifest.json | 10 --- 3 files changed, 78 deletions(-) delete mode 100644 docs/admin/integrations/jfrog-xray.md delete mode 100644 docs/images/guides/xray-integration/example.png diff --git a/docs/admin/integrations/jfrog-xray.md b/docs/admin/integrations/jfrog-xray.md deleted file mode 100644 index 194ea25bf8b6b..0000000000000 --- a/docs/admin/integrations/jfrog-xray.md +++ /dev/null @@ -1,68 +0,0 @@ -# Integrating JFrog Xray with Coder Kubernetes Workspaces - - -March 17, 2024 - ---- - -This guide describes the process of integrating [JFrog Xray](https://jfrog.com/xray/) to Coder Kubernetes-backed -workspaces using Coder's [JFrog Xray Integration](https://github.com/coder/coder-xray). - -## Prerequisites - -- A self-hosted JFrog Platform instance. -- Kubernetes workspaces running on Coder. - -## Deploy the **Coder - JFrog Xray** Integration - -1. Create a JFrog Platform [Access Token](https://jfrog.com/help/r/jfrog-platform-administration-documentation/access-tokens) with a user that has the `read` [permission](https://jfrog.com/help/r/jfrog-platform-administration-documentation/permissions) - for the repositories you want to scan. - -1. Create a Coder [token](../../reference/cli/tokens_create.md#tokens-create) with a user that has the [`owner`](../users/index.md#roles) role. - -1. Create Kubernetes secrets for the JFrog Xray and Coder tokens. - - ```bash - kubectl create secret generic coder-token \ - --from-literal=coder-token='' - ``` - - ```bash - kubectl create secret generic jfrog-token \ - --from-literal=user='' \ - --from-literal=token='' - ``` - -1. Deploy the **Coder - JFrog Xray** integration. - - ```bash - helm repo add coder-xray https://helm.coder.com/coder-xray - ``` - - ```bash - helm upgrade --install coder-xray coder-xray/coder-xray \ - --namespace coder-xray \ - --create-namespace \ - --set namespace="" \ - --set coder.url="https://" \ - --set coder.secretName="coder-token" \ - --set artifactory.url="https://" \ - --set artifactory.secretName="jfrog-token" - ``` - -> [!IMPORTANT] -> To authenticate with the Artifactory registry, you may need to -> create a [Docker config](https://jfrog.com/help/r/jfrog-artifactory-documentation/docker-advanced-topics) and use it in the -> `imagePullSecrets` field of the Kubernetes Pod. -> See the [Defining ImagePullSecrets for Coder workspaces](../../tutorials/image-pull-secret.md) guide for more information. - -## Validate your installation - -Once installed, configured workspaces will now have a banner appear on any -workspace with vulnerabilities reported by JFrog Xray. - -JFrog Xray Integration diff --git a/docs/images/guides/xray-integration/example.png b/docs/images/guides/xray-integration/example.png deleted file mode 100644 index 58c28d332feb5d84a454a4815092fb4d57c8aca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116060 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 diff --git a/docs/manifest.json b/docs/manifest.json index 04e10f4387949..189614f9191d1 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -699,11 +699,6 @@ "description": "Integrate Coder with JFrog Artifactory", "path": "./admin/integrations/jfrog-artifactory.md" }, - { - "title": "JFrog Xray", - "description": "Integrate Coder with JFrog Xray", - "path": "./admin/integrations/jfrog-xray.md" - }, { "title": "Island Secure Browser", "description": "Integrate Coder with Island's Secure Browser", @@ -954,11 +949,6 @@ "description": "Deploy Coder on Azure with an Application Gateway", "path": "./install/kubernetes/kubernetes-azure-app-gateway.md" }, - { - "title": "Scanning Workspaces with JFrog Xray", - "description": "Integrate Coder with JFrog Xray", - "path": "./admin/integrations/jfrog-xray.md" - }, { "title": "Cloning Git Repositories", "description": "Learn how to clone Git repositories in Coder", From a185d3a2c339f2b66fb6f79e7b7c046a2887b110 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Thu, 31 Jul 2025 21:20:27 +0100 Subject: [PATCH 3/3] fix(site): ensure notification settings page follows RBAC correctly (#19097) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure template admin and user admins are able to see the correct notification groups on the notification settings page. --------- Co-authored-by: ケイラ --- .../NotificationsPage.stories.tsx | 16 ++++++++-- .../NotificationsPage/NotificationsPage.tsx | 31 +++++++++++++------ site/src/testHelpers/entities.ts | 26 ++++++++++++++++ 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx index e2ac02e773d2d..72f26f791e960 100644 --- a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx +++ b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.stories.tsx @@ -40,7 +40,7 @@ const meta = { }, ], user: MockUserOwner, - permissions: { viewDeploymentConfig: true }, + permissions: { createTemplates: true, createUser: true }, }, decorators: [withGlobalSnackbar, withAuthProvider, withDashboardProvider], } satisfies Meta; @@ -74,7 +74,19 @@ export const ToggleNotification: Story = { export const NonAdmin: Story = { parameters: { - permissions: { viewDeploymentConfig: false }, + permissions: { createTemplates: false, createUser: false }, + }, +}; + +export const TemplateAdmin: Story = { + parameters: { + permissions: { createTemplates: true, createUser: false }, + }, +}; + +export const UserAdmin: Story = { + parameters: { + permissions: { createTemplates: false, createUser: true }, }, }; diff --git a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx index 1a89c2240c8d1..4e4b1e6bc61bd 100644 --- a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx @@ -28,6 +28,7 @@ import { methodIcons, methodLabels, } from "modules/notifications/utils"; +import type { Permissions } from "modules/permissions"; import { type FC, Fragment } from "react"; import { useEffect } from "react"; import { Helmet } from "react-helmet-async"; @@ -46,15 +47,7 @@ const NotificationsPage: FC = () => { }, { ...systemNotificationTemplates(), - select: (data: NotificationTemplate[]) => { - const groups = selectTemplatesByGroup(data); - return permissions.viewDeploymentConfig - ? groups - : { - // Members only have access to the "Workspace Notifications" group - "Workspace Events": groups["Workspace Events"], - }; - }, + select: (data: NotificationTemplate[]) => selectTemplatesByGroup(data), }, notificationDispatchMethods(), ], @@ -103,6 +96,10 @@ const NotificationsPage: FC = () => { {ready ? ( {Object.entries(templatesByGroup.data).map(([group, templates]) => { + if (!canSeeNotificationGroup(group, permissions)) { + return null; + } + const allDisabled = templates.some((tpl) => { return notificationIsDisabled(disabledPreferences.data, tpl); }); @@ -211,6 +208,22 @@ const NotificationsPage: FC = () => { export default NotificationsPage; +function canSeeNotificationGroup( + group: string, + permissions: Permissions, +): boolean { + switch (group) { + case "Workspace Events": + return true; + case "Template Events": + return permissions.createTemplates; + case "User Events": + return permissions.createUser; + default: + return false; + } +} + function notificationIsDisabled( disabledPreferences: Record, tmpl: NotificationTemplate, diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 78dd9e4e8687a..f3f40e18bac27 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -4404,6 +4404,32 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [ kind: "system", enabled_by_default: true, }, + { + id: "template-event-1", + name: "Template Version Created", + title_template: 'Template version "{{.Labels.version_name}}" created', + body_template: + 'Hi {{.UserName}}\nA new version of template "{{.Labels.template_name}}" has been created.', + actions: + '[{"url": "{{ base_url }}/templates/{{.Labels.template_name}}", "label": "View template"}]', + group: "Template Events", + method: "smtp", + kind: "system", + enabled_by_default: true, + }, + { + id: "template-event-2", + name: "Template Updated", + title_template: 'Template "{{.Labels.template_name}}" updated', + body_template: + 'Hi {{.UserName}}\nTemplate "{{.Labels.template_name}}" has been updated.', + actions: + '[{"url": "{{ base_url }}/templates/{{.Labels.template_name}}", "label": "View template"}]', + group: "Template Events", + method: "webhook", + kind: "system", + enabled_by_default: true, + }, ]; export const MockNotificationMethodsResponse: TypesGen.NotificationMethodsResponse =