Skip to content

Commit 2ba9bde

Browse files
committed
fix site <-> user perms bug
1 parent 095ad88 commit 2ba9bde

File tree

5 files changed

+114
-74
lines changed

5 files changed

+114
-74
lines changed

coderd/database/db2sdk/db2sdk.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ func Role(role rbac.Role) codersdk.Role {
532532
DisplayName: role.DisplayName,
533533
SitePermissions: List(role.Site, Permission),
534534
OrganizationPermissions: Map(role.Org, ListLazy(Permission)),
535-
UserPermissions: List(role.Site, Permission),
535+
UserPermissions: List(role.User, Permission),
536536
}
537537
}
538538

enterprise/cli/roleedit.go

Lines changed: 81 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ import (
1919
func (r *RootCmd) editRole() *serpent.Command {
2020
formatter := cliui.NewOutputFormatter(
2121
cliui.ChangeFormatterData(
22-
cliui.TableFormat([]codersdk.Role{}, []string{"name", "display_name", "site_permissions", "org_permissions", "user_permissions"}),
22+
cliui.TableFormat([]roleTableView{}, []string{"name", "display_name", "site_permissions", "org_permissions", "user_permissions"}),
2323
func(data any) (any, error) {
24-
return []codersdk.Role{data.(codersdk.Role)}, nil
24+
typed, _ := data.(codersdk.Role)
25+
return []roleTableView{roleToTableView(typed)}, nil
2526
},
2627
),
2728
cliui.JSONFormat(),
@@ -51,108 +52,126 @@ func (r *RootCmd) editRole() *serpent.Command {
5152
},
5253
},
5354
Middleware: serpent.Chain(
54-
serpent.RequireNArgs(1),
55+
serpent.RequireRangeArgs(0, 1),
5556
r.InitClient(client),
5657
),
5758
Handler: func(inv *serpent.Invocation) error {
5859
ctx := inv.Context()
59-
roles, err := client.ListSiteRoles(ctx)
60-
if err != nil {
61-
return xerrors.Errorf("listing roles: %w", err)
62-
}
63-
64-
// Make sure the role actually exists first
65-
var originalRole codersdk.AssignableRoles
66-
for _, r := range roles {
67-
if strings.EqualFold(inv.Args[0], r.Name) {
68-
originalRole = r
69-
break
70-
}
71-
}
72-
73-
if originalRole.Name == "" {
74-
_, err = cliui.Prompt(inv, cliui.PromptOptions{
75-
Text: "No role exists with that name, do you want to create one?",
76-
Default: "yes",
77-
IsConfirm: true,
78-
})
79-
if err != nil {
80-
return xerrors.Errorf("abort: %w", err)
81-
}
8260

83-
originalRole.Role = codersdk.Role{
84-
Name: inv.Args[0],
85-
}
86-
}
87-
88-
var customRole *codersdk.Role
89-
// Either interactive, or take input mode.
61+
var customRole codersdk.Role
9062
fi, _ := os.Stdin.Stat()
9163
if (fi.Mode() & os.ModeCharDevice) == 0 {
64+
// JSON Upload mode
9265
bytes, err := io.ReadAll(os.Stdin)
9366
if err != nil {
9467
return xerrors.Errorf("reading stdin: %w", err)
9568
}
9669

97-
err = json.Unmarshal(bytes, customRole)
70+
err = json.Unmarshal(bytes, &customRole)
9871
if err != nil {
9972
return xerrors.Errorf("parsing stdin json: %w", err)
10073
}
101-
} else {
102-
// Interactive mode
103-
if len(originalRole.OrganizationPermissions) > 0 {
104-
return xerrors.Errorf("unable to edit role in interactive mode, it contains organization permissions")
105-
}
10674

107-
if len(originalRole.UserPermissions) > 0 {
108-
return xerrors.Errorf("unable to edit role in interactive mode, it contains user permissions")
75+
if customRole.Name == "" {
76+
arr := make([]json.RawMessage, 0)
77+
err = json.Unmarshal(bytes, &arr)
78+
if err == nil && len(arr) > 0 {
79+
return xerrors.Errorf("the input appears to be an array, only 1 role can be sent at a time")
80+
}
81+
return xerrors.Errorf("json input does not appear to be a valid role")
10982
}
110-
111-
customRole, err = interactiveEdit(inv, &originalRole.Role)
83+
} else {
84+
interactiveRole, err := interactiveEdit(inv, client)
11285
if err != nil {
11386
return xerrors.Errorf("editing role: %w", err)
11487
}
115-
}
11688

117-
totalOrg := 0
118-
for _, o := range customRole.OrganizationPermissions {
119-
totalOrg += len(o)
120-
}
121-
preview := fmt.Sprintf("perms: %d site, %d over %d orgs, %d user",
122-
len(customRole.SitePermissions), totalOrg, len(customRole.OrganizationPermissions), len(customRole.UserPermissions))
123-
_, err = cliui.Prompt(inv, cliui.PromptOptions{
124-
Text: "Are you sure you wish to update the role? " + preview,
125-
Default: "yes",
126-
IsConfirm: true,
127-
})
128-
if err != nil {
129-
return xerrors.Errorf("abort: %w", err)
89+
customRole = *interactiveRole
90+
91+
// Only the interactive can answer prompts.
92+
totalOrg := 0
93+
for _, o := range customRole.OrganizationPermissions {
94+
totalOrg += len(o)
95+
}
96+
preview := fmt.Sprintf("perms: %d site, %d over %d orgs, %d user",
97+
len(customRole.SitePermissions), totalOrg, len(customRole.OrganizationPermissions), len(customRole.UserPermissions))
98+
_, err = cliui.Prompt(inv, cliui.PromptOptions{
99+
Text: "Are you sure you wish to update the role? " + preview,
100+
Default: "yes",
101+
IsConfirm: true,
102+
})
103+
if err != nil {
104+
return xerrors.Errorf("abort: %w", err)
105+
}
130106
}
131107

108+
var err error
132109
var updated codersdk.Role
133110
if dryRun {
134111
// Do not actually post
135-
updated = *customRole
112+
updated = customRole
136113
} else {
137-
updated, err = client.PatchRole(ctx, *customRole)
114+
updated, err = client.PatchRole(ctx, customRole)
138115
if err != nil {
139116
return fmt.Errorf("patch role: %w", err)
140117
}
141118
}
142119

143-
_, err = formatter.Format(ctx, updated)
120+
output, err := formatter.Format(ctx, updated)
144121
if err != nil {
145122
return xerrors.Errorf("formatting: %w", err)
146123
}
147-
return nil
124+
125+
_, err = fmt.Fprintln(inv.Stdout, output)
126+
return err
148127
},
149128
}
150129

151130
formatter.AttachOptions(&cmd.Options)
152131
return cmd
153132
}
154133

155-
func interactiveEdit(inv *serpent.Invocation, role *codersdk.Role) (*codersdk.Role, error) {
134+
func interactiveEdit(inv *serpent.Invocation, client *codersdk.Client) (*codersdk.Role, error) {
135+
ctx := inv.Context()
136+
roles, err := client.ListSiteRoles(ctx)
137+
if err != nil {
138+
return nil, xerrors.Errorf("listing roles: %w", err)
139+
}
140+
141+
// Make sure the role actually exists first
142+
var originalRole codersdk.AssignableRoles
143+
for _, r := range roles {
144+
if strings.EqualFold(inv.Args[0], r.Name) {
145+
originalRole = r
146+
break
147+
}
148+
}
149+
150+
if originalRole.Name == "" {
151+
_, err = cliui.Prompt(inv, cliui.PromptOptions{
152+
Text: "No role exists with that name, do you want to create one?",
153+
Default: "yes",
154+
IsConfirm: true,
155+
})
156+
if err != nil {
157+
return nil, xerrors.Errorf("abort: %w", err)
158+
}
159+
160+
originalRole.Role = codersdk.Role{
161+
Name: inv.Args[0],
162+
}
163+
}
164+
165+
// Some checks since interactive mode is limited in what it currently sees
166+
if len(originalRole.OrganizationPermissions) > 0 {
167+
return nil, xerrors.Errorf("unable to edit role in interactive mode, it contains organization permissions")
168+
}
169+
170+
if len(originalRole.UserPermissions) > 0 {
171+
return nil, xerrors.Errorf("unable to edit role in interactive mode, it contains user permissions")
172+
}
173+
174+
role := &originalRole.Role
156175
allowedResources := []codersdk.RBACResource{
157176
codersdk.ResourceTemplate,
158177
codersdk.ResourceWorkspace,

enterprise/cli/rolescmd.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,9 @@ func (r *RootCmd) showRole() *serpent.Command {
4444
rows := make([]assignableRolesTableRow, 0, len(input))
4545
for _, role := range input {
4646
rows = append(rows, assignableRolesTableRow{
47-
Name: role.Name,
48-
DisplayName: role.DisplayName,
49-
SitePermissions: fmt.Sprintf("%d permissions", len(role.SitePermissions)),
50-
OrganizationPermissions: fmt.Sprintf("%d organizations", len(role.OrganizationPermissions)),
51-
UserPermissions: fmt.Sprintf("%d permissions", len(role.UserPermissions)),
52-
Assignable: role.Assignable,
53-
BuiltIn: role.BuiltIn,
47+
roleTableView: roleToTableView(role.Role),
48+
Assignable: role.Assignable,
49+
BuiltIn: role.BuiltIn,
5450
})
5551
}
5652
return rows, nil
@@ -100,13 +96,27 @@ func (r *RootCmd) showRole() *serpent.Command {
10096
return cmd
10197
}
10298

103-
type assignableRolesTableRow struct {
99+
func roleToTableView(role codersdk.Role) roleTableView {
100+
return roleTableView{
101+
Name: role.Name,
102+
DisplayName: role.DisplayName,
103+
SitePermissions: fmt.Sprintf("%d permissions", len(role.SitePermissions)),
104+
OrganizationPermissions: fmt.Sprintf("%d organizations", len(role.OrganizationPermissions)),
105+
UserPermissions: fmt.Sprintf("%d permissions", len(role.UserPermissions)),
106+
}
107+
}
108+
109+
type roleTableView struct {
104110
Name string `table:"name,default_sort"`
105111
DisplayName string `table:"display_name"`
106112
SitePermissions string ` table:"site_permissions"`
107113
// map[<org_id>] -> Permissions
108114
OrganizationPermissions string `table:"org_permissions"`
109115
UserPermissions string `table:"user_permissions"`
110-
Assignable bool `table:"assignable"`
111-
BuiltIn bool `table:"built_in"`
116+
}
117+
118+
type assignableRolesTableRow struct {
119+
roleTableView `table:"r,recursive_inline"`
120+
Assignable bool `table:"assignable"`
121+
BuiltIn bool `table:"built_in"`
112122
}

enterprise/cmd/coder/role.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{
2+
}

enterprise/coderd/roles_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,18 @@ func TestCustomRole(t *testing.T) {
6767
allRoles, err := tmplAdmin.ListSiteRoles(ctx)
6868
require.NoError(t, err)
6969

70+
var foundRole codersdk.AssignableRoles
7071
require.True(t, slices.ContainsFunc(allRoles, func(selected codersdk.AssignableRoles) bool {
71-
return selected.Name == role.Name
72+
if selected.Name == role.Name {
73+
foundRole = selected
74+
return true
75+
}
76+
return false
7277
}), "role missing from site role list")
78+
79+
require.Len(t, foundRole.SitePermissions, 7)
80+
require.Len(t, foundRole.OrganizationPermissions, 0)
81+
require.Len(t, foundRole.UserPermissions, 0)
7382
})
7483

7584
// Revoked licenses cannot modify/create custom roles, but they can

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