Skip to content

Commit 3b8ae70

Browse files
committed
chore: verify validity of built in rbac roles
Also some xerrors linting cleanup
1 parent a0fce36 commit 3b8ae70

File tree

4 files changed

+80
-9
lines changed

4 files changed

+80
-9
lines changed

coderd/rbac/object.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package rbac
22

33
import (
4-
"fmt"
5-
64
"github.com/google/uuid"
5+
"golang.org/x/xerrors"
76

87
"github.com/coder/coder/v2/coderd/rbac/policy"
98
)
@@ -36,10 +35,10 @@ type Object struct {
3635
func (z Object) ValidAction(action policy.Action) error {
3736
perms, ok := policy.RBACPermissions[z.Type]
3837
if !ok {
39-
return fmt.Errorf("invalid type %q", z.Type)
38+
return xerrors.Errorf("invalid type %q", z.Type)
4039
}
4140
if _, ok := perms.Actions[action]; !ok {
42-
return fmt.Errorf("invalid action %q for type %q", action, z.Type)
41+
return xerrors.Errorf("invalid action %q for type %q", action, z.Type)
4342
}
4443

4544
return nil

coderd/rbac/roles.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rbac
22

33
import (
4+
"errors"
45
"sort"
56
"strings"
67

@@ -369,6 +370,26 @@ type Permission struct {
369370
Action policy.Action `json:"action"`
370371
}
371372

373+
func (perm Permission) Valid() error {
374+
if perm.ResourceType == policy.WildcardSymbol {
375+
// Wildcard is tricky to check. Just allow it.
376+
return nil
377+
}
378+
379+
resource, ok := policy.RBACPermissions[perm.ResourceType]
380+
if !ok {
381+
return xerrors.Errorf("invalid resource type %q", perm.ResourceType)
382+
}
383+
384+
if perm.Action != policy.WildcardSymbol {
385+
_, ok := resource.Actions[perm.Action]
386+
if !ok {
387+
return xerrors.Errorf("invalid action %q for resource %q", perm.Action, perm.ResourceType)
388+
}
389+
}
390+
return nil
391+
}
392+
372393
// Role is a set of permissions at multiple levels:
373394
// - Site level permissions apply EVERYWHERE
374395
// - Org level permissions apply to EVERYTHING in a given ORG
@@ -393,6 +414,34 @@ type Role struct {
393414
cachedRegoValue ast.Value
394415
}
395416

417+
// Valid will check all it's permissions and ensure they are all correct
418+
// according to the policy. This verifies every action specified make sense
419+
// for the given resource.
420+
func (role Role) Valid() error {
421+
var errs []error
422+
for _, perm := range role.Site {
423+
if err := perm.Valid(); err != nil {
424+
errs = append(errs, xerrors.Errorf("site: %w", err))
425+
}
426+
}
427+
428+
for orgID, permissions := range role.Org {
429+
for _, perm := range permissions {
430+
if err := perm.Valid(); err != nil {
431+
errs = append(errs, xerrors.Errorf("org=%q: %w", orgID, err))
432+
}
433+
}
434+
}
435+
436+
for _, perm := range role.User {
437+
if err := perm.Valid(); err != nil {
438+
errs = append(errs, xerrors.Errorf("user: %w", err))
439+
}
440+
}
441+
442+
return errors.Join(errs...)
443+
}
444+
396445
type Roles []Role
397446

398447
func (roles Roles) Expand() ([]Role, error) {
@@ -402,7 +451,7 @@ func (roles Roles) Expand() ([]Role, error) {
402451
func (roles Roles) Names() []string {
403452
names := make([]string, 0, len(roles))
404453
for _, r := range roles {
405-
return append(names, r.Name)
454+
names = append(names, r.Name)
406455
}
407456
return names
408457
}

coderd/rbac/roles_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ type authSubject struct {
2020
Actor rbac.Subject
2121
}
2222

23+
// TestBuiltInRoles makes sure our built-in roles are valid by our own policy
24+
// rules. If this is incorrect, that is a mistake.
25+
func TestBuiltInRoles(t *testing.T) {
26+
t.Parallel()
27+
for _, r := range rbac.SiteRoles() {
28+
r := r
29+
t.Run(r.Name, func(t *testing.T) {
30+
t.Parallel()
31+
require.NoError(t, r.Valid(), "invalid role")
32+
})
33+
}
34+
35+
for _, r := range rbac.OrganizationRoles(uuid.New()) {
36+
r := r
37+
t.Run(r.Name, func(t *testing.T) {
38+
t.Parallel()
39+
require.NoError(t, r.Valid(), "invalid role")
40+
})
41+
}
42+
}
43+
2344
//nolint:tparallel,paralleltest
2445
func TestOwnerExec(t *testing.T) {
2546
owner := rbac.Subject{

scripts/rbacgen/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"slices"
1717
"strings"
1818

19+
"golang.org/x/xerrors"
20+
1921
"github.com/coder/coder/v2/coderd/rbac/policy"
2022
)
2123

@@ -148,7 +150,7 @@ func generateRbacObjects(templateSource string) ([]byte, error) {
148150
// Parse the policy.go file for the action enums
149151
f, err := parser.ParseFile(token.NewFileSet(), "./coderd/rbac/policy/policy.go", nil, parser.ParseComments)
150152
if err != nil {
151-
return nil, fmt.Errorf("parsing policy.go: %w", err)
153+
return nil, xerrors.Errorf("parsing policy.go: %w", err)
152154
}
153155
actionMap := fileActions(f)
154156
actionList := make([]ActionDetails, 0)
@@ -176,14 +178,14 @@ func generateRbacObjects(templateSource string) ([]byte, error) {
176178
x++
177179
v, ok := actionMap[string(action)]
178180
if !ok {
179-
errorList = append(errorList, fmt.Errorf("action value %q does not have a constant a matching enum constant", action))
181+
errorList = append(errorList, xerrors.Errorf("action value %q does not have a constant a matching enum constant", action))
180182
}
181183
return v
182184
},
183185
"concat": func(strs ...string) string { return strings.Join(strs, "") },
184186
}).Parse(templateSource)
185187
if err != nil {
186-
return nil, fmt.Errorf("parse template: %w", err)
188+
return nil, xerrors.Errorf("parse template: %w", err)
187189
}
188190

189191
// Convert to sorted list for autogen consistency.
@@ -203,7 +205,7 @@ func generateRbacObjects(templateSource string) ([]byte, error) {
203205

204206
err = tpl.Execute(&out, list)
205207
if err != nil {
206-
return nil, fmt.Errorf("execute template: %w", err)
208+
return nil, xerrors.Errorf("execute template: %w", err)
207209
}
208210

209211
if len(errorList) > 0 {

0 commit comments

Comments
 (0)