CEL Expression Reference

March 22, 2026 · View on GitHub

CEL (Common Expression Language) is used in darnit TOML configurations to evaluate pass results. This reference covers syntax, context variables, and common pitfalls.

Where CEL is Used

CEL expressions appear in the expr field of TOML [[passes]] entries:

[[controls."MY-01".passes]]
handler = "exec"
command = ["gh", "api", "/repos/$OWNER/$REPO"]
output_format = "json"
expr = 'output.json.private == false'

After any handler runs, the orchestrator evaluates the expr field:

  • CEL evaluates to truePASS
  • CEL evaluates to falseINCONCLUSIVE (pipeline continues to next pass)
  • CEL evaluation error → falls through to handler's exit code / default behavior

Syntax Rules

CEL uses C/Java-style syntax, NOT Python syntax.

Boolean operators

OperatorCELPython (WRONG)
AND&&and
OR||or
NOT!not
# CORRECT
expr = 'output.json.enabled == true && output.exit_code == 0'
expr = '!(output.any_match)'

# WRONG — will cause parse errors
expr = 'output.json.enabled == true and output.exit_code == 0'
expr = 'not output.any_match'

Comparison operators

Standard C-style: ==, !=, <, >, <=, >=

String operations

# Contains
output.stdout.contains("success")

# Starts with / ends with
output.stdout.startsWith("OK")
output.stdout.endsWith(".md")

# Size
output.stdout.size() > 0

List operations

# Size
output.json.items.size() > 0

# Check if list contains value
"admin" in output.json.roles

# Exists (any element matches)
output.json.items.exists(x, x.name == "README.md")

Available Context Variables

For exec handler

VariableTypeDescription
output.stdoutstringStandard output from command
output.stderrstringStandard error from command
output.exit_codeintExit code from command
output.jsonobjectParsed JSON (when output_format = "json")

For pattern handler

VariableTypeDescription
output.any_matchboolWhether any content pattern matched
output.files_foundintNumber of files matching file_patterns
output.matchesobjectPer-pattern match results

For API responses

VariableTypeDescription
response.status_codeintHTTP status code
response.bodystringResponse body
response.headersobjectResponse headers

Project context

VariableTypeDescription
project.*variousValues from .project/project.yaml

Custom Functions

FunctionSignaturePurpose
file_exists(path)string → boolCheck if file exists at path
json_path(obj, path)object, string → valueExtract value using dotted path

TOML String Escaping

This is the most common source of bugs. TOML has two string types relevant to CEL:

Literal strings (single-quoted) — PREFERRED

In TOML literal strings ('...'), backslashes are literal characters. No escape processing occurs.

# What you write in TOML → What CEL receives
expr = 'output.stdout.matches("version\\s+\\d+\\.\\d+")'
#                                                  ^^
# WRONG — this sends two backslashes to CEL

expr = 'output.stdout.matches("version\s+\d+\.\d+")'
#                                              ^^
# CORRECT — CEL receives \. which is regex for "literal dot"

Rule: In literal strings, \. in TOML = \. in CEL regex (matches literal dot).

Basic strings (double-quoted)

In TOML basic strings ("..."), backslashes ARE escape characters. You need double escaping:

expr = "output.stdout.matches(\"version\\s+\\d+\\\\.\\d+\")"
# Messy — avoid this. Use literal strings instead.

Common escaping mistakes

TOML literal stringCEL receivesRegex meaning
'\.'\.Literal dot
'\\.'\\.Backslash + any char (WRONG)
'\n'\nNewline
'\\n'\\nLiteral backslash + n

Bottom line: In TOML literal strings, use \. not \\. for regex literal dots.

Common Pitfalls

1. Using Python-style boolean operators

# WRONG — CEL parse error
expr = 'not output.any_match'
expr = 'output.json.enabled and output.exit_code == 0'

# CORRECT
expr = '!(output.any_match)'
expr = 'output.json.enabled && output.exit_code == 0'

2. Over-escaping in TOML literal strings

# WRONG — sends \\ to CEL regex
expr = 'output.stdout.matches("v\\d+\\.\\d+")'

# CORRECT — sends \ to CEL regex
expr = 'output.stdout.matches("v\d+\.\d+")'

3. Missing parentheses with negation

# Ambiguous — add explicit parentheses
expr = '!output.any_match'

# Clear
expr = '!(output.any_match)'

4. Accessing nested JSON without null checks

# May error if output.json is null or missing key
expr = 'output.json.settings.enabled == true'

# Safer — check key exists first
expr = 'has(output.json.settings) && output.json.settings.enabled == true'

5. Comparing with wrong types

# WRONG — exit_code is int, "0" is string
expr = 'output.exit_code == "0"'

# CORRECT
expr = 'output.exit_code == 0'

Examples from OpenSSF Baseline

# Simple boolean check
expr = 'output.json.two_factor_requirement_enabled == true'

# Negated match (file should NOT exist)
expr = 'output.files_found == 0'

# Combined check
expr = 'output.exit_code == 0 && output.json.default_branch_protection.enabled == true'

# Pattern match result
expr = 'output.any_match'

# Negated pattern match
expr = '!(output.any_match)'

Next Steps