Skip to content

CEL Expressions

Dependency-Track uses the Common Expression Language (CEL) in three places:

  • Policy conditions, evaluated against components or vulnerabilities to drive policy violations and analyses. See Condition expressions.
  • Notification filters, evaluated against notification subjects to control which notifications are dispatched. See Filter expressions.
  • Workload identity binding conditions, evaluated against the claims of a verified platform token to decide whether a workload may act as a service account. Available in 5.2.0 and later. See Workload identity.

The contexts share the syntax described on this page, but expose different variables, types, and custom functions. The custom functions documented for policies (for example depends_on, spdx_expr_allows) are not available to notification filters or binding conditions, and the variables differ entirely. Refer to the context-specific page for the available inputs and functions.

Syntax

The CEL syntax is similar to other C-style languages like Java and JavaScript. However, CEL is not Turing-complete. As such, it does not support constructs like if statements or loops (that is, for, while).

As a compensation for missing loops, CEL offers macros like all, exists, exists_one, map, and filter. Refer to the macros documentation for more details.

CEL syntax is described thoroughly in the official language definition.

Standard library

Both contexts have access to the standard definitions of the CEL specification and the CEL strings extension, which adds functions like charAt, indexOf, join, lowerAscii, replace, split, substring, trim, and upperAscii.

The policy context registers additional custom functions (depends_on, spdx_expr_allows, and so on); see Condition expressions. Notification filters and workload identity binding conditions do not register any custom functions.

Optional field checking

CEL does not have a concept of null. Accessing a field that is not set returns its default value (for example, "" for strings, 0 for numbers, false for booleans), which can lead to misleading matches. Use the has() macro to check for field presence before accessing it:

1
has(obj.field) && obj.field == "value"

The has() macro works in all three contexts. The exact root variables (component, subject, claims, and so on) are documented on the context-specific reference pages.