Files
coder/coderd/rbac/query_internal_test.go
Steven Masley cd4ab97efa 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
2022-10-04 11:35:33 -04:00

93 lines
2.9 KiB
Go

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(&rego.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(&rego.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(&rego.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(&rego.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(&rego.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")
})
}