Skip to content

Commit de198c5

Browse files
committed
Add test vectors
1 parent 87b3454 commit de198c5

File tree

1 file changed

+59
-222
lines changed

1 file changed

+59
-222
lines changed

coderd/rbac/regosql/compile_test.go

Lines changed: 59 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -12,228 +12,6 @@ import (
1212
"github.com/coder/coder/coderd/rbac/regosql/sqltypes"
1313
)
1414

15-
//func TestSomething(t *testing.T) {
16-
// ConvertRegoAst(ConvertConfig{
17-
// ConvertVariable: func(rego ast.Ref) (sqltypes.Node, error) {
18-
// return nil, fmt.Errorf("not implemented")
19-
// },
20-
// }, &rego.PartialQueries{})
21-
//}
22-
23-
//func TestPartialQueriesWithVariables(t *testing.T) {
24-
// cfg := regosql.CompileConfig{
25-
// VariableTypes: NewTree().
26-
// AddElement(strings.Split("input.post.deleted", "."), Boolean{}, StaticName("deleted")).
27-
// AddElement(strings.Split("input.post.author", "."), String{}, StaticName("author")).
28-
// AddElement(strings.Split("input.post.can", "."), String{}, StaticName("can")).
29-
// AddElement(strings.Split("input.post.authors", "."), Map{ValueType: String{}},
30-
// RegexColumnNameReplace(`input\.post\.authors\.(.*)`, "authors->$1")).
31-
// AddElement(strings.Split("input.post.posts", "."), Array{elemType: String{}}, StaticName("posts")).
32-
// AddElement(strings.Split("input.post.can_list", "."), Array{elemType: String{}}, StaticName("can_list")).
33-
// AddElement(strings.Split("input.post.list", "."), Array{elemType: String{}}, StaticName("list")).
34-
// AddElement(strings.Split("input.post.moderators", "."), Array{elemType: String{}}, StaticName("moderators")),
35-
// }
36-
// //opts := ast.ParserOptions{AllFutureKeywords: true}
37-
// testCases := []struct {
38-
// Name string
39-
// Input map[string]interface{}
40-
// Unknowns []string
41-
// Rego string
42-
// ExpectedSQL string
43-
// ExpectError bool
44-
// }{
45-
// {
46-
// Name: "AlwaysFalse",
47-
// Rego: `
48-
// package example
49-
// allow = true {
50-
// input.method = "GET"
51-
// input.path = ["posts"]
52-
// }`,
53-
// Input: map[string]interface{}{
54-
// "method": "GET",
55-
// "path": []string{"users"},
56-
// "user": "bob",
57-
// },
58-
// ExpectedSQL: "false",
59-
// Unknowns: []string{"none"},
60-
// },
61-
// {
62-
// Name: "AlwaysTrue",
63-
// Rego: `
64-
// package example
65-
// allow = true {
66-
// input.method = "GET"
67-
// input.path = ["posts"]
68-
// }`,
69-
// Input: map[string]interface{}{
70-
// "method": "GET",
71-
// "path": []string{"posts"},
72-
// "user": "bob",
73-
// },
74-
// ExpectedSQL: "true",
75-
// Unknowns: []string{"none"},
76-
// },
77-
// {
78-
// Name: "SingleObject",
79-
// // "bob" = input.post.author
80-
// Rego: `
81-
// package example
82-
// allow {
83-
// input.post.author = input.user
84-
// }
85-
// `,
86-
// Input: map[string]interface{}{
87-
// "user": "bob",
88-
// },
89-
// ExpectedSQL: "'bob' = author",
90-
// Unknowns: []string{"input.post.author"},
91-
// },
92-
// {
93-
// Name: "RefBoolean",
94-
// // input.post.deleted
95-
// Rego: `
96-
// package example
97-
// allow {
98-
// input.post.deleted
99-
// }
100-
// `,
101-
// Input: map[string]interface{}{},
102-
// ExpectedSQL: "deleted",
103-
// Unknowns: []string{"input.post.deleted"},
104-
// },
105-
// {
106-
// Name: "RefWithNumber",
107-
// // Query 0: "bob" = input.post.authors.name; "bob" = input.post.list[0]
108-
// Rego: `
109-
// package example
110-
// allow {
111-
// input.post.authors["name"] = input.user
112-
// input.post.list[0] = input.user
113-
// }
114-
// `,
115-
// Input: map[string]interface{}{
116-
// "user": "bob",
117-
// },
118-
// ExpectedSQL: "authors->>name = 'bob AND list[0] = 'bob",
119-
// Unknowns: []string{"input.post.authors", "input.post.list"},
120-
// },
121-
// {
122-
// Name: "Array",
123-
// // Query 0: "bob" = input.post.author
124-
// // Query 1: "bob" = input.post.moderators[_]
125-
// Rego: `
126-
// package example
127-
// allow {
128-
// can_edit
129-
// }
130-
//
131-
// can_edit {
132-
// input.post.author = input.user
133-
// }
134-
// can_edit {
135-
// input.post.moderators[_] = input.user
136-
// }
137-
//
138-
// `,
139-
// Input: map[string]interface{}{
140-
// "user": "bob",
141-
// },
142-
// ExpectedSQL: "'bob' = author OR 'bob' = ANY(moderators)",
143-
// Unknowns: []string{"input.post.author", "input.post.moderators"},
144-
// },
145-
// {
146-
// Name: "ArrayIntersection",
147-
// // Query 0: internal.member_2(input.can_list[_], ["edit", "*"])
148-
// // Query 1: internal.member_2(input.can, ["edit", "*"])
149-
// Rego: `
150-
// package example
151-
// import future.keywords.in
152-
// allow {
153-
// input.can in ["edit", "*"]
154-
// }
155-
//
156-
// allow {
157-
// input.can_list[_] in ["edit", "*"]
158-
// }
159-
// `,
160-
// Input: map[string]interface{}{},
161-
// // TODO: Convert vars to columns
162-
// ExpectedSQL: "input.can_list && ARRAY['edit', '*'] OR input.can = ANY(ARRAY ['edit', '*'])",
163-
// Unknowns: []string{"input.can_list", "input.can"},
164-
// },
165-
// {
166-
// Name: "EveryTerm",
167-
// // "bob" = input.posts[_].author; input.posts[_]
168-
// Rego: `
169-
// package example
170-
// allow = true {
171-
// input.method = "GET"
172-
// input.path = ["posts"]
173-
// allowed[x]
174-
// }
175-
//
176-
// allowed[x] {
177-
// x := input.posts[_]
178-
// x.author == input.user
179-
// }
180-
// `,
181-
// Input: map[string]interface{}{
182-
// "method": "GET",
183-
// "path": []string{"posts"},
184-
// "user": "bob",
185-
// },
186-
// ExpectedSQL: "true",
187-
// Unknowns: []string{"input.posts"},
188-
// },
189-
//
190-
// // Failures
191-
// {
192-
// Name: "RefString",
193-
// Rego: `
194-
// package example
195-
// allow {
196-
// input.post.author
197-
// }
198-
// `,
199-
// Input: map[string]interface{}{},
200-
// Unknowns: []string{"input.post.author"},
201-
// ExpectError: true,
202-
// },
203-
// }
204-
//
205-
// for _, tc := range testCases {
206-
// tc := tc
207-
// t.Run(tc.Name, func(t *testing.T) {
208-
// t.Parallel()
209-
// ctx := context.Background()
210-
//
211-
// part, err := rego.New(
212-
// rego.Query("data.example.allow == true"),
213-
// rego.Module("policy.rego", tc.Rego),
214-
// rego.Input(tc.Input),
215-
// rego.Unknowns(tc.Unknowns),
216-
// ).Partial(ctx)
217-
// require.NoError(t, err)
218-
//
219-
// for i, q := range part.Queries {
220-
// t.Logf("Query %d: %s", i, q.String())
221-
// }
222-
// for i, s := range part.Support {
223-
// t.Logf("Support %d: %s", i, s.String())
224-
// }
225-
//
226-
// sql, err := CompileSQL(cfg, part)
227-
// if tc.ExpectError {
228-
// require.Error(t, err)
229-
// } else {
230-
// require.NoError(t, err, "compile")
231-
// require.Equal(t, tc.ExpectedSQL, sql, "sql match")
232-
// }
233-
// })
234-
// }
235-
//}
236-
23715
// TestRegoQueriesNoVariables handles cases without variables. These should be
23816
// very simple and straight forward.
23917
func TestRegoQueries(t *testing.T) {
@@ -359,6 +137,65 @@ func TestRegoQueries(t *testing.T) {
359137
ExpectedSQL: "((false) OR (false))",
360138
VariableConverter: regosql.NoACLConverter(),
361139
},
140+
{
141+
Name: "TwoExpressions",
142+
Queries: []string{
143+
`true; true`,
144+
},
145+
// Special case where the bool is wrapped
146+
ExpectedSQL: "(true AND true)",
147+
VariableConverter: regosql.DefaultVariableConverter(),
148+
},
149+
150+
// Actual vectors from production
151+
{
152+
Name: "FromOwner",
153+
Queries: []string{
154+
``,
155+
`"05f58202-4bfc-43ce-9ba4-5ff6e0174a71" = input.object.org_owner`,
156+
`"read" in input.object.acl_user_list["d5389ccc-57a4-4b13-8c3f-31747bcdc9f1"]`,
157+
},
158+
// Special case where the bool is wrapped
159+
ExpectedSQL: "true",
160+
VariableConverter: regosql.NoACLConverter(),
161+
},
162+
{
163+
Name: "OrgAdmin",
164+
Queries: []string{
165+
`input.object.org_owner != "";
166+
input.object.org_owner in {"05f58202-4bfc-43ce-9ba4-5ff6e0174a71"};
167+
input.object.owner != "";
168+
"d5389ccc-57a4-4b13-8c3f-31747bcdc9f1" = input.object.owner`,
169+
},
170+
// Special case where the bool is wrapped
171+
ExpectedSQL: "((organization_id :: text != '') AND " +
172+
"(organization_id :: text = ANY(ARRAY ['05f58202-4bfc-43ce-9ba4-5ff6e0174a71'])) AND " +
173+
"(owner_id :: text != '') AND " +
174+
"('d5389ccc-57a4-4b13-8c3f-31747bcdc9f1' = owner_id :: text))",
175+
VariableConverter: regosql.DefaultVariableConverter(),
176+
},
177+
{
178+
Name: "UserACLAllow",
179+
Queries: []string{
180+
`"read" in input.object.acl_user_list["d5389ccc-57a4-4b13-8c3f-31747bcdc9f1"]`,
181+
`"*" in input.object.acl_user_list["d5389ccc-57a4-4b13-8c3f-31747bcdc9f1"]`,
182+
},
183+
// Special case where the bool is wrapped
184+
ExpectedSQL: "((user_acl->'d5389ccc-57a4-4b13-8c3f-31747bcdc9f1' ? 'read') OR " +
185+
"(user_acl->'d5389ccc-57a4-4b13-8c3f-31747bcdc9f1' ? '*'))",
186+
VariableConverter: regosql.DefaultVariableConverter(),
187+
},
188+
{
189+
Name: "NoACLConfig",
190+
Queries: []string{
191+
`input.object.org_owner != "";
192+
input.object.org_owner in {"05f58202-4bfc-43ce-9ba4-5ff6e0174a71"};
193+
"read" in input.object.acl_group_list[input.object.org_owner]`,
194+
},
195+
// Special case where the bool is wrapped
196+
ExpectedSQL: "((organization_id :: text != '') AND (organization_id :: text = ANY(ARRAY ['05f58202-4bfc-43ce-9ba4-5ff6e0174a71'])) AND (false))",
197+
VariableConverter: regosql.NoACLConverter(),
198+
},
362199
}
363200

364201
for _, tc := range testCases {

0 commit comments

Comments
 (0)