Skip to content

Commit ab61328

Browse files
Emyrkjohnstcn
authored andcommitted
WIP: This is a massive WIP
Just testing out some ideas. The code is far from finished, and very sloppy. Committing to share it to start conversations
1 parent f5757ff commit ab61328

File tree

7 files changed

+616
-0
lines changed

7 files changed

+616
-0
lines changed

coderd/authz/authztest/iterator.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package authztest
2+
3+
type iterable interface {
4+
Iterator() iterator
5+
}
6+
7+
type iterator interface {
8+
iterable
9+
10+
Next() bool
11+
Permissions() Set
12+
Reset()
13+
ReturnSize() int
14+
Size() int
15+
}
16+
17+
// SetIterator is very primitive, just used to hold a place in a set.
18+
type SetIterator struct {
19+
i int
20+
set Set
21+
}
22+
23+
func union(sets ...Set) *SetIterator {
24+
all := Set{}
25+
for _, set := range sets {
26+
all = append(all, set...)
27+
}
28+
return &SetIterator{
29+
i: 0,
30+
set: all,
31+
}
32+
}
33+
34+
func (si *SetIterator) Next() bool {
35+
si.i++
36+
return si.i < len(si.set)
37+
}
38+
39+
func (si *SetIterator) Permissions() Set {
40+
return Set{si.set[si.i]}
41+
}
42+
43+
func (si *SetIterator) Permission() *Permission {
44+
return si.set[si.i]
45+
}
46+
47+
func (si *SetIterator) Reset() {
48+
si.i = 0
49+
}
50+
51+
func (si *SetIterator) ReturnSize() int {
52+
return 1
53+
}
54+
55+
func (si *SetIterator) Size() int {
56+
return len(si.set)
57+
}
58+
59+
func (si *SetIterator) Iterator() iterator {
60+
return si
61+
}
62+
63+
type productIterator struct {
64+
i, j int
65+
a Set
66+
b Set
67+
}
68+
69+
func product(a, b Set) *productIterator {
70+
return &productIterator{
71+
i: 0,
72+
j: 0,
73+
a: a,
74+
b: b,
75+
}
76+
}
77+
78+
func (s *productIterator) Next() bool {
79+
s.i++
80+
if s.i >= len(s.a) {
81+
s.i = 0
82+
s.j++
83+
}
84+
if s.j >= len(s.b) {
85+
return false
86+
}
87+
return true
88+
}
89+
90+
func (s productIterator) Permissions() Set {
91+
return Set{s.a[s.i], s.b[s.j]}
92+
}
93+
94+
func (s *productIterator) Reset() {
95+
s.i, s.j = 0, 0
96+
}
97+
98+
func (s *productIterator) ReturnSize() int {
99+
return 2
100+
}
101+
102+
func (s *productIterator) Size() int {
103+
return len(s.a) * len(s.b)
104+
}
105+
106+
func (s *productIterator) Iterator() iterator {
107+
return s
108+
}

coderd/authz/authztest/parser.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package authztest
2+
3+
import "fmt"
4+
5+
type Parser struct {
6+
input string
7+
stack []interface{}
8+
grp setGroup
9+
10+
setI []iterable
11+
}
12+
13+
func ParseRole(grp setGroup, input string) *Role {
14+
p := NewParser(grp, input)
15+
p.parse()
16+
return NewRole(p.setI...)
17+
}
18+
19+
func Parse(grp setGroup, input string) []iterable {
20+
p := NewParser(grp, input)
21+
p.parse()
22+
return p.setI
23+
}
24+
25+
func NewParser(grp setGroup, input string) *Parser {
26+
27+
return &Parser{
28+
grp: grp,
29+
input: input,
30+
stack: make([]interface{}, 0),
31+
}
32+
}
33+
34+
func (p *Parser) skipSpace(ptr int) int {
35+
for ptr < len(p.input) {
36+
r := p.input[ptr]
37+
switch r {
38+
case ' ', '\t', '\n':
39+
ptr++
40+
default:
41+
return ptr
42+
}
43+
}
44+
return ptr
45+
}
46+
47+
func (p *Parser) parse() {
48+
ptr := 0
49+
for ptr < len(p.input) {
50+
ptr = p.skipSpace(ptr)
51+
r := p.input[ptr]
52+
switch r {
53+
case ' ':
54+
ptr++
55+
case 'w', 's', 'o', 'm', 'u':
56+
// Time to look ahead for the grp
57+
ptr++
58+
ptr = p.handleLevel(r, ptr)
59+
default:
60+
panic(fmt.Errorf("cannot handle '%c' at %d", r, ptr))
61+
}
62+
}
63+
}
64+
65+
func (p *Parser) handleLevel(l uint8, ptr int) int {
66+
var lg LevelGroup
67+
switch l {
68+
case 'w':
69+
lg = p.grp.Wildcard()
70+
case 's':
71+
lg = p.grp.Site()
72+
case 'o':
73+
lg = p.grp.AllOrgs()
74+
case 'm':
75+
lg = p.grp.OrgMem()
76+
case 'u':
77+
lg = p.grp.User()
78+
}
79+
80+
// time to look ahead. Find the parenthesis
81+
var sets []Set
82+
var start bool
83+
var stop bool
84+
for {
85+
ptr = p.skipSpace(ptr)
86+
r := p.input[ptr]
87+
if r != '(' && !start {
88+
panic(fmt.Sprintf("Expect a parenthesis at %d", ptr))
89+
}
90+
switch r {
91+
case '(':
92+
start = true
93+
case ')':
94+
stop = true
95+
case 'p':
96+
sets = append(sets, lg.Positive())
97+
case 'n':
98+
sets = append(sets, lg.Negative())
99+
case 'a':
100+
sets = append(sets, lg.Abstain())
101+
case '*':
102+
sets = append(sets, lg.All())
103+
case 'e':
104+
// Add the empty perm
105+
sets = append(sets, Set{nil})
106+
default:
107+
panic(fmt.Errorf("unsupported '%c' for level set", r))
108+
}
109+
ptr++
110+
if stop {
111+
p.setI = append(p.setI, union(sets...))
112+
return ptr
113+
}
114+
}
115+
}
116+
117+
//func (p *Parser)

0 commit comments

Comments
 (0)