default-over-else
Summary: Prefer default assignment over fallback else
Category: Style
Avoid
package policy
import rego.v1
permissions := ["read", "write"] if {
input.user == "admin"
} else := ["read"]
Prefer
package policy
import rego.v1
default permissions := ["read"]
permissions := ["read", "write"] if {
input.user == "admin"
}
Rationale
The else
keyword has a single purpose in Rego — to allow a policy author to control the order of evaluation. Whether
several else
-clauses are chained or not, it's common to use a last "fallback" else
to cover all cases not covered by
the conditions in the preceding else
-bodies. A kind of "catch all", or "default" condition. This is useful, but Rego
arguably provides a more idiomatic construct for default assignment: the
default keyword.
While the end result is the same, default assignment has the benefit of more clearly — and before the conditional assignments — communicating what the safe option is. This is particularly important for entrypoint rules, where the default value of a rule is a part of the rule's contract.
Exceptions
OPA v0.55.0 introduced support for the default keyword
for custom functions. This means that else
fallbacks in functions may now be rewritten to use default assignment too:
package policy
first_name(full_name) := split(full_name, " ")[0] if {
full_name != ""
} else := "Unknown"
Could now be written as:
package policy
default first_name(_) := "Unknown"
first_name(full_name) := split(full_name, " ")[0] if {
full_name != ""
}
Default value assignment for functions however come with a big caveat — the default case will only be triggered if all
arguments passed to the function evaluate to a defined value. Thus, calling the first_name
function from our above
example is not guaranteed to return a value of "Unknown"
:
# undefined if `input.name` is undefined
fname := first_name(input.name)
Whether deemed acceptable or not, this differs enough from default assignment of rules to make this preference opt-in
rather than opt-out. Use the prefer-default-functions
configuration option to control whether default
assignment
should be preferred over else
fallbacks also for custom functions. The default value (no pun intended!) of this config
option is false
.
Configuration Options
This linter rule provides the following configuration options:
rules:
style:
default-over-else:
# one of "error", "warning", "ignore"
level: error
# whether to prefer default assignment over
# `else` fallbacks for custom functions
prefer-default-functions: false
Related Resources
- OPA Docs: Default Keyword
- GitHub: Source Code
Community
If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules,
or just talk about Regal in general, please join us in the #regal
channel in the Styra Community
Slack!