Skip to content

Commit 4946897

Browse files
committed
chore: Make all permission variant levels
Playing around with helper functions to make life easy
1 parent fbf4db1 commit 4946897

File tree

10 files changed

+265
-71
lines changed

10 files changed

+265
-71
lines changed

coderd/authz/authz.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package authz
2+
3+
// TODO: Implement Authorize
4+
func Authorize(subj interface{}, obj Object, action interface{}) error {
5+
return nil
6+
}

coderd/authz/authz_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package authz_test
2+
3+
import (
4+
"fmt"
5+
"github.com/coder/coder/coderd/authz/authztest"
6+
"math/bits"
7+
"testing"
8+
)
9+
10+
var nilSet = authztest.Set{nil}
11+
12+
func Test_ExhaustiveAuthorize(t *testing.T) {
13+
all := authztest.GroupedPermissions(authztest.AllPermissions())
14+
variants := permissionVariants(all)
15+
for name, v := range variants {
16+
fmt.Printf("%s: %d\n", name, v.Size())
17+
}
18+
}
19+
20+
func permissionVariants(all authztest.SetGroup) map[string]*authztest.Role {
21+
// an is any noise above the impactful set
22+
an := abstain
23+
// ln is any noise below the impactful set
24+
ln := positive | negative | abstain
25+
26+
// Cases are X+/- where X indicates the level where the impactful set is.
27+
// The impactful set determines the result.
28+
return map[string]*authztest.Role{
29+
// Wild
30+
"W+": authztest.NewRole(
31+
pos(all.Wildcard()),
32+
noise(ln, all.Site(), all.Org(), all.User()),
33+
),
34+
"W-": authztest.NewRole(
35+
neg(all.Wildcard()),
36+
noise(ln, all.Site(), all.Org(), all.User()),
37+
),
38+
// Site
39+
"S+": authztest.NewRole(
40+
noise(an, all.Wildcard()),
41+
pos(all.Site()),
42+
noise(ln, all.Org(), all.User()),
43+
),
44+
"S-": authztest.NewRole(
45+
noise(an, all.Wildcard()),
46+
neg(all.Site()),
47+
noise(ln, all.Org(), all.User()),
48+
),
49+
// TODO: Figure out cross org noise between org:* and org:mem
50+
// Org:*
51+
"O+": authztest.NewRole(
52+
noise(an, all.Wildcard(), all.Site()),
53+
pos(all.Org()),
54+
noise(ln, all.User()),
55+
),
56+
"O-": authztest.NewRole(
57+
noise(an, all.Wildcard(), all.Site()),
58+
neg(all.Org()),
59+
noise(ln, all.User()),
60+
),
61+
// Org:Mem
62+
"M+": authztest.NewRole(
63+
noise(an, all.Wildcard(), all.Site()),
64+
pos(all.OrgMem()),
65+
noise(ln, all.User()),
66+
),
67+
"M-": authztest.NewRole(
68+
noise(an, all.Wildcard(), all.Site()),
69+
neg(all.OrgMem()),
70+
noise(ln, all.User()),
71+
),
72+
// User
73+
"U+": authztest.NewRole(
74+
noise(an, all.Wildcard(), all.Site(), all.Org()),
75+
pos(all.User()),
76+
),
77+
"U-": authztest.NewRole(
78+
noise(an, all.Wildcard(), all.Site(), all.Org()),
79+
neg(all.User()),
80+
),
81+
}
82+
}
83+
84+
func l() {
85+
//authztest.Levels
86+
//noise(an, all.Wildcard()),
87+
// neg(all.Site()),
88+
// noise(ln, all.Org(), all.User()),
89+
}
90+
91+
// pos returns the positive impactful variant for a given level. It does not
92+
// include noise at any other level but the one given.
93+
func pos(lvl authztest.LevelGroup) *authztest.Role {
94+
return authztest.NewRole(
95+
lvl.Positive(),
96+
authztest.Union(lvl.Abstain()[:1], nilSet),
97+
)
98+
}
99+
100+
func neg(lvl authztest.LevelGroup) *authztest.Role {
101+
return authztest.NewRole(
102+
lvl.Negative(),
103+
authztest.Union(lvl.Positive()[:1], nilSet),
104+
authztest.Union(lvl.Abstain()[:1], nilSet),
105+
)
106+
}
107+
108+
type noiseBits uint8
109+
110+
const (
111+
none noiseBits = 1 << iota
112+
positive
113+
negative
114+
abstain
115+
)
116+
117+
func flagMatch(flag, in noiseBits) bool {
118+
return flag&in != 0
119+
}
120+
121+
// noise returns the noise permission permutations for a given level. You can
122+
// use this helper function when this level is not impactful.
123+
// The returned role is the permutations including at least one example of
124+
// positive, negative, and neutral permissions. It also includes the set of
125+
// no additional permissions.
126+
func noise(f noiseBits, lvls ...authztest.LevelGroup) *authztest.Role {
127+
rs := make([]authztest.Iterable, 0, len(lvls))
128+
for _, lvl := range lvls {
129+
sets := make([]authztest.Iterable, 0, bits.OnesCount8(uint8(f)))
130+
131+
if flagMatch(positive, f) {
132+
sets = append(sets, authztest.Union(lvl.Positive()[:1], nilSet))
133+
}
134+
if flagMatch(negative, f) {
135+
sets = append(sets, authztest.Union(lvl.Negative()[:1], nilSet))
136+
}
137+
if flagMatch(abstain, f) {
138+
sets = append(sets, authztest.Union(lvl.Abstain()[:1], nilSet))
139+
}
140+
141+
rs = append(rs, authztest.NewRole(
142+
sets...,
143+
))
144+
}
145+
146+
if len(rs) == 1 {
147+
return rs[0].(*authztest.Role)
148+
}
149+
return authztest.NewRole(rs...)
150+
}

coderd/authz/authztest/group.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ var nilSet = Set{nil}
1818
// *.*.*.*
1919
//var PermissionSetWPlus = NewRole(
2020
// all.Wildcard().Positive(),
21-
// union(all.Wildcard().Abstain(), nilSet),
21+
// Union(all.Wildcard().Abstain(), nilSet),
2222
//
23-
// union(all.Site().Positive(), nilSet),
24-
// union(all.Site().Negative(), nilSet),
25-
// union(all.Site().Abstain(), nilSet),
23+
// Union(all.Site().Positive(), nilSet),
24+
// Union(all.Site().Negative(), nilSet),
25+
// Union(all.Site().Abstain(), nilSet),
2626
//
27-
// union(all.AllOrgs().Positive(), nilSet),
28-
// union(all.AllOrgs().Negative(), nilSet),
29-
// union(all.AllOrgs().Abstain(), nilSet),
27+
// Union(all.AllOrgs().Positive(), nilSet),
28+
// Union(all.AllOrgs().Negative(), nilSet),
29+
// Union(all.AllOrgs().Abstain(), nilSet),
3030
//
31-
// union(all.User().Positive(), nilSet),
32-
// union(all.User().Negative(), nilSet),
33-
// union(all.User().Abstain(), nilSet),
31+
// Union(all.User().Positive(), nilSet),
32+
// Union(all.User().Negative(), nilSet),
33+
// Union(all.User().Abstain(), nilSet),
3434
//)

coderd/authz/authztest/group_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ func Test_PermissionSetWPlusSearchSpace(t *testing.T) {
99
all := GroupedPermissions(AllPermissions())
1010
wplus := NewRole(
1111
all.Wildcard().Positive(),
12-
union(all.Wildcard().Abstain()[:1], nilSet),
12+
Union(all.Wildcard().Abstain()[:1], nilSet),
1313

14-
union(all.Site().Positive()[:1], nilSet),
15-
union(all.Site().Negative()[:1], nilSet),
16-
union(all.Site().Abstain()[:1], nilSet),
14+
Union(all.Site().Positive()[:1], nilSet),
15+
Union(all.Site().Negative()[:1], nilSet),
16+
Union(all.Site().Abstain()[:1], nilSet),
1717

18-
union(all.AllOrgs().Positive()[:1], nilSet),
19-
union(all.AllOrgs().Negative()[:1], nilSet),
20-
union(all.AllOrgs().Abstain()[:1], nilSet),
18+
Union(all.AllOrgs().Positive()[:1], nilSet),
19+
Union(all.AllOrgs().Negative()[:1], nilSet),
20+
Union(all.AllOrgs().Abstain()[:1], nilSet),
2121

22-
union(all.User().Positive()[:1], nilSet),
23-
union(all.User().Negative()[:1], nilSet),
24-
union(all.User().Abstain()[:1], nilSet),
22+
Union(all.User().Positive()[:1], nilSet),
23+
Union(all.User().Negative()[:1], nilSet),
24+
Union(all.User().Abstain()[:1], nilSet),
2525
)
2626
fmt.Println(wplus.N)
2727
fmt.Println(len(AllPermissions()))

coderd/authz/authztest/iterator.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import (
44
. "github.com/coder/coder/coderd/authz"
55
)
66

7-
type iterable interface {
8-
Iterator() iterator
7+
type Iterable interface {
8+
Iterator() Iterator
99
}
1010

11-
type iterator interface {
12-
iterable
11+
type Iterator interface {
12+
Iterable
1313

1414
Next() bool
1515
Permissions() Set
@@ -32,7 +32,7 @@ type unionIterator struct {
3232
N int
3333
}
3434

35-
func union(sets ...Set) *unionIterator {
35+
func Union(sets ...Set) *unionIterator {
3636
var n int
3737
for _, s := range sets {
3838
n += len(s)
@@ -76,18 +76,45 @@ func (si *unionIterator) Size() int {
7676
return si.N
7777
}
7878

79-
func (si *unionIterator) Iterator() iterator {
79+
func (si *unionIterator) Iterator() Iterator {
8080
return si
8181
}
8282

83+
type productI struct {
84+
ReturnSize int
85+
N int
86+
PermissionSets []Iterator
87+
88+
buffer Set
89+
}
90+
91+
func ProductI(sets ...Iterable) *productI {
92+
setInterfaces := make([]Iterator, 0, len(sets))
93+
var retSize int
94+
var size int = 1
95+
for _, s := range sets {
96+
v := s.Iterator()
97+
setInterfaces = append(setInterfaces, v)
98+
retSize += v.ReturnSize()
99+
// size is the cross product of all Iterator sets
100+
size *= v.Size()
101+
}
102+
return &productI{
103+
ReturnSize: retSize,
104+
N: size,
105+
PermissionSets: setInterfaces,
106+
buffer: make([]*Permission, retSize),
107+
}
108+
}
109+
83110
type productIterator struct {
84111
i, j int
85112
a Set
86113
b Set
87114
buffer Set
88115
}
89116

90-
func product(a, b Set) *productIterator {
117+
func Product(a, b Set) *productIterator {
91118
i := &productIterator{
92119
i: 0,
93120
j: 0,
@@ -128,6 +155,6 @@ func (s *productIterator) Size() int {
128155
return len(s.a) * len(s.b)
129156
}
130157

131-
func (s *productIterator) Iterator() iterator {
158+
func (s *productIterator) Iterator() Iterator {
132159
return s
133160
}

coderd/authz/authztest/level.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import "github.com/coder/coder/coderd/authz"
55
type level string
66

77
const (
8-
levelWild level = "level-wild"
9-
levelSite level = "level-site"
10-
levelOrg level = "level-org"
11-
levelOrgMem level = "level-org:mem"
12-
// levelOrgAll is a helper to get both org levels above
13-
levelOrgAll level = "level-org:*"
14-
levelUser level = "level-user"
8+
LevelWildKey level = "level-wild"
9+
LevelSiteKey level = "level-site"
10+
LevelOrgKey level = "level-org"
11+
LevelOrgMemKey level = "level-org:mem"
12+
// LevelOrgAllKey is a helper to get both org levels above
13+
LevelOrgAllKey level = "level-org:*"
14+
LevelUserKey level = "level-user"
1515
)
1616

1717
// LevelGroup is all permissions for a given level
@@ -43,7 +43,7 @@ func (lg LevelGroup) Abstain() Set {
4343

4444
func GroupedPermissions(perms Set) SetGroup {
4545
groups := make(SetGroup)
46-
allLevelKeys := []level{levelWild, levelSite, levelOrg, levelOrgMem, levelOrgAll, levelUser}
46+
allLevelKeys := []level{LevelWildKey, LevelSiteKey, LevelOrgKey, LevelOrgMemKey, LevelOrgAllKey, LevelUserKey}
4747

4848
for _, l := range allLevelKeys {
4949
groups[l] = make(LevelGroup)
@@ -53,18 +53,18 @@ func GroupedPermissions(perms Set) SetGroup {
5353
m := Impact(p)
5454
switch {
5555
case p.Level == authz.LevelSite:
56-
groups[levelSite][m] = append(groups[levelSite][m], p)
56+
groups[LevelSiteKey][m] = append(groups[LevelSiteKey][m], p)
5757
case p.Level == authz.LevelOrg:
58-
groups[levelOrgAll][m] = append(groups[levelOrgAll][m], p)
58+
groups[LevelOrgAllKey][m] = append(groups[LevelOrgAllKey][m], p)
5959
if p.LevelID == "" || p.LevelID == "*" {
60-
groups[levelOrg][m] = append(groups[levelOrg][m], p)
60+
groups[LevelOrgKey][m] = append(groups[LevelOrgKey][m], p)
6161
} else {
62-
groups[levelOrgMem][m] = append(groups[levelOrgMem][m], p)
62+
groups[LevelOrgMemKey][m] = append(groups[LevelOrgMemKey][m], p)
6363
}
6464
case p.Level == authz.LevelUser:
65-
groups[levelUser][m] = append(groups[levelUser][m], p)
65+
groups[LevelUserKey][m] = append(groups[LevelUserKey][m], p)
6666
case p.Level == authz.LevelWildcard:
67-
groups[levelWild][m] = append(groups[levelWild][m], p)
67+
groups[LevelWildKey][m] = append(groups[LevelWildKey][m], p)
6868
}
6969
}
7070

@@ -74,25 +74,25 @@ func GroupedPermissions(perms Set) SetGroup {
7474
type SetGroup map[level]LevelGroup
7575

7676
func (s SetGroup) Wildcard() LevelGroup {
77-
return s[levelWild]
77+
return s[LevelWildKey]
7878
}
7979

8080
func (s SetGroup) Site() LevelGroup {
81-
return s[levelSite]
81+
return s[LevelSiteKey]
8282
}
8383

8484
func (s SetGroup) Org() LevelGroup {
85-
return s[levelOrg]
85+
return s[LevelOrgKey]
8686
}
8787

8888
func (s SetGroup) AllOrgs() LevelGroup {
89-
return s[levelOrgAll]
89+
return s[LevelOrgAllKey]
9090
}
9191

9292
func (s SetGroup) OrgMem() LevelGroup {
93-
return s[levelOrgMem]
93+
return s[LevelOrgMemKey]
9494
}
9595

9696
func (s SetGroup) User() LevelGroup {
97-
return s[levelUser]
97+
return s[LevelUserKey]
9898
}

0 commit comments

Comments
 (0)