Search code examples
performanceoptimizationopen-policy-agentrego

How to compact and optimize open policy agent, in a single rego policy


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)
}

Solution

  • 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.