I'm new to rego and OPA (Open Policy Agent) in general.
I'm trying to create a default policy for implementations that allow for policy overrides but in normal cases use "Policy Configuration" in a simple JSON document.
I use the input as the "Policy Configuration" and the data is the data that is to be processed by the policy. The data itself is pre-processed where "$error" is JSON elements that has been evaluated with an error.
The policy seems to work ok, but as I understand it, it must be a much easier way of expressing the same thing in rego
and hence also much more optimized (current policy is taking around 1ms to evaluate).
The playground contains the below setup to be evaluated on-line.
Cheers, Mario :)
input.json
{
"range": {"IDT**": [-100, 100], "RHCS**": [20, 200]},
"report": ["ODT", "IDT_*_O2"],
"skip": ["IDT**"]
}
data.json
{
"target": {
"IDT": 22,
"IDT_C1_O1": 22.2,
"IDT_C1_O2": 101,
"IDT_C1_O3": "$error",
"IDT_C1_O4": "$error",
"ODT": "$error",
"RHCS_C13_O44": "$error"
}
}
and the output after evaluating the cbprovider rego
policy is
{
"all_errors": [ "RHCS_C13_O44", "IDT_C1_O3", "IDT_C1_O4", "ODT", "IDT_C1_O2" ],
"report": [ "ODT", "IDT_C1_O2" ],
"skip": [ "IDT_C1_O3", "IDT_C1_O4" ]
}
package cbprovider
# Errors to be skipped
# If present in report as well it will not be skipped
# (report overrides skip)
skip[dp] {
my := data.target[dp]
my == "$error"
matchSkip(dp)
not matchReport(dp)
}
# Errors to be skipped when out of range
skip[dp] {
my := data.target[dp]
my != "$error"
matchSkip(dp)
not matchReport(dp)
range := get_range(dp)
not in_range(my, range[0], range[1])
}
# Errors to be reported
# If matches both in skip and report -> report overrides skip
report[dp] {
my := data.target[dp]
my == "$error"
matchReport(dp)
}
# Errors to be reported when out of range
report[dp] {
my := data.target[dp]
my != "$error"
matchReport(dp)
range := get_range(dp)
not in_range(my, range[0], range[1])
}
all_errors[dp] {
my := data.target[dp]
my == "$error"
}
all_errors[dp] {
my := data.target[dp]
my != "$error"
range := get_range(dp)
not in_range(my, range[0], range[1])
}
in_range(num, low, high) {
num >= low
num <= high
}
get_range(dp) = range {
some key
range := input.range[key]
glob.match(key, ["_"], dp)
}
matchSkip(dp) {
some i
input.skip[i]
glob.match(input.skip[i], ["_"], dp)
}
matchReport(dp) {
some i
input.report[i]
glob.match(input.report[i], ["_"], dp)
}
I think your policy looks fine. If you need to tune it further for performance, I'd suggest looking into shaping your data so that your policy does not need to rely on glob.match
. From casual testing it looks like that's where about half the evaluation time is currently spent.