Skip to content

Commit 6797739

Browse files
committed
Add organization role listing
1 parent 8839537 commit 6797739

File tree

17 files changed

+127
-34
lines changed

17 files changed

+127
-34
lines changed

coderd/apidoc/docs.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/db2sdk/db2sdk.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,13 @@ func ProvisionerDaemon(dbDaemon database.ProvisionerDaemon) codersdk.Provisioner
527527
}
528528

529529
func Role(role rbac.Role) codersdk.Role {
530+
roleName, orgIDStr, err := rbac.RoleSplit(role.Name)
531+
if err != nil {
532+
roleName = role.Name
533+
}
530534
return codersdk.Role{
531-
Name: role.Name,
535+
Name: roleName,
536+
OrganizationID: orgIDStr,
532537
DisplayName: role.DisplayName,
533538
SitePermissions: List(role.Site, Permission),
534539
OrganizationPermissions: Map(role.Org, ListLazy(Permission)),
@@ -546,7 +551,7 @@ func Permission(permission rbac.Permission) codersdk.Permission {
546551

547552
func RoleToRBAC(role codersdk.Role) rbac.Role {
548553
return rbac.Role{
549-
Name: role.Name,
554+
Name: rbac.RoleName(role.Name, role.OrganizationID),
550555
DisplayName: role.DisplayName,
551556
Site: List(role.SitePermissions, PermissionToRBAC),
552557
Org: Map(role.OrganizationPermissions, ListLazy(PermissionToRBAC)),

coderd/database/models.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

+10-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/roles.sql

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ WHERE
1616
organization_id IS null
1717
ELSE true
1818
END
19+
-- Org scoping filter, to only fetch site wide roles
20+
AND CASE WHEN @organization_id :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
21+
organization_id = @organization_id
22+
ELSE true
23+
END
1924
;
2025

2126
-- name: UpsertCustomRole :one

coderd/rbac/roles.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,29 @@ func (names RoleNames) Names() []string {
5353
// site and orgs, and these functions can be removed.
5454

5555
func RoleOwner() string {
56-
return roleName(owner, "")
56+
return RoleName(owner, "")
5757
}
5858

59-
func CustomSiteRole() string { return roleName(customSiteRole, "") }
59+
func CustomSiteRole() string { return RoleName(customSiteRole, "") }
6060

6161
func RoleTemplateAdmin() string {
62-
return roleName(templateAdmin, "")
62+
return RoleName(templateAdmin, "")
6363
}
6464

6565
func RoleUserAdmin() string {
66-
return roleName(userAdmin, "")
66+
return RoleName(userAdmin, "")
6767
}
6868

6969
func RoleMember() string {
70-
return roleName(member, "")
70+
return RoleName(member, "")
7171
}
7272

7373
func RoleOrgAdmin(organizationID uuid.UUID) string {
74-
return roleName(orgAdmin, organizationID.String())
74+
return RoleName(orgAdmin, organizationID.String())
7575
}
7676

7777
func RoleOrgMember(organizationID uuid.UUID) string {
78-
return roleName(orgMember, organizationID.String())
78+
return RoleName(orgMember, organizationID.String())
7979
}
8080

8181
func allPermsExcept(excepts ...Objecter) []Permission {
@@ -273,7 +273,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
273273
// organization scope.
274274
orgAdmin: func(organizationID string) Role {
275275
return Role{
276-
Name: roleName(orgAdmin, organizationID),
276+
Name: RoleName(orgAdmin, organizationID),
277277
DisplayName: "Organization Admin",
278278
Site: []Permission{},
279279
Org: map[string][]Permission{
@@ -291,7 +291,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
291291
// in an organization.
292292
orgMember: func(organizationID string) Role {
293293
return Role{
294-
Name: roleName(orgMember, organizationID),
294+
Name: RoleName(orgMember, organizationID),
295295
DisplayName: "",
296296
Site: []Permission{},
297297
Org: map[string][]Permission{
@@ -475,13 +475,13 @@ func CanAssignRole(expandable ExpandableRoles, assignedRole string) bool {
475475
// For CanAssignRole, we only care about the names of the roles.
476476
roles := expandable.Names()
477477

478-
assigned, assignedOrg, err := roleSplit(assignedRole)
478+
assigned, assignedOrg, err := RoleSplit(assignedRole)
479479
if err != nil {
480480
return false
481481
}
482482

483483
for _, longRole := range roles {
484-
role, orgID, err := roleSplit(longRole)
484+
role, orgID, err := RoleSplit(longRole)
485485
if err != nil {
486486
continue
487487
}
@@ -510,7 +510,7 @@ func CanAssignRole(expandable ExpandableRoles, assignedRole string) bool {
510510
// api. We should maybe make an exported function that returns just the
511511
// human-readable content of the Role struct (name + display name).
512512
func RoleByName(name string) (Role, error) {
513-
roleName, orgID, err := roleSplit(name)
513+
roleName, orgID, err := RoleSplit(name)
514514
if err != nil {
515515
return Role{}, xerrors.Errorf("parse role name: %w", err)
516516
}
@@ -544,7 +544,7 @@ func rolesByNames(roleNames []string) ([]Role, error) {
544544
}
545545

546546
func IsOrgRole(roleName string) (string, bool) {
547-
_, orgID, err := roleSplit(roleName)
547+
_, orgID, err := RoleSplit(roleName)
548548
if err == nil && orgID != "" {
549549
return orgID, true
550550
}
@@ -561,7 +561,7 @@ func OrganizationRoles(organizationID uuid.UUID) []Role {
561561
var roles []Role
562562
for _, roleF := range builtInRoles {
563563
role := roleF(organizationID.String())
564-
_, scope, err := roleSplit(role.Name)
564+
_, scope, err := RoleSplit(role.Name)
565565
if err != nil {
566566
// This should never happen
567567
continue
@@ -582,7 +582,7 @@ func SiteRoles() []Role {
582582
var roles []Role
583583
for _, roleF := range builtInRoles {
584584
role := roleF("random")
585-
_, scope, err := roleSplit(role.Name)
585+
_, scope, err := RoleSplit(role.Name)
586586
if err != nil {
587587
// This should never happen
588588
continue
@@ -625,19 +625,19 @@ func ChangeRoleSet(from []string, to []string) (added []string, removed []string
625625
return added, removed
626626
}
627627

628-
// roleName is a quick helper function to return
628+
// RoleName is a quick helper function to return
629629
//
630630
// role_name:scopeID
631631
//
632632
// If no scopeID is required, only 'role_name' is returned
633-
func roleName(name string, orgID string) string {
633+
func RoleName(name string, orgID string) string {
634634
if orgID == "" {
635635
return name
636636
}
637637
return name + ":" + orgID
638638
}
639639

640-
func roleSplit(role string) (name string, orgID string, err error) {
640+
func RoleSplit(role string) (name string, orgID string, err error) {
641641
arr := strings.Split(role, ":")
642642
if len(arr) > 2 {
643643
return "", "", xerrors.Errorf("too many colons in role name")

coderd/rbac/rolestore/rolestore.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"net/http"
77

8+
"github.com/google/uuid"
89
"golang.org/x/xerrors"
910

1011
"github.com/coder/coder/v2/coderd/database"
@@ -95,8 +96,12 @@ func Expand(ctx context.Context, db database.Store, names []string) (rbac.Roles,
9596
}
9697

9798
func ConvertDBRole(dbRole database.CustomRole) (rbac.Role, error) {
99+
name := dbRole.Name
100+
if dbRole.OrganizationID.Valid {
101+
name = rbac.RoleName(dbRole.Name, dbRole.OrganizationID.UUID.String())
102+
}
98103
role := rbac.Role{
99-
Name: dbRole.Name,
104+
Name: name,
100105
DisplayName: dbRole.DisplayName,
101106
Site: nil,
102107
Org: nil,
@@ -122,11 +127,27 @@ func ConvertDBRole(dbRole database.CustomRole) (rbac.Role, error) {
122127
}
123128

124129
func ConvertRoleToDB(role rbac.Role) (database.CustomRole, error) {
130+
roleName, orgIDStr, err := rbac.RoleSplit(role.Name)
131+
if err != nil {
132+
return database.CustomRole{}, xerrors.Errorf("split role %q: %w", role.Name, err)
133+
}
134+
125135
dbRole := database.CustomRole{
126-
Name: role.Name,
136+
Name: roleName,
127137
DisplayName: role.DisplayName,
128138
}
129139

140+
if orgIDStr != "" {
141+
orgID, err := uuid.Parse(orgIDStr)
142+
if err != nil {
143+
return database.CustomRole{}, xerrors.Errorf("parse org id %q: %w", orgIDStr, err)
144+
}
145+
dbRole.OrganizationID = uuid.NullUUID{
146+
UUID: orgID,
147+
Valid: true,
148+
}
149+
}
150+
130151
siteData, err := json.Marshal(role.Site)
131152
if err != nil {
132153
return dbRole, xerrors.Errorf("marshal site permissions: %w", err)

coderd/roles.go

+17
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ func (api *API) assignableOrgRoles(rw http.ResponseWriter, r *http.Request) {
129129
}
130130

131131
roles := rbac.OrganizationRoles(organization.ID)
132+
dbCustomRoles, err := api.Database.CustomRoles(ctx, database.CustomRolesParams{
133+
LookupRoles: nil,
134+
ExcludeOrgRoles: false,
135+
OrganizationID: organization.ID,
136+
})
137+
if err != nil {
138+
httpapi.InternalServerError(rw, err)
139+
return
140+
}
141+
142+
customRoles := make([]rbac.Role, 0, len(dbCustomRoles))
143+
for _, customRole := range dbCustomRoles {
144+
rbacRole, err := rolestore.ConvertDBRole(customRole)
145+
if err == nil {
146+
customRoles = append(customRoles, rbacRole)
147+
}
148+
}
132149
httpapi.Write(ctx, rw, http.StatusOK, assignableRoles(actorRoles.Roles, roles, []rbac.Role{}))
133150
}
134151

codersdk/roles.go

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type Permission struct {
3636
// Role is a longer form of SlimRole used to edit custom roles.
3737
type Role struct {
3838
Name string `json:"name" table:"name,default_sort" validate:"username"`
39+
OrganizationID string `json:"organization_id" table:"organization_id" format:"uuid"`
3940
DisplayName string `json:"display_name" table:"display_name"`
4041
SitePermissions []Permission `json:"site_permissions" table:"site_permissions"`
4142
// map[<org_id>] -> Permissions

0 commit comments

Comments
 (0)