mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
feat: Convert rego queries into SQL clauses (#4225)
* feat: Convert rego queries into SQL clauses * Fix postgres quotes to single quotes * Ensure all test cases can compile into SQL clauses * Do not export extra types * Add custom query with rbac filter * First draft of a custom authorized db call * Add comments + tests * Support better regex style matching for variables * Handle jsonb arrays * Remove auth call on workspaces * Fix PG endpoints test * Match psql implementation * Add some comments * Remove unused argument * Add query name for tracking * Handle nested types This solves it without proper types in our AST. Might bite the bullet and implement some better types * Add comment * Renaming function call to GetAuthorizedWorkspaces
This commit is contained in:
92
coderd/rbac/query_internal_test.go
Normal file
92
coderd/rbac/query_internal_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCompileQuery(t *testing.T) {
|
||||
t.Parallel()
|
||||
opts := ast.ParserOptions{
|
||||
AllFutureKeywords: true,
|
||||
}
|
||||
t.Run("EmptyQuery", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
expression, err := Compile(®o.PartialQueries{
|
||||
Queries: []ast.Body{
|
||||
must(ast.ParseBody("")),
|
||||
},
|
||||
Support: []*ast.Module{},
|
||||
})
|
||||
require.NoError(t, err, "compile empty")
|
||||
|
||||
require.Equal(t, "true", expression.RegoString(), "empty query is rego 'true'")
|
||||
require.Equal(t, "true", expression.SQLString(SQLConfig{}), "empty query is sql 'true'")
|
||||
})
|
||||
|
||||
t.Run("TrueQuery", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
expression, err := Compile(®o.PartialQueries{
|
||||
Queries: []ast.Body{
|
||||
must(ast.ParseBody("true")),
|
||||
},
|
||||
Support: []*ast.Module{},
|
||||
})
|
||||
require.NoError(t, err, "compile")
|
||||
|
||||
require.Equal(t, "true", expression.RegoString(), "true query is rego 'true'")
|
||||
require.Equal(t, "true", expression.SQLString(SQLConfig{}), "true query is sql 'true'")
|
||||
})
|
||||
|
||||
t.Run("ACLIn", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
expression, err := Compile(®o.PartialQueries{
|
||||
Queries: []ast.Body{
|
||||
ast.MustParseBodyWithOpts(`"*" in input.object.acl_group_list.allUsers`, opts),
|
||||
},
|
||||
Support: []*ast.Module{},
|
||||
})
|
||||
require.NoError(t, err, "compile")
|
||||
|
||||
require.Equal(t, `internal.member_2("*", input.object.acl_group_list.allUsers)`, expression.RegoString(), "convert to internal_member")
|
||||
require.Equal(t, `group_acl->allUsers ? '*'`, expression.SQLString(DefaultConfig()), "jsonb in")
|
||||
})
|
||||
|
||||
t.Run("Complex", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
expression, err := Compile(®o.PartialQueries{
|
||||
Queries: []ast.Body{
|
||||
ast.MustParseBodyWithOpts(`input.object.org_owner != ""`, opts),
|
||||
ast.MustParseBodyWithOpts(`input.object.org_owner in {"a", "b", "c"}`, opts),
|
||||
ast.MustParseBodyWithOpts(`input.object.org_owner != ""`, opts),
|
||||
ast.MustParseBodyWithOpts(`"read" in input.object.acl_group_list.allUsers`, opts),
|
||||
ast.MustParseBodyWithOpts(`"read" in input.object.acl_user_list.me`, opts),
|
||||
},
|
||||
Support: []*ast.Module{},
|
||||
})
|
||||
require.NoError(t, err, "compile")
|
||||
require.Equal(t, `(organization_id :: text != '' OR `+
|
||||
`organization_id :: text = ANY(ARRAY ['a','b','c']) OR `+
|
||||
`organization_id :: text != '' OR `+
|
||||
`group_acl->allUsers ? 'read' OR `+
|
||||
`user_acl->me ? 'read')`,
|
||||
expression.SQLString(DefaultConfig()), "complex")
|
||||
})
|
||||
|
||||
t.Run("SetDereference", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
expression, err := Compile(®o.PartialQueries{
|
||||
Queries: []ast.Body{
|
||||
ast.MustParseBodyWithOpts(`"*" in input.object.acl_group_list[input.object.org_owner]`, opts),
|
||||
},
|
||||
Support: []*ast.Module{},
|
||||
})
|
||||
require.NoError(t, err, "compile")
|
||||
require.Equal(t, `group_acl->organization_id :: text ? '*'`,
|
||||
expression.SQLString(DefaultConfig()), "set dereference")
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user