Skip to content

Commit a9b7704

Browse files
committed
feat: implement proper sql filter for users query
1 parent 5802921 commit a9b7704

File tree

7 files changed

+71
-34
lines changed

7 files changed

+71
-34
lines changed

coderd/database/dbmetrics/dbmetrics.go

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/users.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ WHERE
209209
END
210210
-- End of filters
211211

212+
-- Authorize Filter clause will be injected below in GetAuthorizedUserCount
213+
-- @authorize_filter
212214
ORDER BY
213215
-- Deterministic and consistent ordering of all users. This is to ensure consistent pagination.
214216
LOWER(username) ASC OFFSET @offset_opt

coderd/rbac/input.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
{
2-
"action": "never-match-action",
2+
"action": "read",
33
"object": {
44
"id": "9046b041-58ed-47a3-9c3a-de302577875a",
5-
"owner": "00000000-0000-0000-0000-000000000000",
6-
"org_owner": "bf7b72bd-a2b1-4ef2-962c-1d698e0483f6",
7-
"type": "workspace",
5+
"owner": "9046b041-58ed-47a3-9c3a-de302577875a",
6+
"org_owner": "00000000-0000-0000-0000-000000000000",
7+
"type": "user",
88
"acl_user_list": {
9-
"f041847d-711b-40da-a89a-ede39f70dc7f": ["create"]
109
},
1110
"acl_group_list": {}
1211
},
1312
"subject": {
1413
"id": "10d03e62-7703-4df5-a358-4f76577d4e2f",
1514
"roles": [
1615
{
17-
"name": "owner",
18-
"display_name": "Owner",
16+
"name": "member",
17+
"display_name": "Member",
1918
"site": [
19+
],
20+
"org": {},
21+
"user": [
2022
{
2123
"negate": false,
22-
"resource_type": "*",
23-
"action": "*"
24+
"resource_type": "user",
25+
"action": "read"
2426
}
25-
],
26-
"org": {},
27-
"user": []
27+
]
2828
}
2929
],
30-
"groups": ["b617a647-b5d0-4cbe-9e40-26f89710bf18"],
30+
"groups": [],
3131
"scope": {
3232
"name": "Scope_all",
3333
"display_name": "All operations",

coderd/rbac/regosql/compile_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,26 @@ neq(input.object.owner, "");
242242
p("false")),
243243
VariableConverter: regosql.TemplateConverter(),
244244
},
245+
{
246+
Name: "UserNoOrgOwner",
247+
Queries: []string{
248+
`input.object.org_owner != ""`,
249+
},
250+
ExpectedSQL: p("'' != ''"),
251+
VariableConverter: regosql.UserConverter(),
252+
},
253+
{
254+
Name: "UserOwnsSelf",
255+
Queries: []string{
256+
`"10d03e62-7703-4df5-a358-4f76577d4e2f" = input.object.owner;
257+
input.object.owner != "";
258+
input.object.org_owner = ""`,
259+
},
260+
VariableConverter: regosql.UserConverter(),
261+
ExpectedSQL: p(
262+
p("'10d03e62-7703-4df5-a358-4f76577d4e2f' = id :: text") + " AND " + p("id :: text != ''") + " AND " + p("'' = ''"),
263+
),
264+
},
245265
}
246266

247267
for _, tc := range testCases {

coderd/rbac/regosql/configs.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ func userACLMatcher(m sqltypes.VariableMatcher) sqltypes.VariableMatcher {
2525
func UserConverter() *sqltypes.VariableConverter {
2626
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
2727
resourceIDMatcher(),
28-
// Users are never owned by an organization.
29-
sqltypes.AlwaysFalse(organizationOwnerMatcher()),
28+
// Users are never owned by an organization, so always return the empty string
29+
// for the org owner.
30+
sqltypes.StringVarMatcher("''", []string{"input", "object", "org_owner"}),
3031
// Users are always owned by themselves.
3132
sqltypes.StringVarMatcher("id :: text", []string{"input", "object", "owner"}),
3233
)
Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,77 @@
11
package sqltypes
22

33
import (
4+
"strconv"
5+
46
"github.com/open-policy-agent/opa/ast"
57
)
68

79
var (
8-
_ Node = alwaysFalse{}
9-
_ VariableMatcher = alwaysFalse{}
10+
_ Node = constBoolean{}
11+
_ VariableMatcher = constBoolean{}
1012
)
1113

12-
type alwaysFalse struct {
13-
Matcher VariableMatcher
14+
type constBoolean struct {
15+
Matcher VariableMatcher
16+
constant bool
1417

1518
InnerNode Node
1619
}
1720

1821
// AlwaysFalse overrides the inner node with a constant "false".
1922
func AlwaysFalse(m VariableMatcher) VariableMatcher {
20-
return alwaysFalse{
21-
Matcher: m,
23+
return constBoolean{
24+
Matcher: m,
25+
constant: false,
26+
}
27+
}
28+
29+
func AlwaysTrue(m VariableMatcher) VariableMatcher {
30+
return constBoolean{
31+
Matcher: m,
32+
constant: true,
2233
}
2334
}
2435

2536
// AlwaysFalseNode is mainly used for unit testing to make a Node immediately.
2637
func AlwaysFalseNode(n Node) Node {
27-
return alwaysFalse{
38+
return constBoolean{
2839
InnerNode: n,
2940
Matcher: nil,
41+
constant: false,
3042
}
3143
}
3244

3345
// UseAs uses a type no one supports to always override with false.
34-
func (alwaysFalse) UseAs() Node { return alwaysFalse{} }
46+
func (constBoolean) UseAs() Node { return constBoolean{} }
3547

36-
func (f alwaysFalse) ConvertVariable(rego ast.Ref) (Node, bool) {
48+
func (f constBoolean) ConvertVariable(rego ast.Ref) (Node, bool) {
3749
if f.Matcher != nil {
3850
n, ok := f.Matcher.ConvertVariable(rego)
3951
if ok {
40-
return alwaysFalse{
52+
return constBoolean{
4153
Matcher: f.Matcher,
4254
InnerNode: n,
55+
constant: f.constant,
4356
}, true
4457
}
4558
}
4659

4760
return nil, false
4861
}
4962

50-
func (alwaysFalse) SQLString(_ *SQLGenerator) string {
51-
return "false"
63+
func (c constBoolean) SQLString(_ *SQLGenerator) string {
64+
return strconv.FormatBool(c.constant)
5265
}
5366

54-
func (alwaysFalse) ContainsSQL(_ *SQLGenerator, _ Node) (string, error) {
55-
return "false", nil
67+
func (c constBoolean) ContainsSQL(_ *SQLGenerator, _ Node) (string, error) {
68+
return strconv.FormatBool(c.constant), nil
5669
}
5770

58-
func (alwaysFalse) ContainedInSQL(_ *SQLGenerator, _ Node) (string, error) {
59-
return "false", nil
71+
func (c constBoolean) ContainedInSQL(_ *SQLGenerator, _ Node) (string, error) {
72+
return strconv.FormatBool(c.constant), nil
6073
}
6174

62-
func (alwaysFalse) EqualsSQLString(_ *SQLGenerator, _ bool, _ Node) (string, error) {
63-
return "false", nil
75+
func (c constBoolean) EqualsSQLString(_ *SQLGenerator, _ bool, _ Node) (string, error) {
76+
return strconv.FormatBool(c.constant), nil
6477
}

0 commit comments

Comments
 (0)