Sentinel
Language: Boolean Expressions
Boolean expressions are expressions that evaluate to a boolean value from the result of a combination of one or more comparisons and logical operators. Boolean expressions form the basis of policy since policy can be broken down to a set of logical decisions that turn into true or false.
A single boolean expression is the body of a rule. Additionally, boolean expressions are used with conditionals, and more.
Order of Operations
The precedence of operators is shown below. Operators with higher precedence values (larger numbers) are evaluated first. Operators with the same precedence value are evaluated left-to-right.
Precedence Operator
6 * / %
5 + -
4 else
3 == != < <= > >= "is" "is not" "matches" "contains" "in"
2 and
1 or xor
Examples of this precedence are shown below:
4 * 5 / 5 // 4
4 * 5 + 2 // 22
4 + 5 * 2 // 14
Logical Operators
Logical operators are used to change or combine logical expressions.
There are three binary operators and
, or
, and xor
. There is
a single unary operator not
(which can also be specified as !
).
The binary operators require two boolean operands and the unary operator requires a single boolean operand. In both case, the operands are values or expressions that are boolean types.
Below is a basic explanation of the logical operators directly from the specification:
and conditional AND p and q is "if p then q else false"
or conditional OR p or q is "if p then true else q"
xor conditional XOR p xor q is "if p and not q or not p and q then true"
! NOT !p is "not p"
not NOT !p is "not p"
Using parentheses to group boolean expressions, you can combine boolean expressions to become more complex or affect ordering:
(p and q) or r
p and (q or r)
Comparison Operators
Comparison operators compare two operands and yield a boolean value.
For any comparison, the two operands must be equivalent types. The one exception are integers and floats. When an integer is compared with a float, the integer is promoted to a floating point value.
The available comparison operators are:
== equal
!= not equal
< less
<= less or equal
> greater
>= greater or equal
"is" equal
"is not" not equal
The behavior of is
with ==
and is not
with !=
is identical.
Example comparisons:
name is "Mitchell"
idnumber > 42
idnumber <= 12
Using the logical operators, these can be combined:
name is "Mitchell" and idnumber > 42
The language specification provides more detail on exactly how comparison behaves.
Set Operators
The set operators contains
and in
test for inclusion in a collection
(a list or map).
Set operators may be negated by prefixing the operator with not
, such
as not contains
and not in
. This is equivalent to wrapping the expression
in a unary not
but results in a more readable form.
contains
tests if the left-hand collection contains the right-hand value.
in
tests if the right-hand collection contains the left-hand value. For
maps, "contains" looks at the keys, not the values.
Examples:
[1, 2, 3] contains 2 // true
[1, 2, 3] contains 5 // false
[1, 2, 3] contains "value" // false
[1, 2, 3] not contains "value" // true
{ "a": 1, "b": 2 } contains "a" // true
{ "a": 1, "b": 2 } contains "c" // false
{ "a": 1, "b": 2 } contains 2 // false
{ "a": 1, "b": 2 } not contains 2 // true
Matches Operator
The matches
operator tests if a string matches a regular expression.
The matches
operator can be negated by prefixing the operator with
not
, such as not matches
.
The left-hand value is the string to test. The right-hand value is a string value representing a regular expression. The syntax of the regular expression is the same general syntax used by Python, Ruby, and other languages. The precise syntax accepted is the syntax accepted by RE2.
Regular expressions are not anchored by default; any anchoring must be explicitly specified.
"test" matches "e" // true
"test" matches "^e" // false
"TEST" matches "test" // false
"TEST" matches "(?i)test" // true
"ABC123" matches "[A-Z]+\\d+" // true
"test" not matches "e" // false
Any, All Expressions
any
and all
expressions allow testing that any or all elements of a
collection match some boolean expression. The result of an any
and all
expression is a boolean.
any
returns the boolean value true
if any value in the collection expression
results in the body expression evaluating to true
. If the body expression
evalutes to false
for all values, the any expression returns false
.
all
returns the boolean true
if all values in the collection expression
result in the body expression evaluating to true
. If any value in the
collection expression result in the body expression evaluating to false
,
the all
expression returns false
.
For empty collections, any
returns false
and all
returns true
.
all group.tasks as t { t.driver is "vmware" }
any group.tasks as t { t.driver is "vmware" }
Since any
and all
expressions are themselves boolean expressions, they
can be combined with other operators:
any ["a", "b"] as char { char is "a" } or
other_value is "another"
Emptiness Comparison
The expressions is empty
and is not empty
provide a convenience
method for determining the emptiness of a value. It supports the same types
as the built-in length, collections and strings.
[] is empty // true
[] is not empty // false
["foo"] is empty // false
["foo"] is not empty // true
undefined is empty // undefined
undefined is not empty // undefined
Defined Comparison
The expressions is defined
and is not defined
provide a convenience
method for determining if a value has been defined. In other words, any value
other than undefined
can be considered as defined
.
[] is defined // true
4 is defined // true
true is defined // true
{} is defined // true
undefined is defined // false
[] is not defined // false
4 is not defined // false
true is not defined // false
undefined is not defined // true