-
Notifications
You must be signed in to change notification settings - Fork 930
chore: Rewrite rbac rego -> SQL clause #5138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
d8fce5e
chore: Rewrite rbac rego -> SQL clause
Emyrk 4b2e99f
Begin removing all old code
Emyrk 6c89f1d
Add unit tests for equality and membership
Emyrk 300dc4c
fixup! Add unit tests for equality and membership
Emyrk 87b3454
Rework arguments
Emyrk de198c5
Add test vectors
Emyrk b9b1c4e
Handle empty arrays
Emyrk a0790b0
test: Add unit test verifying acl behavior against all normal cases.
Emyrk 618904e
Implement AlwaysFalsE
Emyrk 5de395a
Make filter ignore owner, not org
Emyrk e6696cc
Add comment
Emyrk 1f37ca1
Cleanup some code
Emyrk 203bc7c
Cleanup and comments
Emyrk f0fce00
Linting
Emyrk a000c15
errors.New -> xerrors.fmt
Emyrk a521616
More linting
Emyrk cbb219b
Handle fakeDB for authorize test
Emyrk f8453af
Add comment
Emyrk 7e1f482
Trying to make the linter happy
Emyrk 7b1231a
Add exempt method
Emyrk 5333401
Merge remote-tracking branch 'origin/main' into stevenmasley/rego_to_…
Emyrk aae858e
Fix merge with master: Add template fields
Emyrk 38e9fde
Add defensive programming checks
Emyrk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next
Next commit
chore: Rewrite rbac rego -> SQL clause
Previous code was challenging to read with edge cases
- Loading branch information
commit d8fce5e85eb014f689d628fed08404bcd5ae1b0f
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package regosql | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/open-policy-agent/opa/ast" | ||
|
||
"github.com/coder/coder/coderd/rbac/regosql/sqltypes" | ||
) | ||
|
||
var _ sqltypes.VariableMatcher = ACLGroupVar{} | ||
|
||
// ACLGroupVar is also the Node type to reduce the number of types that we need | ||
// to export. | ||
var _ sqltypes.Node = ACLGroupVar{} | ||
|
||
// ACLGroupVar is a variable matcher that handles group_acl and user_acl. | ||
// The sql type is a jsonb object with the following structure: | ||
// | ||
// "group_acl": { | ||
// "<group_name>": ["<actions>"] | ||
// } | ||
// | ||
// This is a custom variable matcher as json objects have arbitrary complexity. | ||
type ACLGroupVar struct { | ||
StructSQL string | ||
StructPath []string | ||
// DenyAll is helpful for when we don't care about ACL groups. | ||
// We need to default to denying access. | ||
DenyAll bool | ||
|
||
// FieldReference handles referencing the subfields, which could be | ||
// more variables. We pass one in as the global one might not be correctly | ||
// scoped. | ||
FieldReference sqltypes.VariableMatcher | ||
|
||
// Instance fields | ||
Source sqltypes.RegoSource | ||
GroupNode sqltypes.Node | ||
} | ||
|
||
func ACLGroupMatcher(fieldRefernce sqltypes.VariableMatcher, structSQL string, structPath []string) ACLGroupVar { | ||
return ACLGroupVar{StructSQL: structSQL, StructPath: structPath, FieldReference: fieldRefernce} | ||
} | ||
|
||
func (ACLGroupVar) UseAs() sqltypes.Node { return ACLGroupVar{} } | ||
|
||
// Disable is a helper to disable the ACL group matching in the SQL generation. | ||
// This is because some tables do not have ACL columns, and in this case we | ||
// do not want to grant access based on columns that do not exist. | ||
// This replaces any clause with "group_acl" or "user_acl" with "false". | ||
func (g *ACLGroupVar) Disable() *ACLGroupVar { | ||
g.DenyAll = true | ||
return g | ||
} | ||
|
||
func (g ACLGroupVar) ConvertVariable(rego ast.Ref) (sqltypes.Node, bool) { | ||
// "left" will be a map of group names to actions in rego. | ||
// { | ||
// "all_users": ["read"] | ||
// } | ||
left, err := sqltypes.RegoVarPath(g.StructPath, rego) | ||
if err != nil { | ||
return nil, false | ||
} | ||
|
||
aclGrp := ACLGroupVar{ | ||
DenyAll: g.DenyAll, | ||
StructSQL: g.StructSQL, | ||
StructPath: g.StructPath, | ||
FieldReference: g.FieldReference, | ||
|
||
Source: sqltypes.RegoSource(rego.String()), | ||
} | ||
|
||
// We expect 1 more term. Either a ref or a string. | ||
if len(left) != 1 { | ||
return nil, false | ||
} | ||
|
||
// If the remaining is a variable, then we need to convert it. | ||
// Assuming we support variable fields. | ||
ref, ok := left[0].Value.(ast.Ref) | ||
if ok && g.FieldReference != nil { | ||
groupNode, ok := g.FieldReference.ConvertVariable(ref) | ||
if ok { | ||
aclGrp.GroupNode = groupNode | ||
return aclGrp, true | ||
} | ||
} | ||
|
||
// If it is a string, we assume it is a literal | ||
groupName, ok := left[0].Value.(ast.String) | ||
if ok { | ||
aclGrp.GroupNode = sqltypes.String(string(groupName)) | ||
return aclGrp, true | ||
} | ||
|
||
// If we have not matched it yet, then it is something we do not recognize. | ||
return nil, false | ||
} | ||
|
||
func (g ACLGroupVar) SQLString(cfg *sqltypes.SQLGenerator) string { | ||
if g.DenyAll { | ||
return "false" | ||
} | ||
return fmt.Sprintf("%s->%s", g.StructSQL, g.GroupNode.SQLString(cfg)) | ||
} | ||
|
||
func (g ACLGroupVar) ContainsSQL(cfg *sqltypes.SQLGenerator, other sqltypes.Node) (string, error) { | ||
if g.DenyAll { | ||
return "false", nil | ||
} | ||
|
||
switch other.UseAs().(type) { | ||
// Only supports containing other strings. | ||
case sqltypes.AstString: | ||
return fmt.Sprintf("%s ? %s", g.SQLString(cfg), other.SQLString(cfg)), nil | ||
} | ||
|
||
return "", fmt.Errorf("unsupported acl group contains %T", other) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.