google / cel-go

Fast, portable, non-Turing complete expression evaluation with gradual typing (Go)
https://cel.dev
Apache License 2.0
2.19k stars 218 forks source link

[Policy engine] Support conditional nested rules #985

Closed seirl closed 1 month ago

seirl commented 1 month ago

In the policy engine, it would be useful to support conditional nested rules, because that would allow us to define variables that only make sense if a specific condition is met:

rule:
  match:
    - condition: a.hasValue()
      rule:
        variables:
          - name: a_derived
            expression: "a.value().derived"
        match:
          - condition: a_derived > 42
            output: "false"
          - condition: a_derived < 42
            output: "false"
          - output: true
    - condition: "b.hasValue()"
      output: "b.value()"
    - output: "false"

However this is currently not supported and will fail with the error message subrule early terminates policy. I think this check is here to prevent things like:

rule:
  match:
    - rule:
        match:
          - condition: a > 42
            output: "false"
          - output: true
    - output: "false"

where the last "output" block can never be reached.

To support this, the check should be relaxed, but we still want to catch the error above. I think a good refined check would be:

"If the nested rule is guarded by a trivially true condition, it should not early terminate the policy".

This would allow the first example (because there is a condition a.hasValue() guarding the nested rule), but not the second (because there is no condition for the rule and for the last output block).

seirl commented 1 month ago

Come to think of it, I don't really see the use-case for unconditional rules (at least ones that are not the last one in the list). For me the reason they are useful is mostly to define variables that only make sense when the condition is met, otherwise you can just flatten the nested rule in the upper rule.