Sentinel
Sentinel Language
Sentinel policies are written using the Sentinel language. This language is easy to learn and easy to write. You can learn the Sentinel language and be productive within an hour. Learning Sentinel doesn't require any formal programming experience.
This language guide will contain many details that are not necessary to be productive with Sentinel or are targeted to those who are looking for exact information about the language (such as what types of line endings are allowed). You can safely ignore these sentences.
You may also view the official language specification This is a specific and detailed document on the syntax and behavior of the language primarily intended for implementation creators and to disambiguate the language.
Simplest Example
The example below is about the simplest practical example of Sentinel. It is reasonable to imagine this as a realistic policy. This shows that in most cases, Sentinel will be extremely simple:
main = rule { request.method is "GET" and request.headers contains "X-Key" }
Files
Sentinel policies are single files that end in the .sentinel
file extension.
There is currently no built-in mechanism to Sentinel for merging multiple
files. This is purposefully done to make Sentinel policies easy to submit
to systems that support Sentinel policies.
Sentinel policy files must be UTF-8 encoded and can end in both Unix (LF) or Windows (CRLF) line breaks. When running the auto-formatter, line endings will always use Unix line breaks.
Ordering
Sentinel policies are executed top-down. For example:
a = 1 // a = 1 here
b = a + 1 // b = 2 here
a = 3 // a = 3, b = 2
In this example, the value of a
and b
is shown at each line. Since Sentinel
executes values top-down, the final value of a
is 3 and b
is 2. b
does
not become 4.
Main
Sentinel expects there to be a main
rule.
The value of this rule is the result of the entire policy.
The result of the policy depends on the evaluated contents of the main
rule.
For booleans, a policy passes on a true
value, and fails on a false
value.
Other types generally follow a zero or zero-length pattern for determining
success.
Type | Passing Condition | Failing Condition |
---|---|---|
Boolean | true | false |
String | "" | Any non-zero length string |
Integer | 0 | Any non-zero value |
Float | 0.0 | Any non-zero value |
List | [] | Any non-zero length list |
Map | {} | Any non-zero length map |
A value of main that falls outside of the above types will result in a policy
error. As a special case, if main
evaluates to an undefined value, the error
message will indicate as such, with a reference to where the undefined value was
encountered.
More Complex Example
The simple example above is a full working example. In our experience with Sentinel, many policies can be representing using this simple form. However, to show more features of the language, a more complex example is shown below. This example is also a realistic example of what Sentinel may be used for.
import "units"
memory = func(job) {
result = 0
for job.groups as g {
for g.tasks as t {
result += t.resources.memory else 0
}
}
return result
}
main = rule {
memory(job) < 1 * units.gigabyte
}