Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
topdown+rego+server: allow opt-in for evaluating non-det builtins in …
…PE (#7313) * topdown+rego: allow opt-in for evaluating non-det builtins in PE Some use cases of PE, notably generating queries that are to be translated into filters of some sort (think SQL), require the evaluation of non-deterministic builtins. This is because the result of the builtin informs what queries are returned. Imagine that the user associated with a request is known at PE-time, but we need extra information from an HTTP API to determine the filters that should be applied. Previously, that was just impossible to do. Now, we can opt-in to evaluate non-det builtins during PE from the Rego API. Note that it would probably make sense to include this in the inlining controls, as sent to the Compile API. (Considered out of scope for this PR.) Also note that this will take highest precedence over the `ast.IgnoreDuringPartialEval` map and the "Nondeterministic" value of the registered builtin. If the new option is provided, both of these are ignored. Signed-off-by: Stephan Renatus <[email protected]> * server+rego: expose nondeterministicBuiltins via inlining controls With `foo.rego` as ```rego package ex include if input.fruits.name == object.get(http.send(input.req).body, input.path, "unknown") ``` the following queries show the difference: ```interactive $ curl -v http://127.0.0.1:8181/v1/compile \ -d '{"input": {"req": {"url": "https://httpbin.org/json", "method":"GET"}, "path": ["slideshow", "title"]}, "query": "data.ex.include", "unknowns": ["input.fruits"]}' { "result": { "queries": [ [ { "index": 0, "terms": [ { "type": "ref", "value": [ { "type": "var", "value": "http" }, { "type": "string", "value": "send" } ] }, { "type": "object", "value": [ [ { "type": "string", "value": "method" }, { "type": "string", "value": "GET" } ], [ { "type": "string", "value": "url" }, { "type": "string", "value": "https://httpbin.org/json" } ] ] }, { "type": "var", "value": "__local0__1" } ] }, { "index": 1, "terms": [ { "type": "ref", "value": [ { "type": "var", "value": "eq" } ] }, { "type": "ref", "value": [ { "type": "var", "value": "input" }, { "type": "string", "value": "fruits" }, { "type": "string", "value": "name" } ] }, { "type": "call", "value": [ { "type": "ref", "value": [ { "type": "var", "value": "object" }, { "type": "string", "value": "get" } ] }, { "type": "ref", "value": [ { "type": "var", "value": "__local0__1" }, { "type": "string", "value": "body" } ] }, { "type": "array", "value": [ { "type": "string", "value": "slideshow" }, { "type": "string", "value": "title" } ] }, { "type": "string", "value": "unknown" } ] } ] } ] ] } } ``` Here, the builtin call to http.send is preserved. If we also pass `nondeterminsticBuiltins: true` to the options, we get this: ```interactive $ curl http://127.0.0.1:8181/v1/compile \ -d '{"input": {"req": {"url": "https://httpbin.org/json", "method":"GET"}, "path": ["slideshow", "title"]}, "query": "data.ex.include", "unknowns": ["input.fruits"], "options": {"nondeterministicBuiltins": true}}' { "result": { "queries": [ [ { "index": 0, "terms": [ { "type": "ref", "value": [ { "type": "var", "value": "eq" } ] }, { "type": "ref", "value": [ { "type": "var", "value": "input" }, { "type": "string", "value": "fruits" }, { "type": "string", "value": "name" } ] }, { "type": "string", "value": "Sample Slide Show" } ] } ] ] } } ``` Here, all args to http.send have been known at PE time and the call was fully evaluated. Signed-off-by: Stephan Renatus <[email protected]> * cmd/eval: expose --nondeterminstic-builtins for new PE control ```interactive $ echo '{"req": {"url": "https://httpbin.org/json", "method":"GET"}, "path": ["slideshow", "title"]}'| ./opa_darwin_amd64 eval -fpretty -p -I -d foo.rego -u input.fruits data.ex.include +---------+-------------------------------------------------------------------------------------+ | Query 1 | http.send({"method": "GET", "url": "https://httpbin.org/json"}, __local0__1) | | | input.fruits.name = object.get(__local0__1.body, ["slideshow", "title"], "unknown") | +---------+-------------------------------------------------------------------------------------+ $ echo '{"req": {"url": "https://httpbin.org/json", "method":"GET"}, "path": ["slideshow", "title"]}'| ./opa_darwin_amd64 eval -fpretty -p -I -d foo.rego -u input.fruits data.ex.include --nondeterminstic-builtins +---------+-----------------------------------------+ | Query 1 | input.fruits.name = "Sample Slide Show" | +---------+-----------------------------------------+ ``` Signed-off-by: Stephan Renatus <[email protected]> --------- Signed-off-by: Stephan Renatus <[email protected]>
- Loading branch information