Add new built-in function to query for metadata at provided ref
Metadata annotations provides many benefits for separating a policy project's metadata from its policy logic. This separation however comes with a cost, as we'll need to duplicate parts of metadata into data accessible in Rego. We need to do this since the capabilities to query metadata from inside of Rego are limited to metadata pertaining to the rule it's queried from (including the chain from which it inherits metadata). Having a built-in function that's able to query for metadata at any location, sort of like object.get but for metadata, would unlock a whole bunch of interesting things, like:
- Dynamic policy composition, where metadata determines the rules to evaluate.
- Including metadata attributes in returned decisions, like the common "reasons" seen in responses.
- Using metadata like severity levels as part of policy decisions.
- "Introspection" capabilities to e.g. generate docs or other things from metadata directly from Rego.
@anderseknert technically you could use rego.metadata.chain() which was a little difficult to find but is documented here.
This shows the path ancestry including paths and all annotations.
Here is a playground example of how you could use it. Not the most robust solution, but you could add some field validation as well. Great for Dynamic policy composition.
Thanks @aalsabag! The rego.metadata.chain function however works only to obtain the chain of metadata for the rule from which it is called. What's being requested here is getting the metadata from another rule or package. Simple example:
package p
foo := rego.metadata.get(["data", "p", "bar"])
# METADATA
# description: this is bar
bar {
# ...
}
Yup! Which is why I too would love this feature. Thanks for raising the issue @anderseknert . So the way I'm getting around that now is by creating a function in each policy file that returns the metadata. I even have a helper/util function to extract what I need. Not the prettiest of solutions, but it's gotten the job done for now and is going to be easy to refactor once this feature comes in. Util Function:
package utils.metadata
policy_metadata(chain) := {
"policy": chain[1].annotations.title,
"version": chain[1].annotations.custom.version,
}
Call in each policy:
package policies.abc
import data.utils.metadata
policy_metadata contains msg if {
msg := metadata.policy_metadata(rego.metadata.chain())
}