Skip to content

Commit 1b4ca00

Browse files
authored
chore: include custom roles in list org roles (#13336)
* chore: include custom roles in list org roles * move cli show roles to org scope
1 parent d748c6d commit 1b4ca00

File tree

24 files changed

+312
-117
lines changed

24 files changed

+312
-117
lines changed

cli/organization.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func (r *RootCmd) organizations() *serpent.Command {
3030
r.currentOrganization(),
3131
r.switchOrganization(),
3232
r.createOrganization(),
33+
r.organizationRoles(),
3334
},
3435
}
3536

enterprise/cli/rolescmd.go renamed to cli/organizationroles.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,23 @@ import (
1212
"github.com/coder/serpent"
1313
)
1414

15-
// **NOTE** Only covers site wide roles at present. Org scoped roles maybe
16-
// should be nested under some command that scopes to an org??
17-
18-
func (r *RootCmd) roles() *serpent.Command {
15+
func (r *RootCmd) organizationRoles() *serpent.Command {
1916
cmd := &serpent.Command{
2017
Use: "roles",
21-
Short: "Manage site-wide roles.",
18+
Short: "Manage organization roles.",
2219
Aliases: []string{"role"},
2320
Handler: func(inv *serpent.Invocation) error {
2421
return inv.Command.HelpHandler(inv)
2522
},
2623
Hidden: true,
2724
Children: []*serpent.Command{
28-
r.showRole(),
25+
r.showOrganizationRoles(),
2926
},
3027
}
3128
return cmd
3229
}
3330

34-
func (r *RootCmd) showRole() *serpent.Command {
31+
func (r *RootCmd) showOrganizationRoles() *serpent.Command {
3532
formatter := cliui.NewOutputFormatter(
3633
cliui.ChangeFormatterData(
3734
cliui.TableFormat([]assignableRolesTableRow{}, []string{"name", "display_name", "built_in", "site_permissions", "org_permissions", "user_permissions"}),
@@ -67,7 +64,12 @@ func (r *RootCmd) showRole() *serpent.Command {
6764
),
6865
Handler: func(inv *serpent.Invocation) error {
6966
ctx := inv.Context()
70-
roles, err := client.ListSiteRoles(ctx)
67+
org, err := CurrentOrganization(r, inv, client)
68+
if err != nil {
69+
return err
70+
}
71+
72+
roles, err := client.ListOrganizationRoles(ctx, org.ID)
7173
if err != nil {
7274
return xerrors.Errorf("listing roles: %w", err)
7375
}

cli/organizationroles_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package cli_test
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/google/uuid"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/cli/clitest"
11+
"github.com/coder/coder/v2/coderd/coderdtest"
12+
"github.com/coder/coder/v2/coderd/database"
13+
"github.com/coder/coder/v2/coderd/database/dbgen"
14+
"github.com/coder/coder/v2/coderd/rbac"
15+
"github.com/coder/coder/v2/testutil"
16+
)
17+
18+
func TestShowOrganizationRoles(t *testing.T) {
19+
t.Parallel()
20+
21+
t.Run("OK", func(t *testing.T) {
22+
t.Parallel()
23+
24+
ownerClient, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{})
25+
owner := coderdtest.CreateFirstUser(t, ownerClient)
26+
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleUserAdmin())
27+
28+
const expectedRole = "test-role"
29+
dbgen.CustomRole(t, db, database.CustomRole{
30+
Name: expectedRole,
31+
DisplayName: "Expected",
32+
SitePermissions: nil,
33+
OrgPermissions: nil,
34+
UserPermissions: nil,
35+
OrganizationID: uuid.NullUUID{
36+
UUID: owner.OrganizationID,
37+
Valid: true,
38+
},
39+
})
40+
41+
ctx := testutil.Context(t, testutil.WaitMedium)
42+
inv, root := clitest.New(t, "organization", "roles", "show")
43+
clitest.SetupConfig(t, client, root)
44+
45+
buf := new(bytes.Buffer)
46+
inv.Stdout = buf
47+
err := inv.WithContext(ctx).Run()
48+
require.NoError(t, err)
49+
require.Contains(t, buf.String(), expectedRole)
50+
})
51+
}

coderd/apidoc/docs.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/db2sdk/db2sdk.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,17 @@ 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)),
535-
UserPermissions: List(role.Site, Permission),
540+
UserPermissions: List(role.User, Permission),
536541
}
537542
}
538543

@@ -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/dbgen/dbgen.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"encoding/json"
99
"fmt"
1010
"net"
11+
"strings"
1112
"testing"
1213
"time"
1314

@@ -817,6 +818,19 @@ func OAuth2ProviderAppToken(t testing.TB, db database.Store, seed database.OAuth
817818
return token
818819
}
819820

821+
func CustomRole(t testing.TB, db database.Store, seed database.CustomRole) database.CustomRole {
822+
role, err := db.UpsertCustomRole(genCtx, database.UpsertCustomRoleParams{
823+
Name: takeFirst(seed.Name, strings.ToLower(namesgenerator.GetRandomName(1))),
824+
DisplayName: namesgenerator.GetRandomName(1),
825+
OrganizationID: seed.OrganizationID,
826+
SitePermissions: takeFirstSlice(seed.SitePermissions, []byte("[]")),
827+
OrgPermissions: takeFirstSlice(seed.SitePermissions, []byte("{}")),
828+
UserPermissions: takeFirstSlice(seed.SitePermissions, []byte("[]")),
829+
})
830+
require.NoError(t, err, "insert custom role")
831+
return role
832+
}
833+
820834
func must[V any](v V, err error) V {
821835
if err != nil {
822836
panic(err)

coderd/database/dbmem/dbmem.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,11 @@ func (q *FakeQuerier) CustomRoles(_ context.Context, arg database.CustomRolesPar
11871187
role := role
11881188
if len(arg.LookupRoles) > 0 {
11891189
if !slices.ContainsFunc(arg.LookupRoles, func(s string) bool {
1190-
return strings.EqualFold(s, role.Name)
1190+
roleName := rbac.RoleName(role.Name, "")
1191+
if role.OrganizationID.UUID != uuid.Nil {
1192+
roleName = rbac.RoleName(role.Name, role.OrganizationID.UUID.String())
1193+
}
1194+
return strings.EqualFold(s, roleName)
11911195
}) {
11921196
continue
11931197
}
@@ -1197,6 +1201,10 @@ func (q *FakeQuerier) CustomRoles(_ context.Context, arg database.CustomRolesPar
11971201
continue
11981202
}
11991203

1204+
if arg.OrganizationID != uuid.Nil && role.OrganizationID.UUID != arg.OrganizationID {
1205+
continue
1206+
}
1207+
12001208
found = append(found, role)
12011209
}
12021210

@@ -8377,6 +8385,7 @@ func (q *FakeQuerier) UpsertCustomRole(_ context.Context, arg database.UpsertCus
83778385
for i := range q.customRoles {
83788386
if strings.EqualFold(q.customRoles[i].Name, arg.Name) {
83798387
q.customRoles[i].DisplayName = arg.DisplayName
8388+
q.customRoles[i].OrganizationID = arg.OrganizationID
83808389
q.customRoles[i].SitePermissions = arg.SitePermissions
83818390
q.customRoles[i].OrgPermissions = arg.OrgPermissions
83828391
q.customRoles[i].UserPermissions = arg.UserPermissions
@@ -8388,6 +8397,7 @@ func (q *FakeQuerier) UpsertCustomRole(_ context.Context, arg database.UpsertCus
83888397
role := database.CustomRole{
83898398
Name: arg.Name,
83908399
DisplayName: arg.DisplayName,
8400+
OrganizationID: arg.OrganizationID,
83918401
SitePermissions: arg.SitePermissions,
83928402
OrgPermissions: arg.OrgPermissions,
83938403
UserPermissions: arg.UserPermissions,

coderd/database/queries.sql.go

Lines changed: 21 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/roles.sql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,32 @@ FROM
55
custom_roles
66
WHERE
77
true
8-
-- Lookup roles filter
8+
-- Lookup roles filter expects the role names to be in the rbac package
9+
-- format. Eg: name[:<organization_id>]
910
AND CASE WHEN array_length(@lookup_roles :: text[], 1) > 0 THEN
10-
-- Case insensitive
11-
name ILIKE ANY(@lookup_roles :: text [])
11+
-- Case insensitive lookup with org_id appended (if non-null).
12+
-- This will return just the name if org_id is null. It'll append
13+
-- the org_id if not null
14+
concat(name, NULLIF(concat(':', organization_id), ':')) ILIKE ANY(@lookup_roles :: text [])
1215
ELSE true
1316
END
1417
-- Org scoping filter, to only fetch site wide roles
1518
AND CASE WHEN @exclude_org_roles :: boolean THEN
1619
organization_id IS null
1720
ELSE true
1821
END
22+
AND CASE WHEN @organization_id :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
23+
organization_id = @organization_id
24+
ELSE true
25+
END
1926
;
2027

2128
-- name: UpsertCustomRole :one
2229
INSERT INTO
2330
custom_roles (
2431
name,
2532
display_name,
33+
organization_id,
2634
site_permissions,
2735
org_permissions,
2836
user_permissions,
@@ -33,6 +41,7 @@ VALUES (
3341
-- Always force lowercase names
3442
lower(@name),
3543
@display_name,
44+
@organization_id,
3645
@site_permissions,
3746
@org_permissions,
3847
@user_permissions,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy