diff --git a/cli/server_createadminuser.go b/cli/server_createadminuser.go index 278ecafb0644a..9f8d5ffe3ccf9 100644 --- a/cli/server_createadminuser.go +++ b/cli/server_createadminuser.go @@ -222,7 +222,7 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command { UserID: newUser.ID, CreatedAt: dbtime.Now(), UpdatedAt: dbtime.Now(), - Roles: []string{rbac.RoleOrgAdmin(org.ID)}, + Roles: []string{rbac.ScopedRoleOrgAdmin(org.ID)}, }) if err != nil { return xerrors.Errorf("insert organization member: %w", err) diff --git a/cli/server_createadminuser_test.go b/cli/server_createadminuser_test.go index 67ce74fd237a3..6510e1332f120 100644 --- a/cli/server_createadminuser_test.go +++ b/cli/server_createadminuser_test.go @@ -71,7 +71,7 @@ func TestServerCreateAdminUser(t *testing.T) { orgIDs2 := make(map[uuid.UUID]struct{}, len(orgMemberships)) for _, membership := range orgMemberships { orgIDs2[membership.OrganizationID] = struct{}{} - assert.Equal(t, []string{rbac.RoleOrgAdmin(membership.OrganizationID)}, membership.Roles, "user is not org admin") + assert.Equal(t, []string{rbac.ScopedRoleOrgAdmin(membership.OrganizationID)}, membership.Roles, "user is not org admin") } require.Equal(t, orgIDs, orgIDs2, "user is not in all orgs") diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index c5e2a6041526f..590fc3ed8e6a4 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -11458,6 +11458,9 @@ const docTemplate = `{ }, "name": { "type": "string" + }, + "organization_id": { + "type": "string" } } }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 66afad1f041f0..346893693d752 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -10341,6 +10341,9 @@ }, "name": { "type": "string" + }, + "organization_id": { + "type": "string" } } }, diff --git a/coderd/authorize_test.go b/coderd/authorize_test.go index 3fcb2f6c8e64f..f720f90c09206 100644 --- a/coderd/authorize_test.go +++ b/coderd/authorize_test.go @@ -27,7 +27,7 @@ func TestCheckPermissions(t *testing.T) { memberClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID) memberUser, err := memberClient.User(ctx, codersdk.Me) require.NoError(t, err) - orgAdminClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID, rbac.RoleOrgAdmin(adminUser.OrganizationID)) + orgAdminClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID, rbac.ScopedRoleOrgAdmin(adminUser.OrganizationID)) orgAdminUser, err := orgAdminClient.User(ctx, codersdk.Me) require.NoError(t, err) diff --git a/coderd/batchstats/batcher_internal_test.go b/coderd/batchstats/batcher_internal_test.go index 8954fa5455fcd..d153ac283b086 100644 --- a/coderd/batchstats/batcher_internal_test.go +++ b/coderd/batchstats/batcher_internal_test.go @@ -177,7 +177,7 @@ func setupDeps(t *testing.T, store database.Store, ps pubsub.Pubsub) deps { _, err := store.InsertOrganizationMember(context.Background(), database.InsertOrganizationMemberParams{ OrganizationID: org.ID, UserID: user.ID, - Roles: []string{rbac.RoleOrgMember(org.ID)}, + Roles: []string{rbac.ScopedRoleOrgMember(org.ID)}, }) require.NoError(t, err) tv := dbgen.TemplateVersion(t, store, database.TemplateVersion{ diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 7110cc79471fb..316683a9f1e65 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -663,6 +663,7 @@ func CreateFirstUser(t testing.TB, client *codersdk.Client) codersdk.CreateFirst } // CreateAnotherUser creates and authenticates a new user. +// Roles can include org scoped roles with 'roleName:' func CreateAnotherUser(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, roles ...string) (*codersdk.Client, codersdk.User) { return createAnotherUserRetry(t, client, organizationID, 5, roles) } @@ -680,7 +681,7 @@ func AuthzUserSubject(user codersdk.User, orgID uuid.UUID) rbac.Subject { roles = append(roles, r.Name) } // We assume only 1 org exists - roles = append(roles, rbac.RoleOrgMember(orgID)) + roles = append(roles, rbac.ScopedRoleOrgMember(orgID)) return rbac.Subject{ ID: user.ID.String(), @@ -754,6 +755,8 @@ func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationI for _, roleName := range roles { roleName := roleName orgID, ok := rbac.IsOrgRole(roleName) + roleName, _, err = rbac.RoleSplit(roleName) + require.NoError(t, err, "split org role name") if ok { orgRoles[orgID] = append(orgRoles[orgID], roleName) } else { diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index 402752805bf7b..1dbd62b4d6a96 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -204,13 +204,6 @@ func Group(group database.Group, members []database.User) codersdk.Group { } } -func SlimRole(role rbac.Role) codersdk.SlimRole { - return codersdk.SlimRole{ - DisplayName: role.DisplayName, - Name: role.Name, - } -} - func TemplateInsightsParameters(parameterRows []database.GetTemplateParameterInsightsRow) ([]codersdk.TemplateParameterUsage, error) { // Use a stable sort, similarly to how we would sort in the query, note that // we don't sort in the query because order varies depending on the table @@ -525,6 +518,19 @@ func ProvisionerDaemon(dbDaemon database.ProvisionerDaemon) codersdk.Provisioner return result } +func SlimRole(role rbac.Role) codersdk.SlimRole { + roleName, orgIDStr, err := rbac.RoleSplit(role.Name) + if err != nil { + roleName = role.Name + } + + return codersdk.SlimRole{ + DisplayName: role.DisplayName, + Name: roleName, + OrganizationID: orgIDStr, + } +} + func RBACRole(role rbac.Role) codersdk.Role { roleName, orgIDStr, err := rbac.RoleSplit(role.Name) if err != nil { diff --git a/coderd/database/dbauthz/customroles_test.go b/coderd/database/dbauthz/customroles_test.go index ddcdca084f7f8..a5077121c0629 100644 --- a/coderd/database/dbauthz/customroles_test.go +++ b/coderd/database/dbauthz/customroles_test.go @@ -153,7 +153,7 @@ func TestUpsertCustomRoles(t *testing.T) { UUID: uuid.New(), Valid: true, }, - subject: merge(canAssignRole, rbac.RoleOrgAdmin(orgID.UUID)), + subject: merge(canAssignRole, rbac.ScopedRoleOrgAdmin(orgID.UUID)), org: codersdk.CreatePermissions(map[codersdk.RBACResource][]codersdk.RBACAction{ codersdk.ResourceWorkspace: {codersdk.ActionRead}, }), @@ -162,7 +162,7 @@ func TestUpsertCustomRoles(t *testing.T) { { name: "user-escalation", // These roles do not grant user perms - subject: merge(canAssignRole, rbac.RoleOrgAdmin(orgID.UUID)), + subject: merge(canAssignRole, rbac.ScopedRoleOrgAdmin(orgID.UUID)), user: codersdk.CreatePermissions(map[codersdk.RBACResource][]codersdk.RBACAction{ codersdk.ResourceWorkspace: {codersdk.ActionRead}, }), @@ -190,7 +190,7 @@ func TestUpsertCustomRoles(t *testing.T) { }, { name: "read-workspace-in-org", - subject: merge(canAssignRole, rbac.RoleOrgAdmin(orgID.UUID)), + subject: merge(canAssignRole, rbac.ScopedRoleOrgAdmin(orgID.UUID)), organizationID: orgID, org: codersdk.CreatePermissions(map[codersdk.RBACResource][]codersdk.RBACAction{ codersdk.ResourceWorkspace: {codersdk.ActionRead}, diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index a590e272e65fe..73c73176b5953 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2472,7 +2472,7 @@ func (q *querier) InsertOrganization(ctx context.Context, arg database.InsertOrg func (q *querier) InsertOrganizationMember(ctx context.Context, arg database.InsertOrganizationMemberParams) (database.OrganizationMember, error) { // All roles are added roles. Org member is always implied. - addedRoles := append(arg.Roles, rbac.RoleOrgMember(arg.OrganizationID)) + addedRoles := append(arg.Roles, rbac.ScopedRoleOrgMember(arg.OrganizationID)) err := q.canAssignRoles(ctx, &arg.OrganizationID, addedRoles, []string{}) if err != nil { return database.OrganizationMember{}, err @@ -2847,8 +2847,22 @@ func (q *querier) UpdateMemberRoles(ctx context.Context, arg database.UpdateMemb return database.OrganizationMember{}, err } + // The 'rbac' package expects role names to be scoped. + // Convert the argument roles for validation. + scopedGranted := make([]string, 0, len(arg.GrantedRoles)) + for _, grantedRole := range arg.GrantedRoles { + // This check is a developer safety check. Old code might try to invoke this code path with + // organization id suffixes. Catch this and return a nice error so it can be fixed. + _, foundOrg, _ := rbac.RoleSplit(grantedRole) + if foundOrg != "" { + return database.OrganizationMember{}, xerrors.Errorf("attempt to assign a role %q, remove the ': suffix", grantedRole) + } + + scopedGranted = append(scopedGranted, rbac.RoleName(grantedRole, arg.OrgID.String())) + } + // The org member role is always implied. - impliedTypes := append(arg.GrantedRoles, rbac.RoleOrgMember(arg.OrgID)) + impliedTypes := append(scopedGranted, rbac.ScopedRoleOrgMember(arg.OrgID)) added, removed := rbac.ChangeRoleSet(member.Roles, impliedTypes) err = q.canAssignRoles(ctx, &arg.OrgID, added, removed) if err != nil { diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 218f73af762ae..dbfb4e15e0de0 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -636,7 +636,7 @@ func (s *MethodTestSuite) TestOrganization() { check.Args(database.InsertOrganizationMemberParams{ OrganizationID: o.ID, UserID: u.ID, - Roles: []string{rbac.RoleOrgAdmin(o.ID)}, + Roles: []string{rbac.ScopedRoleOrgAdmin(o.ID)}, }).Asserts( rbac.ResourceAssignRole.InOrg(o.ID), policy.ActionAssign, rbac.ResourceOrganizationMember.InOrg(o.ID).WithID(u.ID), policy.ActionCreate) @@ -664,7 +664,7 @@ func (s *MethodTestSuite) TestOrganization() { mem := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{ OrganizationID: o.ID, UserID: u.ID, - Roles: []string{rbac.RoleOrgAdmin(o.ID)}, + Roles: []string{rbac.ScopedRoleOrgAdmin(o.ID)}, }) out := mem out.Roles = []string{} diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index fe9b56e35ebdb..2bfff39a949a9 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -1997,7 +1997,9 @@ func (q *FakeQuerier) GetAuthorizationUserRoles(_ context.Context, userID uuid.U for _, mem := range q.organizationMembers { if mem.UserID == userID { - roles = append(roles, mem.Roles...) + for _, orgRole := range mem.Roles { + roles = append(roles, orgRole+":"+mem.OrganizationID.String()) + } roles = append(roles, "organization-member:"+mem.OrganizationID.String()) } } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index fde9c9556ac84..28adc8a36b1f1 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -576,7 +576,7 @@ CREATE TABLE organization_members ( organization_id uuid NOT NULL, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, - roles text[] DEFAULT '{organization-member}'::text[] NOT NULL + roles text[] DEFAULT '{}'::text[] NOT NULL ); CREATE TABLE organizations ( diff --git a/coderd/database/migrations/000215_scoped_org_db_roles.down.sql b/coderd/database/migrations/000215_scoped_org_db_roles.down.sql new file mode 100644 index 0000000000000..68a43a8fe8c7a --- /dev/null +++ b/coderd/database/migrations/000215_scoped_org_db_roles.down.sql @@ -0,0 +1 @@ +ALTER TABLE ONLY organization_members ALTER COLUMN roles SET DEFAULT '{organization-member}'; diff --git a/coderd/database/migrations/000215_scoped_org_db_roles.up.sql b/coderd/database/migrations/000215_scoped_org_db_roles.up.sql new file mode 100644 index 0000000000000..aecd19b8da668 --- /dev/null +++ b/coderd/database/migrations/000215_scoped_org_db_roles.up.sql @@ -0,0 +1,7 @@ +-- The default was 'organization-member', but we imply that in the +-- 'GetAuthorizationUserRoles' query. +ALTER TABLE ONLY organization_members ALTER COLUMN roles SET DEFAULT '{}'; + +-- No one should be using organization roles yet. If they are, the names in the +-- database are now incorrect. Just remove them all. +UPDATE organization_members SET roles = '{}'; diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 5bc7552117b58..677f972e734c3 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -8432,12 +8432,14 @@ SELECT array_append(users.rbac_roles, 'member'), ( SELECT - array_agg(org_roles) + -- The roles are returned as a flat array, org scoped and site side. + -- Concatenating the organization id scopes the organization roles. + array_agg(org_roles || ':' || organization_members.organization_id::text) FROM organization_members, - -- All org_members get the org-member role for their orgs + -- All org_members get the organization-member role for their orgs unnest( - array_append(roles, 'organization-member:' || organization_members.organization_id::text) + array_append(roles, 'organization-member') ) AS org_roles WHERE user_id = users.id diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index 5062b14429427..cd2b3456379fa 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -227,12 +227,14 @@ SELECT array_append(users.rbac_roles, 'member'), ( SELECT - array_agg(org_roles) + -- The roles are returned as a flat array, org scoped and site side. + -- Concatenating the organization id scopes the organization roles. + array_agg(org_roles || ':' || organization_members.organization_id::text) FROM organization_members, - -- All org_members get the org-member role for their orgs + -- All org_members get the organization-member role for their orgs unnest( - array_append(roles, 'organization-member:' || organization_members.organization_id::text) + array_append(roles, 'organization-member') ) AS org_roles WHERE user_id = users.id diff --git a/coderd/httpmw/authorize_test.go b/coderd/httpmw/authorize_test.go index c67be2ca2bdf7..131040b89b1f4 100644 --- a/coderd/httpmw/authorize_test.go +++ b/coderd/httpmw/authorize_test.go @@ -68,7 +68,7 @@ func TestExtractUserRoles(t *testing.T) { Roles: orgRoles, }) require.NoError(t, err) - return user, append(roles, append(orgRoles, rbac.RoleMember(), rbac.RoleOrgMember(org.ID))...), token + return user, append(roles, append(orgRoles, rbac.RoleMember(), rbac.ScopedRoleOrgMember(org.ID))...), token }, }, { @@ -89,7 +89,8 @@ func TestExtractUserRoles(t *testing.T) { orgRoles := []string{} if i%2 == 0 { - orgRoles = append(orgRoles, rbac.RoleOrgAdmin(organization.ID)) + orgRoles = append(orgRoles, rbac.RoleOrgAdmin()) + roles = append(roles, rbac.ScopedRoleOrgAdmin(organization.ID)) } _, err = db.InsertOrganizationMember(context.Background(), database.InsertOrganizationMemberParams{ OrganizationID: organization.ID, @@ -99,8 +100,7 @@ func TestExtractUserRoles(t *testing.T) { Roles: orgRoles, }) require.NoError(t, err) - roles = append(roles, orgRoles...) - roles = append(roles, rbac.RoleOrgMember(organization.ID)) + roles = append(roles, rbac.ScopedRoleOrgMember(organization.ID)) } return user, roles, token }, diff --git a/coderd/httpmw/organizationparam_test.go b/coderd/httpmw/organizationparam_test.go index 02b7ce1e14ad8..44d63cd664460 100644 --- a/coderd/httpmw/organizationparam_test.go +++ b/coderd/httpmw/organizationparam_test.go @@ -152,7 +152,7 @@ func TestOrganizationParam(t *testing.T) { _ = dbgen.OrganizationMember(t, db, database.OrganizationMember{ OrganizationID: organization.ID, UserID: user.ID, - Roles: []string{rbac.RoleOrgMember(organization.ID)}, + Roles: []string{rbac.ScopedRoleOrgMember(organization.ID)}, }) _, err := db.UpdateUserRoles(ctx, database.UpdateUserRolesParams{ ID: user.ID, diff --git a/coderd/members.go b/coderd/members.go index beae302ab3124..36660e5cb968e 100644 --- a/coderd/members.go +++ b/coderd/members.go @@ -68,7 +68,7 @@ func convertOrganizationMember(mem database.OrganizationMember) codersdk.Organiz } for _, roleName := range mem.Roles { - rbacRole, _ := rbac.RoleByName(roleName) + rbacRole, _ := rbac.RoleByName(rbac.RoleName(roleName, mem.OrganizationID.String())) convertedMember.Roles = append(convertedMember.Roles, db2sdk.SlimRole(rbacRole)) } return convertedMember diff --git a/coderd/organizations.go b/coderd/organizations.go index 2a43ed2a7011a..b92d80342dfd6 100644 --- a/coderd/organizations.go +++ b/coderd/organizations.go @@ -94,7 +94,7 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) { // come back to determining the default role of the person who // creates the org. Until that happens, all users in an organization // should be just regular members. - rbac.RoleOrgMember(organization.ID), + rbac.ScopedRoleOrgMember(organization.ID), }, }) if err != nil { diff --git a/coderd/rbac/authz_internal_test.go b/coderd/rbac/authz_internal_test.go index 7b53939a3651b..d3d1ae8d9f765 100644 --- a/coderd/rbac/authz_internal_test.go +++ b/coderd/rbac/authz_internal_test.go @@ -168,7 +168,7 @@ func TestFilter(t *testing.T) { Name: "Admin", Actor: Subject{ ID: userIDs[0].String(), - Roles: RoleNames{RoleOrgMember(orgIDs[0]), "auditor", RoleOwner(), RoleMember()}, + Roles: RoleNames{ScopedRoleOrgMember(orgIDs[0]), "auditor", RoleOwner(), RoleMember()}, }, ObjectType: ResourceWorkspace.Type, Action: policy.ActionRead, @@ -177,7 +177,7 @@ func TestFilter(t *testing.T) { Name: "OrgAdmin", Actor: Subject{ ID: userIDs[0].String(), - Roles: RoleNames{RoleOrgMember(orgIDs[0]), RoleOrgAdmin(orgIDs[0]), RoleMember()}, + Roles: RoleNames{ScopedRoleOrgMember(orgIDs[0]), ScopedRoleOrgAdmin(orgIDs[0]), RoleMember()}, }, ObjectType: ResourceWorkspace.Type, Action: policy.ActionRead, @@ -186,7 +186,7 @@ func TestFilter(t *testing.T) { Name: "OrgMember", Actor: Subject{ ID: userIDs[0].String(), - Roles: RoleNames{RoleOrgMember(orgIDs[0]), RoleOrgMember(orgIDs[1]), RoleMember()}, + Roles: RoleNames{ScopedRoleOrgMember(orgIDs[0]), ScopedRoleOrgMember(orgIDs[1]), RoleMember()}, }, ObjectType: ResourceWorkspace.Type, Action: policy.ActionRead, @@ -196,11 +196,11 @@ func TestFilter(t *testing.T) { Actor: Subject{ ID: userIDs[0].String(), Roles: RoleNames{ - RoleOrgMember(orgIDs[0]), RoleOrgAdmin(orgIDs[0]), - RoleOrgMember(orgIDs[1]), RoleOrgAdmin(orgIDs[1]), - RoleOrgMember(orgIDs[2]), RoleOrgAdmin(orgIDs[2]), - RoleOrgMember(orgIDs[4]), - RoleOrgMember(orgIDs[5]), + ScopedRoleOrgMember(orgIDs[0]), ScopedRoleOrgAdmin(orgIDs[0]), + ScopedRoleOrgMember(orgIDs[1]), ScopedRoleOrgAdmin(orgIDs[1]), + ScopedRoleOrgMember(orgIDs[2]), ScopedRoleOrgAdmin(orgIDs[2]), + ScopedRoleOrgMember(orgIDs[4]), + ScopedRoleOrgMember(orgIDs[5]), RoleMember(), }, }, @@ -221,10 +221,10 @@ func TestFilter(t *testing.T) { Actor: Subject{ ID: userIDs[0].String(), Roles: RoleNames{ - RoleOrgMember(orgIDs[0]), - RoleOrgMember(orgIDs[1]), - RoleOrgMember(orgIDs[2]), - RoleOrgMember(orgIDs[3]), + ScopedRoleOrgMember(orgIDs[0]), + ScopedRoleOrgMember(orgIDs[1]), + ScopedRoleOrgMember(orgIDs[2]), + ScopedRoleOrgMember(orgIDs[3]), RoleMember(), }, }, @@ -235,7 +235,7 @@ func TestFilter(t *testing.T) { Name: "ScopeApplicationConnect", Actor: Subject{ ID: userIDs[0].String(), - Roles: RoleNames{RoleOrgMember(orgIDs[0]), "auditor", RoleOwner(), RoleMember()}, + Roles: RoleNames{ScopedRoleOrgMember(orgIDs[0]), "auditor", RoleOwner(), RoleMember()}, }, ObjectType: ResourceWorkspace.Type, Action: policy.ActionRead, @@ -297,7 +297,7 @@ func TestAuthorizeDomain(t *testing.T) { Groups: []string{allUsersGroup}, Roles: Roles{ must(RoleByName(RoleMember())), - must(RoleByName(RoleOrgMember(defOrg))), + must(RoleByName(ScopedRoleOrgMember(defOrg))), }, } @@ -435,7 +435,7 @@ func TestAuthorizeDomain(t *testing.T) { ID: "me", Scope: must(ExpandScope(ScopeAll)), Roles: Roles{ - must(RoleByName(RoleOrgAdmin(defOrg))), + must(RoleByName(ScopedRoleOrgAdmin(defOrg))), must(RoleByName(RoleMember())), }, } @@ -507,7 +507,7 @@ func TestAuthorizeDomain(t *testing.T) { ID: "me", Scope: must(ExpandScope(ScopeApplicationConnect)), Roles: Roles{ - must(RoleByName(RoleOrgMember(defOrg))), + must(RoleByName(ScopedRoleOrgMember(defOrg))), must(RoleByName(RoleMember())), }, } @@ -770,7 +770,7 @@ func TestAuthorizeLevels(t *testing.T) { }, }, }, - must(RoleByName(RoleOrgAdmin(defOrg))), + must(RoleByName(ScopedRoleOrgAdmin(defOrg))), { Name: "user-deny-all", // List out deny permissions explicitly @@ -856,7 +856,7 @@ func TestAuthorizeScope(t *testing.T) { ID: "me", Roles: Roles{ must(RoleByName(RoleMember())), - must(RoleByName(RoleOrgMember(defOrg))), + must(RoleByName(ScopedRoleOrgMember(defOrg))), }, Scope: must(ExpandScope(ScopeApplicationConnect)), } @@ -892,7 +892,7 @@ func TestAuthorizeScope(t *testing.T) { ID: "me", Roles: Roles{ must(RoleByName(RoleMember())), - must(RoleByName(RoleOrgMember(defOrg))), + must(RoleByName(ScopedRoleOrgMember(defOrg))), }, Scope: Scope{ Role: Role{ @@ -981,7 +981,7 @@ func TestAuthorizeScope(t *testing.T) { ID: "me", Roles: Roles{ must(RoleByName(RoleMember())), - must(RoleByName(RoleOrgMember(defOrg))), + must(RoleByName(ScopedRoleOrgMember(defOrg))), }, Scope: Scope{ Role: Role{ diff --git a/coderd/rbac/authz_test.go b/coderd/rbac/authz_test.go index 05940856ec583..344d85562a094 100644 --- a/coderd/rbac/authz_test.go +++ b/coderd/rbac/authz_test.go @@ -49,7 +49,7 @@ func benchmarkUserCases() (cases []benchmarkCase, users uuid.UUID, orgs []uuid.U Name: "Admin", Actor: rbac.Subject{ // Give some extra roles that an admin might have - Roles: rbac.RoleNames{rbac.RoleOrgMember(orgs[0]), "auditor", rbac.RoleOwner(), rbac.RoleMember()}, + Roles: rbac.RoleNames{rbac.ScopedRoleOrgMember(orgs[0]), "auditor", rbac.RoleOwner(), rbac.RoleMember()}, ID: user.String(), Scope: rbac.ScopeAll, Groups: noiseGroups, @@ -58,7 +58,7 @@ func benchmarkUserCases() (cases []benchmarkCase, users uuid.UUID, orgs []uuid.U { Name: "OrgAdmin", Actor: rbac.Subject{ - Roles: rbac.RoleNames{rbac.RoleOrgMember(orgs[0]), rbac.RoleOrgAdmin(orgs[0]), rbac.RoleMember()}, + Roles: rbac.RoleNames{rbac.ScopedRoleOrgMember(orgs[0]), rbac.ScopedRoleOrgAdmin(orgs[0]), rbac.RoleMember()}, ID: user.String(), Scope: rbac.ScopeAll, Groups: noiseGroups, @@ -68,7 +68,7 @@ func benchmarkUserCases() (cases []benchmarkCase, users uuid.UUID, orgs []uuid.U Name: "OrgMember", Actor: rbac.Subject{ // Member of 2 orgs - Roles: rbac.RoleNames{rbac.RoleOrgMember(orgs[0]), rbac.RoleOrgMember(orgs[1]), rbac.RoleMember()}, + Roles: rbac.RoleNames{rbac.ScopedRoleOrgMember(orgs[0]), rbac.ScopedRoleOrgMember(orgs[1]), rbac.RoleMember()}, ID: user.String(), Scope: rbac.ScopeAll, Groups: noiseGroups, @@ -79,9 +79,9 @@ func benchmarkUserCases() (cases []benchmarkCase, users uuid.UUID, orgs []uuid.U Actor: rbac.Subject{ // Admin of many orgs Roles: rbac.RoleNames{ - rbac.RoleOrgMember(orgs[0]), rbac.RoleOrgAdmin(orgs[0]), - rbac.RoleOrgMember(orgs[1]), rbac.RoleOrgAdmin(orgs[1]), - rbac.RoleOrgMember(orgs[2]), rbac.RoleOrgAdmin(orgs[2]), + rbac.ScopedRoleOrgMember(orgs[0]), rbac.ScopedRoleOrgAdmin(orgs[0]), + rbac.ScopedRoleOrgMember(orgs[1]), rbac.ScopedRoleOrgAdmin(orgs[1]), + rbac.ScopedRoleOrgMember(orgs[2]), rbac.ScopedRoleOrgAdmin(orgs[2]), rbac.RoleMember(), }, ID: user.String(), @@ -94,9 +94,9 @@ func benchmarkUserCases() (cases []benchmarkCase, users uuid.UUID, orgs []uuid.U Actor: rbac.Subject{ // Admin of many orgs Roles: rbac.RoleNames{ - rbac.RoleOrgMember(orgs[0]), rbac.RoleOrgAdmin(orgs[0]), - rbac.RoleOrgMember(orgs[1]), rbac.RoleOrgAdmin(orgs[1]), - rbac.RoleOrgMember(orgs[2]), rbac.RoleOrgAdmin(orgs[2]), + rbac.ScopedRoleOrgMember(orgs[0]), rbac.ScopedRoleOrgAdmin(orgs[0]), + rbac.ScopedRoleOrgMember(orgs[1]), rbac.ScopedRoleOrgAdmin(orgs[1]), + rbac.ScopedRoleOrgMember(orgs[2]), rbac.ScopedRoleOrgAdmin(orgs[2]), rbac.RoleMember(), }, ID: user.String(), @@ -108,7 +108,7 @@ func benchmarkUserCases() (cases []benchmarkCase, users uuid.UUID, orgs []uuid.U Name: "AdminWithScope", Actor: rbac.Subject{ // Give some extra roles that an admin might have - Roles: rbac.RoleNames{rbac.RoleOrgMember(orgs[0]), "auditor", rbac.RoleOwner(), rbac.RoleMember()}, + Roles: rbac.RoleNames{rbac.ScopedRoleOrgMember(orgs[0]), "auditor", rbac.RoleOwner(), rbac.RoleMember()}, ID: user.String(), Scope: rbac.ScopeApplicationConnect, Groups: noiseGroups, diff --git a/coderd/rbac/roles.go b/coderd/rbac/roles.go index 137d2c0c1258b..fae31150e2053 100644 --- a/coderd/rbac/roles.go +++ b/coderd/rbac/roles.go @@ -70,11 +70,25 @@ func RoleMember() string { return RoleName(member, "") } -func RoleOrgAdmin(organizationID uuid.UUID) string { +func RoleOrgAdmin() string { + return orgAdmin +} + +func RoleOrgMember() string { + return orgMember +} + +// ScopedRoleOrgAdmin is the org role with the organization ID +// Deprecated This was used before organization scope was included as a +// field in all user facing APIs. Usage of 'ScopedRoleOrgAdmin()' is preferred. +func ScopedRoleOrgAdmin(organizationID uuid.UUID) string { return RoleName(orgAdmin, organizationID.String()) } -func RoleOrgMember(organizationID uuid.UUID) string { +// ScopedRoleOrgMember is the org role with the organization ID +// Deprecated This was used before organization scope was included as a +// field in all user facing APIs. Usage of 'ScopedRoleOrgMember()' is preferred. +func ScopedRoleOrgMember(organizationID uuid.UUID) string { return RoleName(orgMember, organizationID.String()) } diff --git a/coderd/rbac/roles_internal_test.go b/coderd/rbac/roles_internal_test.go index 07126981081d8..70296f7519b97 100644 --- a/coderd/rbac/roles_internal_test.go +++ b/coderd/rbac/roles_internal_test.go @@ -20,7 +20,7 @@ import ( // A possible large improvement would be to implement the ast.Value interface directly. func BenchmarkRBACValueAllocation(b *testing.B) { actor := Subject{ - Roles: RoleNames{RoleOrgMember(uuid.New()), RoleOrgAdmin(uuid.New()), RoleMember()}, + Roles: RoleNames{ScopedRoleOrgMember(uuid.New()), ScopedRoleOrgAdmin(uuid.New()), RoleMember()}, ID: uuid.NewString(), Scope: ScopeAll, Groups: []string{uuid.NewString(), uuid.NewString(), uuid.NewString()}, @@ -73,7 +73,7 @@ func TestRegoInputValue(t *testing.T) { // Expand all roles and make sure we have a good copy. // This is because these tests modify the roles, and we don't want to // modify the original roles. - roles, err := RoleNames{RoleOrgMember(uuid.New()), RoleOrgAdmin(uuid.New()), RoleMember()}.Expand() + roles, err := RoleNames{ScopedRoleOrgMember(uuid.New()), ScopedRoleOrgAdmin(uuid.New()), RoleMember()}.Expand() require.NoError(t, err, "failed to expand roles") for i := range roles { // If all cached values are nil, then the role will not use diff --git a/coderd/rbac/roles_test.go b/coderd/rbac/roles_test.go index e6680d4d628cc..f2f0d1d3399e2 100644 --- a/coderd/rbac/roles_test.go +++ b/coderd/rbac/roles_test.go @@ -99,13 +99,13 @@ func TestRolePermissions(t *testing.T) { // Subjects to user memberMe := authSubject{Name: "member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleNames{rbac.RoleMember()}}} - orgMemberMe := authSubject{Name: "org_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleOrgMember(orgID)}}} + orgMemberMe := authSubject{Name: "org_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID)}}} owner := authSubject{Name: "owner", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleOwner()}}} - orgAdmin := authSubject{Name: "org_admin", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleOrgMember(orgID), rbac.RoleOrgAdmin(orgID)}}} + orgAdmin := authSubject{Name: "org_admin", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID), rbac.ScopedRoleOrgAdmin(orgID)}}} - otherOrgMember := authSubject{Name: "org_member_other", Actor: rbac.Subject{ID: uuid.NewString(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg)}}} - otherOrgAdmin := authSubject{Name: "org_admin_other", Actor: rbac.Subject{ID: uuid.NewString(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleOrgMember(otherOrg), rbac.RoleOrgAdmin(otherOrg)}}} + otherOrgMember := authSubject{Name: "org_member_other", Actor: rbac.Subject{ID: uuid.NewString(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg)}}} + otherOrgAdmin := authSubject{Name: "org_admin_other", Actor: rbac.Subject{ID: uuid.NewString(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.ScopedRoleOrgMember(otherOrg), rbac.ScopedRoleOrgAdmin(otherOrg)}}} templateAdmin := authSubject{Name: "template-admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleTemplateAdmin()}}} userAdmin := authSubject{Name: "user-admin", Actor: rbac.Subject{ID: templateAdminID.String(), Roles: rbac.RoleNames{rbac.RoleMember(), rbac.RoleUserAdmin()}}} @@ -636,12 +636,12 @@ func TestIsOrgRole(t *testing.T) { // Org roles { - RoleName: rbac.RoleOrgAdmin(randomUUID), + RoleName: rbac.ScopedRoleOrgAdmin(randomUUID), OrgRole: true, OrgID: randomUUID.String(), }, { - RoleName: rbac.RoleOrgMember(randomUUID), + RoleName: rbac.ScopedRoleOrgMember(randomUUID), OrgRole: true, OrgID: randomUUID.String(), }, diff --git a/coderd/roles_test.go b/coderd/roles_test.go index 1b1aa94c6025a..24845fea3fa3d 100644 --- a/coderd/roles_test.go +++ b/coderd/roles_test.go @@ -26,7 +26,7 @@ func TestListRoles(t *testing.T) { // Create owner, member, and org admin owner := coderdtest.CreateFirstUser(t, client) member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - orgAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleOrgAdmin(owner.OrganizationID)) + orgAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgAdmin(owner.OrganizationID)) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) t.Cleanup(cancel) @@ -64,7 +64,7 @@ func TestListRoles(t *testing.T) { return member.ListOrganizationRoles(ctx, owner.OrganizationID) }, ExpectedRoles: convertRoles(map[string]bool{ - rbac.RoleOrgAdmin(owner.OrganizationID): false, + rbac.ScopedRoleOrgAdmin(owner.OrganizationID): false, }), }, { @@ -93,7 +93,7 @@ func TestListRoles(t *testing.T) { return orgAdmin.ListOrganizationRoles(ctx, owner.OrganizationID) }, ExpectedRoles: convertRoles(map[string]bool{ - rbac.RoleOrgAdmin(owner.OrganizationID): true, + rbac.ScopedRoleOrgAdmin(owner.OrganizationID): true, }), }, { @@ -122,7 +122,7 @@ func TestListRoles(t *testing.T) { return client.ListOrganizationRoles(ctx, owner.OrganizationID) }, ExpectedRoles: convertRoles(map[string]bool{ - rbac.RoleOrgAdmin(owner.OrganizationID): true, + rbac.ScopedRoleOrgAdmin(owner.OrganizationID): true, }), }, } diff --git a/coderd/users_test.go b/coderd/users_test.go index 80c7062c914ed..0fa42c4578c6d 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -962,12 +962,12 @@ func TestGrantSiteRoles(t *testing.T) { admin := coderdtest.New(t, nil) first := coderdtest.CreateFirstUser(t, admin) member, _ := coderdtest.CreateAnotherUser(t, admin, first.OrganizationID) - orgAdmin, _ := coderdtest.CreateAnotherUser(t, admin, first.OrganizationID, rbac.RoleOrgAdmin(first.OrganizationID)) + orgAdmin, _ := coderdtest.CreateAnotherUser(t, admin, first.OrganizationID, rbac.ScopedRoleOrgAdmin(first.OrganizationID)) randOrg, err := admin.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{ Name: "random", }) require.NoError(t, err) - _, randOrgUser := coderdtest.CreateAnotherUser(t, admin, randOrg.ID, rbac.RoleOrgAdmin(randOrg.ID)) + _, randOrgUser := coderdtest.CreateAnotherUser(t, admin, randOrg.ID, rbac.ScopedRoleOrgAdmin(randOrg.ID)) userAdmin, _ := coderdtest.CreateAnotherUser(t, admin, first.OrganizationID, rbac.RoleUserAdmin()) const newUser = "newUser" @@ -986,7 +986,7 @@ func TestGrantSiteRoles(t *testing.T) { Name: "OrgRoleInSite", Client: admin, AssignToUser: codersdk.Me, - Roles: []string{rbac.RoleOrgAdmin(first.OrganizationID)}, + Roles: []string{rbac.RoleOrgAdmin()}, Error: true, StatusCode: http.StatusBadRequest, }, @@ -1029,7 +1029,7 @@ func TestGrantSiteRoles(t *testing.T) { Client: orgAdmin, OrgID: randOrg.ID, AssignToUser: randOrgUser.ID.String(), - Roles: []string{rbac.RoleOrgMember(randOrg.ID)}, + Roles: []string{rbac.RoleOrgMember()}, Error: true, StatusCode: http.StatusNotFound, }, @@ -1047,9 +1047,9 @@ func TestGrantSiteRoles(t *testing.T) { Client: orgAdmin, OrgID: first.OrganizationID, AssignToUser: newUser, - Roles: []string{rbac.RoleOrgAdmin(first.OrganizationID)}, + Roles: []string{rbac.RoleOrgAdmin()}, ExpectedRoles: []string{ - rbac.RoleOrgAdmin(first.OrganizationID), + rbac.RoleOrgAdmin(), }, Error: false, }, diff --git a/codersdk/roles.go b/codersdk/roles.go index bfab6b15ae391..6707bb1d6e276 100644 --- a/codersdk/roles.go +++ b/codersdk/roles.go @@ -14,8 +14,9 @@ import ( // and it would require extra db calls to fetch this information. The UI does // not need it, so most api calls will use this structure that omits information. type SlimRole struct { - Name string `json:"name"` - DisplayName string `json:"display_name"` + Name string `json:"name"` + DisplayName string `json:"display_name"` + OrganizationID string `json:"organization_id,omitempty"` } type AssignableRoles struct { @@ -36,7 +37,7 @@ type Permission struct { // Role is a longer form of SlimRole used to edit custom roles. type Role struct { Name string `json:"name" table:"name,default_sort" validate:"username"` - OrganizationID string `json:"organization_id" table:"organization_id" format:"uuid"` + OrganizationID string `json:"organization_id,omitempty" table:"organization_id" format:"uuid"` DisplayName string `json:"display_name" table:"display_name"` SitePermissions []Permission `json:"site_permissions" table:"site_permissions"` // OrganizationPermissions are specific for the organization in the field 'OrganizationID' above. diff --git a/docs/api/audit.md b/docs/api/audit.md index a755ed9412bd5..0c2cf32cd2758 100644 --- a/docs/api/audit.md +++ b/docs/api/audit.md @@ -68,7 +68,8 @@ curl -X GET http://coder-server:8080/api/v2/audit?limit=0 \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", diff --git a/docs/api/enterprise.md b/docs/api/enterprise.md index 3cf43102e7c77..758489995ccf5 100644 --- a/docs/api/enterprise.md +++ b/docs/api/enterprise.md @@ -1600,7 +1600,8 @@ curl -X PATCH http://coder-server:8080/api/v2/scim/v2/Users/{id} \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1655,7 +1656,8 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1690,6 +1692,7 @@ Status Code **200** | `» roles` | array | false | | | | `»» display_name` | string | false | | | | `»» name` | string | false | | | +| `»» organization_id` | string | false | | | | `» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | | `» theme_preference` | string | false | | | | `» username` | string | true | | | diff --git a/docs/api/members.md b/docs/api/members.md index 6364b08ca528e..ce7cc81f1762b 100644 --- a/docs/api/members.md +++ b/docs/api/members.md @@ -289,7 +289,8 @@ curl -X PUT http://coder-server:8080/api/v2/organizations/{organization}/members "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 7770b091878bd..bd460b5f8fdbf 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -966,7 +966,8 @@ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1045,7 +1046,8 @@ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -2972,7 +2974,8 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -3616,7 +3619,8 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "updated_at": "2019-08-24T14:15:22Z", @@ -4452,16 +4456,18 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o ```json { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| -------------- | ------ | -------- | ------------ | ----------- | -| `display_name` | string | false | | | -| `name` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ----------------- | ------ | -------- | ------------ | ----------- | +| `display_name` | string | false | | | +| `name` | string | false | | | +| `organization_id` | string | false | | | ## codersdk.SupportConfig @@ -5002,7 +5008,8 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -5607,7 +5614,8 @@ If the schedule is empty, the user will be updated to use the default schedule.| "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", diff --git a/docs/api/users.md b/docs/api/users.md index c9910bf66c1c7..db5f959a7fa76 100644 --- a/docs/api/users.md +++ b/docs/api/users.md @@ -42,7 +42,8 @@ curl -X GET http://coder-server:8080/api/v2/users \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -111,7 +112,8 @@ curl -X POST http://coder-server:8080/api/v2/users \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -381,7 +383,8 @@ curl -X GET http://coder-server:8080/api/v2/users/{user} \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -434,7 +437,8 @@ curl -X DELETE http://coder-server:8080/api/v2/users/{user} \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -497,7 +501,8 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1148,7 +1153,8 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/profile \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1201,7 +1207,8 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/roles \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1264,7 +1271,8 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/roles \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1317,7 +1325,8 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/status/activate \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", @@ -1370,7 +1379,8 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/status/suspend \ "roles": [ { "display_name": "string", - "name": "string" + "name": "string", + "organization_id": "string" } ], "status": "active", diff --git a/enterprise/coderd/authorize_test.go b/enterprise/coderd/authorize_test.go index 30d890b0beab6..670df18916aaa 100644 --- a/enterprise/coderd/authorize_test.go +++ b/enterprise/coderd/authorize_test.go @@ -35,7 +35,7 @@ func TestCheckACLPermissions(t *testing.T) { memberClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID) memberUser, err := memberClient.User(ctx, codersdk.Me) require.NoError(t, err) - orgAdminClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID, rbac.RoleOrgAdmin(adminUser.OrganizationID)) + orgAdminClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID, rbac.ScopedRoleOrgAdmin(adminUser.OrganizationID)) orgAdminUser, err := orgAdminClient.User(ctx, codersdk.Me) require.NoError(t, err) diff --git a/enterprise/coderd/provisionerdaemons_test.go b/enterprise/coderd/provisionerdaemons_test.go index c62a91593d80f..68558706914a0 100644 --- a/enterprise/coderd/provisionerdaemons_test.go +++ b/enterprise/coderd/provisionerdaemons_test.go @@ -197,7 +197,7 @@ func TestProvisionerDaemonServe(t *testing.T) { codersdk.FeatureExternalProvisionerDaemons: 1, }, }}) - another, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleOrgAdmin(user.OrganizationID)) + another, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.ScopedRoleOrgAdmin(user.OrganizationID)) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() _, err := another.ServeProvisionerDaemon(ctx, codersdk.ServeProvisionerDaemonRequest{ diff --git a/enterprise/coderd/templates_test.go b/enterprise/coderd/templates_test.go index c7d9a9cfb3830..7440ee743dca2 100644 --- a/enterprise/coderd/templates_test.go +++ b/enterprise/coderd/templates_test.go @@ -1639,9 +1639,9 @@ func TestTemplateAccess(t *testing.T) { newOrg, err := ownerClient.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{Name: orgName}) require.NoError(t, err, "failed to create org") - adminCli, adminUsr := coderdtest.CreateAnotherUser(t, ownerClient, newOrg.ID, rbac.RoleOrgAdmin(newOrg.ID)) - groupMemCli, groupMemUsr := coderdtest.CreateAnotherUser(t, ownerClient, newOrg.ID, rbac.RoleOrgMember(newOrg.ID)) - memberCli, memberUsr := coderdtest.CreateAnotherUser(t, ownerClient, newOrg.ID, rbac.RoleOrgMember(newOrg.ID)) + adminCli, adminUsr := coderdtest.CreateAnotherUser(t, ownerClient, newOrg.ID, rbac.ScopedRoleOrgAdmin(newOrg.ID)) + groupMemCli, groupMemUsr := coderdtest.CreateAnotherUser(t, ownerClient, newOrg.ID, rbac.ScopedRoleOrgMember(newOrg.ID)) + memberCli, memberUsr := coderdtest.CreateAnotherUser(t, ownerClient, newOrg.ID, rbac.ScopedRoleOrgMember(newOrg.ID)) // Make group group, err := adminCli.CreateGroup(ctx, newOrg.ID, codersdk.CreateGroupRequest{ diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 88e5c7e508f67..b7de0be88ba37 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -977,7 +977,7 @@ export interface Response { // From codersdk/roles.go export interface Role { readonly name: string; - readonly organization_id: string; + readonly organization_id?: string; readonly display_name: string; readonly site_permissions: readonly Permission[]; readonly organization_permissions: readonly Permission[]; @@ -1030,6 +1030,7 @@ export interface SessionLifetime { export interface SlimRole { readonly name: string; readonly display_name: string; + readonly organization_id?: string; } // From codersdk/deployment.go