mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
ast: Respecting capabilities built-ins for rego.metadata.* functions (#4581)
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
This commit is contained in:
+11
-8
@@ -1771,6 +1771,9 @@ func (c *Compiler) parseMetadataBlocks() {
|
||||
func (c *Compiler) rewriteRegoMetadataCalls() {
|
||||
eqFactory := newEqualityFactory(c.localvargen)
|
||||
|
||||
_, chainFuncAllowed := c.builtins[RegoMetadataChain.Name]
|
||||
_, ruleFuncAllowed := c.builtins[RegoMetadataRule.Name]
|
||||
|
||||
for _, name := range c.sorted {
|
||||
mod := c.Modules[name]
|
||||
|
||||
@@ -1779,9 +1782,9 @@ func (c *Compiler) rewriteRegoMetadataCalls() {
|
||||
var ruleCalled bool
|
||||
|
||||
WalkExprs(rule, func(expr *Expr) bool {
|
||||
if isRegoMetadataChainCall(expr) {
|
||||
if chainFuncAllowed && isRegoMetadataChainCall(expr) {
|
||||
chainCalled = true
|
||||
} else if isRegoMetadataRuleCall(expr) {
|
||||
} else if ruleFuncAllowed && isRegoMetadataRuleCall(expr) {
|
||||
ruleCalled = true
|
||||
}
|
||||
return chainCalled && ruleCalled
|
||||
@@ -1835,7 +1838,7 @@ func (c *Compiler) rewriteRegoMetadataCalls() {
|
||||
rule.Body = body
|
||||
|
||||
vis := func(b Body) bool {
|
||||
for _, err := range rewriteRegoMetadataCalls(metadataChainVar, metadataRuleVar, b, &c.RewrittenVars) {
|
||||
for _, err := range rewriteRegoMetadataCalls(&metadataChainVar, &metadataRuleVar, b, &c.RewrittenVars) {
|
||||
c.err(err)
|
||||
}
|
||||
return false
|
||||
@@ -1864,7 +1867,7 @@ func getPrimaryRuleAnnotations(as *AnnotationSet, rule *Rule) *Annotations {
|
||||
return annots[0]
|
||||
}
|
||||
|
||||
func rewriteRegoMetadataCalls(metadataChainVar Var, metadataRuleVar Var, body Body, rewrittenVars *map[Var]Var) Errors {
|
||||
func rewriteRegoMetadataCalls(metadataChainVar *Var, metadataRuleVar *Var, body Body, rewrittenVars *map[Var]Var) Errors {
|
||||
var errs Errors
|
||||
|
||||
WalkClosures(body, func(x interface{}) bool {
|
||||
@@ -1885,10 +1888,10 @@ func rewriteRegoMetadataCalls(metadataChainVar Var, metadataRuleVar Var, body Bo
|
||||
expr := body[i]
|
||||
var metadataVar Var
|
||||
|
||||
if isRegoMetadataChainCall(expr) {
|
||||
metadataVar = metadataChainVar
|
||||
} else if isRegoMetadataRuleCall(expr) {
|
||||
metadataVar = metadataRuleVar
|
||||
if metadataChainVar != nil && isRegoMetadataChainCall(expr) {
|
||||
metadataVar = *metadataChainVar
|
||||
} else if metadataRuleVar != nil && isRegoMetadataRuleCall(expr) {
|
||||
metadataVar = *metadataRuleVar
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -500,6 +500,80 @@ func TestEvalWithSchemaFileWithRemoteRef(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuiltinsCapabilities(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
policy string
|
||||
query string
|
||||
ruleName string
|
||||
expectedCode string
|
||||
expectedMessage string
|
||||
}{
|
||||
{
|
||||
note: "rego.metadata.chain() not allowed",
|
||||
policy: "package p\n r := rego.metadata.chain()",
|
||||
query: "data.p",
|
||||
ruleName: "rego.metadata.chain",
|
||||
expectedCode: "rego_type_error",
|
||||
expectedMessage: "undefined function rego.metadata.chain",
|
||||
},
|
||||
{
|
||||
note: "rego.metadata.rule() not allowed",
|
||||
policy: "package p\n r := rego.metadata.rule()",
|
||||
query: "data.p",
|
||||
ruleName: "rego.metadata.rule",
|
||||
expectedCode: "rego_type_error",
|
||||
expectedMessage: "undefined function rego.metadata.rule",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
|
||||
files := map[string]string{
|
||||
"p.rego": tc.policy,
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(path string) {
|
||||
params := newEvalCommandParams()
|
||||
params.capabilities.C = ast.CapabilitiesForThisVersion()
|
||||
params.capabilities.C.Builtins = removeBuiltin(params.capabilities.C.Builtins, tc.ruleName)
|
||||
|
||||
_ = params.dataPaths.Set(filepath.Join(path, "p.rego"))
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err := eval([]string{tc.query}, params, &buf)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if exp, act := 1, len(output.Errors); exp != act {
|
||||
t.Fatalf("expected %d errors, got %d", exp, act)
|
||||
}
|
||||
if code := output.Errors[0].Code; code != tc.expectedCode {
|
||||
t.Errorf("expected code '%v', got '%v'", tc.expectedCode, code)
|
||||
}
|
||||
if msg := output.Errors[0].Message; msg != tc.expectedMessage {
|
||||
t.Errorf("expected message '%v', got '%v'", tc.expectedMessage, msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func removeBuiltin(builtins []*ast.Builtin, name string) []*ast.Builtin {
|
||||
var cpy []*ast.Builtin
|
||||
for _, builtin := range builtins {
|
||||
if builtin.Name != name {
|
||||
cpy = append(cpy, builtin)
|
||||
}
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
func TestEvalReturnsRegoError(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := eval([]string{`{k: v | k = ["a", "a"][_]; v = [0,1][_]}`}, newEvalCommandParams(), buf)
|
||||
|
||||
Reference in New Issue
Block a user