From 233962ce2b1bbedf9ddf7e9eba85f270d39f61b7 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 12 Aug 2022 15:02:06 -0500 Subject: [PATCH 01/10] Add migration for removing the 'admin' role --- .../000034_remove_admin_role.down.sql | 22 +++++++++++++++++++ .../000034_remove_admin_role.up.sql | 20 +++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 coderd/database/migrations/000034_remove_admin_role.down.sql create mode 100644 coderd/database/migrations/000034_remove_admin_role.up.sql diff --git a/coderd/database/migrations/000034_remove_admin_role.down.sql b/coderd/database/migrations/000034_remove_admin_role.down.sql new file mode 100644 index 0000000000000..5fcd85730dee7 --- /dev/null +++ b/coderd/database/migrations/000034_remove_admin_role.down.sql @@ -0,0 +1,22 @@ +UPDATE + users +SET + -- Replace 'template-admin' and 'user-admin' role with 'admin' + rbac_roles = array_append( + array_remove( + array_remove(users.rbac_roles, 'template-admin'), + 'user-admin' + ), 'admin') +WHERE + -- Only on existing admins + ARRAY ['template-admin', 'user-admin'] <@ rbac_roles; + + +UPDATE + users +SET + -- Replace 'owner' with 'admin + rbac_roles = array_replace(rbac_roles, 'owner', 'admin') +WHERE + -- Only on the owner + 'owner' = ANY(rbac_roles); diff --git a/coderd/database/migrations/000034_remove_admin_role.up.sql b/coderd/database/migrations/000034_remove_admin_role.up.sql new file mode 100644 index 0000000000000..652295fc01444 --- /dev/null +++ b/coderd/database/migrations/000034_remove_admin_role.up.sql @@ -0,0 +1,20 @@ +UPDATE + users +SET + -- Replace the role 'admin' with the role 'owner' + rbac_roles = array_replace(rbac_roles, 'admin', 'owner') +WHERE + -- Update the first user with the role 'admin'. This should be the first + -- user ever, but if that user was demoted from an admin, then choose + -- the next best user. + id = (SELECT id FROM users WHERE 'admin' = ANY(rbac_roles) ORDER BY created_at ASC LIMIT 1); + + +UPDATE + users +SET + -- Replace 'admin' role with 'template-admin' and 'user-admin' + rbac_roles = array_cat(array_remove(users.rbac_roles, 'admin'), ARRAY ['template-admin', 'user-admin']) +WHERE + -- Only on existing admins + 'admin' = ANY(rbac_roles); From 5ca12ce9eed4cbc40653d4c3d6c4fe18b07f4177 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 12 Aug 2022 16:13:32 -0500 Subject: [PATCH 02/10] Rename admin role -> owner --- coderd/httpmw/authorize_test.go | 2 +- coderd/provisionerjobs_internal_test.go | 4 +++- coderd/rbac/authz_internal_test.go | 6 +++--- coderd/rbac/builtin.go | 16 +++++++-------- coderd/rbac/builtin_internal_test.go | 2 +- coderd/rbac/builtin_test.go | 8 ++++---- coderd/roles_test.go | 2 +- coderd/templates_test.go | 4 ++-- coderd/users.go | 2 +- coderd/users_internal_test.go | 4 ++-- coderd/users_test.go | 26 ++++++++++++------------- coderd/workspaces_test.go | 6 +++--- 12 files changed, 42 insertions(+), 40 deletions(-) diff --git a/coderd/httpmw/authorize_test.go b/coderd/httpmw/authorize_test.go index 997ac44350340..2077926e6f989 100644 --- a/coderd/httpmw/authorize_test.go +++ b/coderd/httpmw/authorize_test.go @@ -40,7 +40,7 @@ func TestExtractUserRoles(t *testing.T) { { Name: "Admin", AddUser: func(db database.Store) (database.User, []string, string) { - roles := []string{rbac.RoleAdmin()} + roles := []string{rbac.RoleOwner()} user, token := addUser(t, db, roles...) return user, append(roles, rbac.RoleMember()), token }, diff --git a/coderd/provisionerjobs_internal_test.go b/coderd/provisionerjobs_internal_test.go index 4d215f6bb2a92..751915fc73c05 100644 --- a/coderd/provisionerjobs_internal_test.go +++ b/coderd/provisionerjobs_internal_test.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/coder/coder/coderd/rbac" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -77,7 +79,7 @@ func TestProvisionerJobLogs_Unit(t *testing.T) { require.NoError(t, err) _, err = fDB.InsertUser(ctx, database.InsertUserParams{ ID: userID, - RBACRoles: []string{"admin"}, + RBACRoles: []string{rbac.RoleOwner()}, }) require.NoError(t, err) _, err = fDB.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ diff --git a/coderd/rbac/authz_internal_test.go b/coderd/rbac/authz_internal_test.go index 3b66031f3cd39..a3aca022c7ce8 100644 --- a/coderd/rbac/authz_internal_test.go +++ b/coderd/rbac/authz_internal_test.go @@ -87,7 +87,7 @@ func TestFilter(t *testing.T) { { Name: "Admin", SubjectID: userIDs[0].String(), - Roles: []string{RoleOrgMember(orgIDs[0]), "auditor", RoleAdmin(), RoleMember()}, + Roles: []string{RoleOrgMember(orgIDs[0]), "auditor", RoleOwner(), RoleMember()}, ObjectType: ResourceWorkspace.Type, Action: ActionRead, }, @@ -292,7 +292,7 @@ func TestAuthorizeDomain(t *testing.T) { user = subject{ UserID: "me", Roles: []Role{ - must(RoleByName(RoleAdmin())), + must(RoleByName(RoleOwner())), must(RoleByName(RoleMember())), }, } @@ -499,7 +499,7 @@ func TestAuthorizeLevels(t *testing.T) { user := subject{ UserID: "me", Roles: []Role{ - must(RoleByName(RoleAdmin())), + must(RoleByName(RoleOwner())), { Name: "org-deny:" + defOrg.String(), Org: map[string][]Permission{ diff --git a/coderd/rbac/builtin.go b/coderd/rbac/builtin.go index 1f3f34fd9ffb7..24f45a300d3b1 100644 --- a/coderd/rbac/builtin.go +++ b/coderd/rbac/builtin.go @@ -9,7 +9,7 @@ import ( ) const ( - admin string = "admin" + owner string = "owner" member string = "member" templateAdmin string = "template-admin" userAdmin string = "user-admin" @@ -24,8 +24,8 @@ const ( // Once we have a database implementation, the "default" roles can be defined on the // site and orgs, and these functions can be removed. -func RoleAdmin() string { - return roleName(admin, "") +func RoleOwner() string { + return roleName(owner, "") } func RoleTemplateAdmin() string { @@ -59,10 +59,10 @@ var ( // https://github.com/coder/coder/issues/1194 builtInRoles = map[string]func(orgID string) Role{ // admin grants all actions to all resources. - admin: func(_ string) Role { + owner: func(_ string) Role { return Role{ - Name: admin, - DisplayName: "Admin", + Name: owner, + DisplayName: "Owner", Site: permissions(map[Object][]Action{ ResourceWildcard: {WildcardSymbol}, }), @@ -187,8 +187,8 @@ var ( // The first key is the actor role, the second is the roles they can assign. // map[actor_role][assign_role] assignRoles = map[string]map[string]bool{ - admin: { - admin: true, + owner: { + owner: true, auditor: true, member: true, orgAdmin: true, diff --git a/coderd/rbac/builtin_internal_test.go b/coderd/rbac/builtin_internal_test.go index 2e49949d6cc04..0921cb361a6fc 100644 --- a/coderd/rbac/builtin_internal_test.go +++ b/coderd/rbac/builtin_internal_test.go @@ -16,7 +16,7 @@ func TestRoleByName(t *testing.T) { testCases := []struct { Role Role }{ - {Role: builtInRoles[admin]("")}, + {Role: builtInRoles[owner]("")}, {Role: builtInRoles[member]("")}, {Role: builtInRoles[templateAdmin]("")}, {Role: builtInRoles[userAdmin]("")}, diff --git a/coderd/rbac/builtin_test.go b/coderd/rbac/builtin_test.go index de0bb076d82a9..9936c2e1385cb 100644 --- a/coderd/rbac/builtin_test.go +++ b/coderd/rbac/builtin_test.go @@ -41,7 +41,7 @@ func BenchmarkRBACFilter(b *testing.B) { { Name: "Admin", // Give some extra roles that an admin might have - Roles: []string{rbac.RoleOrgMember(orgs[0]), "auditor", rbac.RoleAdmin(), rbac.RoleMember()}, + Roles: []string{rbac.RoleOrgMember(orgs[0]), "auditor", rbac.RoleOwner(), rbac.RoleMember()}, UserID: users[0], }, { @@ -119,7 +119,7 @@ func TestRolePermissions(t *testing.T) { memberMe := authSubject{Name: "member_me", UserID: currentUser.String(), Roles: []string{rbac.RoleMember()}} orgMemberMe := authSubject{Name: "org_member_me", UserID: currentUser.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID)}} - admin := authSubject{Name: "admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleAdmin()}} + admin := authSubject{Name: "admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOwner()}} orgAdmin := authSubject{Name: "org_admin", UserID: adminID.String(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(orgID), rbac.RoleOrgAdmin(orgID)}} otherOrgMember := authSubject{Name: "org_member_other", UserID: uuid.NewString(), Roles: []string{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg)}} @@ -358,7 +358,7 @@ func TestIsOrgRole(t *testing.T) { OrgID string }{ // Not org roles - {RoleName: rbac.RoleAdmin()}, + {RoleName: rbac.RoleOwner()}, {RoleName: rbac.RoleMember()}, {RoleName: "auditor"}, @@ -413,7 +413,7 @@ func TestListRoles(t *testing.T) { // Always use constant strings, as if the names change, we need to write // a SQL migration to change the name on the backend. require.ElementsMatch(t, []string{ - "admin", + "owner", "member", "auditor", "template-admin", diff --git a/coderd/roles_test.go b/coderd/roles_test.go index d2b83c83cc618..7dcc5354d7355 100644 --- a/coderd/roles_test.go +++ b/coderd/roles_test.go @@ -120,7 +120,7 @@ func TestListRoles(t *testing.T) { require.NoError(t, err, "create org") const forbidden = "Forbidden" - siteRoles := convertRoles(rbac.RoleAdmin(), "auditor", "template-admin", "user-admin") + siteRoles := convertRoles(rbac.RoleOwner(), "auditor", "template-admin", "user-admin") orgRoles := convertRoles(rbac.RoleOrgAdmin(admin.OrganizationID)) testCases := []struct { diff --git a/coderd/templates_test.go b/coderd/templates_test.go index c34734dd73590..00e8aed712b95 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -38,8 +38,8 @@ func TestTemplate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) user := coderdtest.CreateFirstUser(t, client) - member := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleAdmin()) - memberWithDeleted := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleAdmin()) + member := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleOwner()) + memberWithDeleted := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleOwner()) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) diff --git a/coderd/users.go b/coderd/users.go index 15ba09dfffcbe..9d3297eee68b3 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -102,7 +102,7 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) { // and add some rbac bypass when calling api functions this way?? // Add the admin role to this first user. _, err = api.Database.UpdateUserRoles(r.Context(), database.UpdateUserRolesParams{ - GrantedRoles: []string{rbac.RoleAdmin()}, + GrantedRoles: []string{rbac.RoleOwner()}, ID: user.ID, }) if err != nil { diff --git a/coderd/users_internal_test.go b/coderd/users_internal_test.go index 26e6d14bc0954..038db14bd1018 100644 --- a/coderd/users_internal_test.go +++ b/coderd/users_internal_test.go @@ -57,7 +57,7 @@ func TestSearchUsers(t *testing.T) { Expected: database.GetUsersParams{ Search: "user-name", Status: []database.UserStatus{database.UserStatusActive}, - RbacRole: []string{rbac.RoleAdmin()}, + RbacRole: []string{rbac.RoleOwner()}, }, }, { @@ -75,7 +75,7 @@ func TestSearchUsers(t *testing.T) { Expected: database.GetUsersParams{ Search: "user-name", Status: []database.UserStatus{database.UserStatusActive}, - RbacRole: []string{rbac.RoleAdmin()}, + RbacRole: []string{rbac.RoleOwner()}, }, }, { diff --git a/coderd/users_test.go b/coderd/users_test.go index 74dc33b86eb08..bf372f01f182d 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -279,7 +279,7 @@ func TestPostUsers(t *testing.T) { client := coderdtest.New(t, nil) first := coderdtest.CreateFirstUser(t, client) notInOrg := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) - other := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleAdmin(), rbac.RoleMember()) + other := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleOwner(), rbac.RoleMember()) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -513,7 +513,7 @@ func TestGrantSiteRoles(t *testing.T) { Name: "UserNotExists", Client: admin, AssignToUser: uuid.NewString(), - Roles: []string{rbac.RoleAdmin()}, + Roles: []string{rbac.RoleOwner()}, Error: true, StatusCode: http.StatusBadRequest, }, @@ -539,7 +539,7 @@ func TestGrantSiteRoles(t *testing.T) { Client: admin, OrgID: first.OrganizationID, AssignToUser: codersdk.Me, - Roles: []string{rbac.RoleAdmin()}, + Roles: []string{rbac.RoleOwner()}, Error: true, StatusCode: http.StatusBadRequest, }, @@ -629,7 +629,7 @@ func TestInitialRoles(t *testing.T) { roles, err := client.GetUserRoles(ctx, codersdk.Me) require.NoError(t, err) require.ElementsMatch(t, roles.Roles, []string{ - rbac.RoleAdmin(), + rbac.RoleOwner(), }, "should be a member and admin") require.ElementsMatch(t, roles.OrganizationRoles[first.OrganizationID], []string{ @@ -744,7 +744,7 @@ func TestUsersFilter(t *testing.T) { for i := 0; i < 15; i++ { roles := []string{} if i%2 == 0 { - roles = append(roles, rbac.RoleAdmin()) + roles = append(roles, rbac.RoleOwner()) } if i%3 == 0 { roles = append(roles, "auditor") @@ -823,12 +823,12 @@ func TestUsersFilter(t *testing.T) { { Name: "Admins", Filter: codersdk.UsersRequest{ - Role: rbac.RoleAdmin(), + Role: rbac.RoleOwner(), Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive, }, FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool { for _, r := range u.Roles { - if r.Name == rbac.RoleAdmin() { + if r.Name == rbac.RoleOwner() { return true } } @@ -838,12 +838,12 @@ func TestUsersFilter(t *testing.T) { { Name: "AdminsUppercase", Filter: codersdk.UsersRequest{ - Role: "ADMIN", + Role: "OWNER", Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive, }, FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool { for _, r := range u.Roles { - if r.Name == rbac.RoleAdmin() { + if r.Name == rbac.RoleOwner() { return true } } @@ -863,11 +863,11 @@ func TestUsersFilter(t *testing.T) { { Name: "SearchQuery", Filter: codersdk.UsersRequest{ - SearchQuery: "i role:admin status:active", + SearchQuery: "i role:owner status:active", }, FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool { for _, r := range u.Roles { - if r.Name == rbac.RoleAdmin() { + if r.Name == rbac.RoleOwner() { return (strings.ContainsAny(u.Username, "iI") || strings.ContainsAny(u.Email, "iI")) && u.Status == codersdk.UserStatusActive } @@ -878,11 +878,11 @@ func TestUsersFilter(t *testing.T) { { Name: "SearchQueryInsensitive", Filter: codersdk.UsersRequest{ - SearchQuery: "i Role:Admin STATUS:Active", + SearchQuery: "i Role:Owner STATUS:Active", }, FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool { for _, r := range u.Roles { - if r.Name == rbac.RoleAdmin() { + if r.Name == rbac.RoleOwner() { return (strings.ContainsAny(u.Username, "iI") || strings.ContainsAny(u.Email, "iI")) && u.Status == codersdk.UserStatusActive } diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index c33a485986c31..3c4acc52f46d0 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -102,7 +102,7 @@ func TestAdminViewAllWorkspaces(t *testing.T) { // This other user is not in the first user's org. Since other is an admin, they can // still see the "first" user's workspace. - other := coderdtest.CreateAnotherUser(t, client, otherOrg.ID, rbac.RoleAdmin()) + other := coderdtest.CreateAnotherUser(t, client, otherOrg.ID, rbac.RoleOwner()) otherWorkspaces, err := other.Workspaces(ctx, codersdk.WorkspaceFilter{}) require.NoError(t, err, "(other) fetch workspaces") @@ -137,7 +137,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { client := coderdtest.New(t, nil) first := coderdtest.CreateFirstUser(t, client) - other := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleMember(), rbac.RoleAdmin()) + other := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleMember(), rbac.RoleOwner()) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -406,7 +406,7 @@ func TestWorkspaceFilter(t *testing.T) { users := make([]coderUser, 0) for i := 0; i < 10; i++ { - userClient := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleAdmin()) + userClient := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleOwner()) user, err := userClient.User(ctx, codersdk.Me) require.NoError(t, err, "fetch me") From 52cac69f1a3d1b46404a19dc7f05ae702649f1a6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 12 Aug 2022 16:22:51 -0500 Subject: [PATCH 03/10] Update migration to promote either admin --- .../migrations/000034_remove_admin_role.down.sql | 12 ++++++------ .../migrations/000034_remove_admin_role.up.sql | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/coderd/database/migrations/000034_remove_admin_role.down.sql b/coderd/database/migrations/000034_remove_admin_role.down.sql index 5fcd85730dee7..e89b338c20d92 100644 --- a/coderd/database/migrations/000034_remove_admin_role.down.sql +++ b/coderd/database/migrations/000034_remove_admin_role.down.sql @@ -3,13 +3,13 @@ UPDATE SET -- Replace 'template-admin' and 'user-admin' role with 'admin' rbac_roles = array_append( - array_remove( - array_remove(users.rbac_roles, 'template-admin'), - 'user-admin' - ), 'admin') + array_remove( + array_remove(rbac_roles, 'template-admin'), + 'user-admin' + ), 'admin') WHERE - -- Only on existing admins - ARRAY ['template-admin', 'user-admin'] <@ rbac_roles; + -- Only on existing admins. If they have either role, make them an admin + ARRAY ['template-admin', 'user-admin'] && rbac_roles; UPDATE diff --git a/coderd/database/migrations/000034_remove_admin_role.up.sql b/coderd/database/migrations/000034_remove_admin_role.up.sql index 652295fc01444..ffd81b0567b55 100644 --- a/coderd/database/migrations/000034_remove_admin_role.up.sql +++ b/coderd/database/migrations/000034_remove_admin_role.up.sql @@ -4,7 +4,7 @@ SET -- Replace the role 'admin' with the role 'owner' rbac_roles = array_replace(rbac_roles, 'admin', 'owner') WHERE - -- Update the first user with the role 'admin'. This should be the first + -- Update the first user with the role 'admin'. This should be the first -- user ever, but if that user was demoted from an admin, then choose -- the next best user. id = (SELECT id FROM users WHERE 'admin' = ANY(rbac_roles) ORDER BY created_at ASC LIMIT 1); From fb4f80f9b84ed8f3234f982d35e3b211b4b5c71d Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 12 Aug 2022 16:24:30 -0500 Subject: [PATCH 04/10] fixup! Update migration to promote either admin --- coderd/database/migrations/000034_remove_admin_role.up.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/database/migrations/000034_remove_admin_role.up.sql b/coderd/database/migrations/000034_remove_admin_role.up.sql index ffd81b0567b55..6a90befb304e5 100644 --- a/coderd/database/migrations/000034_remove_admin_role.up.sql +++ b/coderd/database/migrations/000034_remove_admin_role.up.sql @@ -14,7 +14,7 @@ UPDATE users SET -- Replace 'admin' role with 'template-admin' and 'user-admin' - rbac_roles = array_cat(array_remove(users.rbac_roles, 'admin'), ARRAY ['template-admin', 'user-admin']) + rbac_roles = array_cat(array_remove(rbac_roles, 'admin'), ARRAY ['template-admin', 'user-admin']) WHERE -- Only on existing admins 'admin' = ANY(rbac_roles); From 21e48e725603554d9258391bda35e2cdea1cc806 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 15 Aug 2022 07:58:39 -0500 Subject: [PATCH 05/10] Update "admin" -> "owner" in docs --- docs/quickstart.md | 6 +++--- docs/users.md | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index 6630b6de38b60..b8d0174b57fb7 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -7,10 +7,10 @@ possible way to use Coder. Please [install Coder](../install.md) before proceeding with the steps below. -## First time admin user setup +## First time owner user setup 1. Run `coder login ` in a new terminal and follow the - interactive instructions to create your admin user and password. + interactive instructions to create your owner user and password. > If using `coder server --tunnel`, the Access URL appears in the terminal logs. @@ -45,7 +45,7 @@ coder ssh ``` To access your workspace in the Coder dashboard, navigate to the [configured access URL](../configure.md), -and log in with the admin credentials provided to you by Coder. +and log in with the owner credentials provided to you by Coder. ![Coder Web UI with code-server](./images/code-server.png) diff --git a/docs/users.md b/docs/users.md index e9a4b19daab3e..926c6bcd95b4d 100644 --- a/docs/users.md +++ b/docs/users.md @@ -6,13 +6,13 @@ This article walks you through the user roles available in Coder and creating an Coder offers these user roles in the community edition: -| | User Admin | Template Admin | Admin | -| ------------------------------------------ | ---------- | -------------- | ----- | -| Add and remove Users | ✅ | | ✅ | -| Change User roles | | | ✅ | -| Manage Templates | | ✅ | ✅ | -| View, update and delete **ALL** Workspaces | | ✅ | ✅ | -| Execute and use **ALL** Workspaces | | | ✅ | +| | User Admin | Template Admin | Owner | +| ------------------------------------------ | ---------- | -------------- |-------| +| Add and remove Users | ✅ | | ✅ | +| Change User roles | | | ✅ | +| Manage Templates | | ✅ | ✅ | +| View, update and delete **ALL** Workspaces | | ✅ | ✅ | +| Execute and use **ALL** Workspaces | | | ✅ | A user may have one or more roles. All users have an implicit Member role that may use personal workspaces. @@ -21,7 +21,7 @@ that may use personal workspaces. To create a user with the web UI: -1. Log in as an admin. +1. Log in as a user admin. 2. Go to **Users** > **New user**. 3. In the window that opens, provide the **username**, **email**, and **password** for the user (they can opt to change their password after their @@ -56,7 +56,7 @@ Create a workspace coder create ! ## Suspend a user -Admins can suspend a user, removing the user's access to Coder. +User admins can suspend a user, removing the user's access to Coder. To suspend a user via the web UI: @@ -75,7 +75,7 @@ Confirm the user suspension by typing **yes** and pressing **enter**. ## Activate a suspended user -Admins can activate a suspended user, restoring their access to Coder. +User admins can activate a suspended user, restoring their access to Coder. To activate a user via the web UI: From 9c122a6acb75adf81d055dbb7a419a35b87a1af5 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 15 Aug 2022 08:52:23 -0500 Subject: [PATCH 06/10] Fix unit test for role rename --- coderd/users_internal_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/users_internal_test.go b/coderd/users_internal_test.go index 038db14bd1018..c44f499d4ca94 100644 --- a/coderd/users_internal_test.go +++ b/coderd/users_internal_test.go @@ -53,7 +53,7 @@ func TestSearchUsers(t *testing.T) { }, { Name: "OnlyParams", - Query: "status:acTIve sEArch:User-Name role:Admin", + Query: "status:acTIve sEArch:User-Name role:Owner", Expected: database.GetUsersParams{ Search: "user-name", Status: []database.UserStatus{database.UserStatusActive}, @@ -71,7 +71,7 @@ func TestSearchUsers(t *testing.T) { }, { Name: "QuotedKey", - Query: `"status":acTIve "sEArch":User-Name "role":Admin`, + Query: `"status":acTIve "sEArch":User-Name "role":Owner`, Expected: database.GetUsersParams{ Search: "user-name", Status: []database.UserStatus{database.UserStatusActive}, From dd9e323bf2e59872bd8b12b59d6b634456ac3574 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 15 Aug 2022 08:54:16 -0500 Subject: [PATCH 07/10] Fix spacing on SQL queries --- .../000034_remove_admin_role.down.sql | 26 +++++++++---------- .../000034_remove_admin_role.up.sql | 18 ++++++------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/coderd/database/migrations/000034_remove_admin_role.down.sql b/coderd/database/migrations/000034_remove_admin_role.down.sql index e89b338c20d92..2f2042d24a3ef 100644 --- a/coderd/database/migrations/000034_remove_admin_role.down.sql +++ b/coderd/database/migrations/000034_remove_admin_role.down.sql @@ -1,22 +1,22 @@ UPDATE users SET - -- Replace 'template-admin' and 'user-admin' role with 'admin' - rbac_roles = array_append( - array_remove( - array_remove(rbac_roles, 'template-admin'), - 'user-admin' - ), 'admin') + -- Replace 'template-admin' and 'user-admin' role with 'admin' + rbac_roles = array_append( + array_remove( + array_remove(rbac_roles, 'template-admin'), + 'user-admin' + ), 'admin') WHERE - -- Only on existing admins. If they have either role, make them an admin - ARRAY ['template-admin', 'user-admin'] && rbac_roles; + -- Only on existing admins. If they have either role, make them an admin + ARRAY ['template-admin', 'user-admin'] && rbac_roles; UPDATE - users + users SET - -- Replace 'owner' with 'admin - rbac_roles = array_replace(rbac_roles, 'owner', 'admin') + -- Replace 'owner' with 'admin + rbac_roles = array_replace(rbac_roles, 'owner', 'admin') WHERE - -- Only on the owner - 'owner' = ANY(rbac_roles); + -- Only on the owner + 'owner' = ANY(rbac_roles); diff --git a/coderd/database/migrations/000034_remove_admin_role.up.sql b/coderd/database/migrations/000034_remove_admin_role.up.sql index 6a90befb304e5..7df3366e309cc 100644 --- a/coderd/database/migrations/000034_remove_admin_role.up.sql +++ b/coderd/database/migrations/000034_remove_admin_role.up.sql @@ -1,20 +1,20 @@ UPDATE - users + users SET - -- Replace the role 'admin' with the role 'owner' - rbac_roles = array_replace(rbac_roles, 'admin', 'owner') + -- Replace the role 'admin' with the role 'owner' + rbac_roles = array_replace(rbac_roles, 'admin', 'owner') WHERE -- Update the first user with the role 'admin'. This should be the first -- user ever, but if that user was demoted from an admin, then choose -- the next best user. - id = (SELECT id FROM users WHERE 'admin' = ANY(rbac_roles) ORDER BY created_at ASC LIMIT 1); + id = (SELECT id FROM users WHERE 'admin' = ANY(rbac_roles) ORDER BY created_at ASC LIMIT 1); UPDATE - users + users SET - -- Replace 'admin' role with 'template-admin' and 'user-admin' - rbac_roles = array_cat(array_remove(rbac_roles, 'admin'), ARRAY ['template-admin', 'user-admin']) + -- Replace 'admin' role with 'template-admin' and 'user-admin' + rbac_roles = array_cat(array_remove(rbac_roles, 'admin'), ARRAY ['template-admin', 'user-admin']) WHERE - -- Only on existing admins - 'admin' = ANY(rbac_roles); + -- Only on existing admins + 'admin' = ANY(rbac_roles); From 4a4845a3b2055e3fbdd8de5546c70006ae055045 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 15 Aug 2022 08:55:37 -0500 Subject: [PATCH 08/10] Import order --- coderd/provisionerjobs_internal_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/coderd/provisionerjobs_internal_test.go b/coderd/provisionerjobs_internal_test.go index 751915fc73c05..44bdb6d7fd9e7 100644 --- a/coderd/provisionerjobs_internal_test.go +++ b/coderd/provisionerjobs_internal_test.go @@ -11,17 +11,15 @@ import ( "testing" "time" - "github.com/coder/coder/coderd/rbac" - "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" - "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/databasefake" + "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/codersdk" "github.com/coder/coder/testutil" ) From ec56c607be127a0f36a9ac556624c57f94916f8f Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 15 Aug 2022 09:01:33 -0500 Subject: [PATCH 09/10] Fix typo --- site/site.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/site.go b/site/site.go index a436532d7fb69..6afebf731697b 100644 --- a/site/site.go +++ b/site/site.go @@ -346,7 +346,7 @@ func secureHeaders(next http.Handler) http.Handler { return secure.New(secure.Options{ PermissionsPolicy: permissions, - // Prevent the browser from sending Referer header with requests + // Prevent the browser from sending Referrer header with requests ReferrerPolicy: "no-referrer", }).Handler(cspHeaders(next)) } From a5598fa50d063925fa126ab0df875d0e6e52f7b3 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 15 Aug 2022 12:45:30 -0500 Subject: [PATCH 10/10] Update coderd/database/migrations/000034_remove_admin_role.down.sql Co-authored-by: Colin Adler --- coderd/database/migrations/000034_remove_admin_role.down.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/database/migrations/000034_remove_admin_role.down.sql b/coderd/database/migrations/000034_remove_admin_role.down.sql index 2f2042d24a3ef..c50b2692147cb 100644 --- a/coderd/database/migrations/000034_remove_admin_role.down.sql +++ b/coderd/database/migrations/000034_remove_admin_role.down.sql @@ -15,7 +15,7 @@ WHERE UPDATE users SET - -- Replace 'owner' with 'admin + -- Replace 'owner' with 'admin' rbac_roles = array_replace(rbac_roles, 'owner', 'admin') WHERE -- Only on the owner