Search code examples
open-policy-agent

OR in Open Policy Agent (union behavior)


In OPA it's clear how to query against condition AND condition:

values := {
  "value1": {
    "a": "one"
  },
  "value2": {
    "a": "one",
    "b": "two"
  },
  "value3": {
    "a": "one",
    "b": "one"
  }
}

goodValues = [name |
  value = values[name]
  value.a == "one"
  value.b == "one"
]

So that goodValues here will contain value3 only.

But how to query condition OR condition, so that goodValues will contain all 3 values, because they have either value.a == "one" OR value.b == "one"?


Solution

  • Joining multiple expressions together expresses logical AND. To express logical OR you define multiple rules or functions with the same name. There are a couple different ways this can work. This is covered in the introduction to OPA: https://www.openpolicyagent.org/docs/latest/#logical-or.

    Option 1: Comprehensions & Functions

    The conditions that you want to express against the value can be factored into helper functions and then the comprehension query can refer to the function.

    goodValues = [name |
      value := values[name]
      value_match(value)
    ]
    
    value_match(v) {
      v.a == "one"
    }
    
    value_match(v) {
      v.b = "two"
    }
    

    Option 2: Incremental Rules

    In OPA/Rego, incremental rules assign a set of values to a variable. The rule definition provides the logic to generate the set values. Unlike comprehensions, you can overload the rule definition (providing multiple with the same name) and express logical OR like the other answer explains.

    # goodValues is a set that contains 'name' if...
    goodValues[name] {
     value := values[name]  # name is in values
     value.a == "one"       # value.a is "one"
    }
    
    # goodvalues is a set that contains 'name' if...
    goodValues[name] {
      value := values[name]  # name is in values
      value.b == "two"       # value.b is "two"
    }