In the documentation of OPA there are a lot of examples for generating sets/arrays/objects for querying, e.g.:
app_to_hostnames[app_name] = hostnames {
app := apps[_]
app_name := app.name
hostnames := [hostname | name := app.servers[_]
s := sites[_].servers[_]
s.name == name
hostname := s.hostname]
}
However, in the documentation, all data is statically defined: in the example the variables apps
already exists and is defined as some json object.
For reusability I would like to define a function that returns a set/array/object but allows for the input to be passed dynamically. In essence what I want to try to do is the following:
app_to_hostnames[app_name](apps) = hostnames {
app := apps[_]
app_name := app.name
hostnames := [hostname | name := app.servers[_]
s := sites[_].servers[_]
s.name == name
hostname := s.hostname]
}
Where in this case apps is passed as a function input. Is there a way to achieve this in Rego policies? Or should I approach the problem in a different way? Or is there a way to pass different inputs to different policies?
I know you could send the input via the REST API to a specific policy and control it that way, but in this case I am using conftest which passes the input document (for example a json file) to a compiled set of rego policies) via the terminal so using the REST API won't work for me.
The input
and data
documents are global. You can always replace their values on a given expression using the with
keyword but sometimes it's more natural to wrap the logic in a function.
That specific example can be rewritten using a comprehension:
app_to_hostnames(apps, sites) = {app_name: hostnames |
app := apps[_]
app_name := app.name
hostnames := [hostname | name := app.servers[_]
s := sites[_].servers[_]
s.name == name
hostname := s.hostname]
}
Alternatively you can use the with
keyword to temporarily replace portions of the data
or input
documents. For example, if apps
, sites
were imported from under data in the file containing app_to_hostnames
you could query app_to_hostnames
as follows:
mock_apps := [
{"name": "foo", "servers": ["s1"]},
{"name": "bar", "servers": ["s2", "s3"]},
]
mock_sites := [
{"servers": [{"name": "s1", "hostname": "x.com"}]},
{"servers": [{"name": "s2", "hostname": "y.com"}, {"name": "s3", "hostname": "z.com"}]},
]
app_to_hostnames == {"foo": ["x.com"], "bar": ["y.com", "z.com"]} with data.apps as mock_apps with data.sites as mock_sites
Here's a link to the policy inside the playground: https://play.openpolicyagent.org/p/pEp6BLCtgn