Condition expressions¶
Policy conditions use CEL. This page describes the inputs, custom functions, and example expressions available to policy conditions.
Evaluation contexts¶
Dependency-Track has two policy types, each with its own CEL evaluation context.
Component policies¶
Component policies apply to individual components. Each condition runs for every component in a project.
| Variable | Type | Description |
|---|---|---|
component |
Component | The component under evaluation |
project |
Project | The project the component is part of |
vulns |
list(Vulnerability) | Vulnerabilities affecting the component |
now |
google.protobuf.Timestamp |
The current time at the start of evaluation |
Vulnerability policies¶
Vulnerability policies apply to a single vulnerability. Each condition runs for every vulnerability finding in a project.
| Variable | Type | Description |
|---|---|---|
component |
Component | The component the vulnerability applies to |
project |
Project | The project the component belongs to |
vuln |
Vulnerability | The vulnerability under evaluation |
now |
google.protobuf.Timestamp |
The current time at the start of evaluation |
The two contexts differ only in how they expose vulnerabilities. Component policies
iterate over vulns (a list); vulnerability policies receive a single vuln. All
custom functions documented below are available to both contexts.
Note
Many fields on Component, Project, and Vulnerability are optional.
Use the has() macro to check for presence of optional fields
before accessing them.
Examples¶
Component age¶
Besides out-of-date versions, component age is another indicator of potential risk. Components may be on the latest available version, but still be 20 years old.
The following expression matches Components that are two years old, or even older, using the now
variable and timestamp arithmetic:
1 2 | |
Component blacklist¶
The following expression matches on the Component's Package URL, using a regular expression in RE2 syntax.
It also checks whether the Component's version falls into a given vers range using
matches_range.
1 2 | |
The expression matches:
pkg:maven/com.acme/acme-lib@0.1.0pkg:maven/com.acme/acme-lib@0.9.9
but not:
pkg:maven/com.acme/acme-library@0.1.0pkg:maven/com.acme/acme-lib@0.2.4
Dependency graph traversal¶
The following expression matches Components that are a (possibly transitive) dependency of a Component
with name foo, but only if a Component with name bar is also present in the Project.
1 2 | |
To check whether a component is a direct (that is, non-transitive) dependency:
1 | |
To check whether a component is only introduced through another component (that is, no other path in the dependency graph leads to it):
1 | |
Dependency graph functions support the following Component fields for matching:
| Field | re: prefix |
vers: prefix |
|---|---|---|
uuid |
||
group |
✅ | |
name |
✅ | |
version |
✅ | ✅ |
classifier |
||
cpe |
✅ | |
purl |
✅ | |
swid_tag_id |
✅ | |
is_internal |
The re: prefix enables RE2 regular expression matching on the field value:
1 | |
The vers: prefix enables vers range matching on the version field:
1 2 3 4 | |
Note
When constructing objects like Component on-the-fly, use their version namespace,
that is, v1. This enables type checking and ensures backward compatibility.
License expression allowlist¶
The following expression matches non-internal Components whose SPDX license expression requires a license outside the approved set. License-with-exception combinations appear as a single compound entry.
1 2 3 4 | |
When components don't have a license expression, component.resolved_license.id works as a fallback.
A single license ID is a valid SPDX expression, so it gets the same version-aware treatment:
1 2 3 4 5 6 | |
License blacklist¶
The following expression matches Components that are not internal to the organization, and have either:
1 2 3 4 5 | |
Vulnerability blacklist¶
The following expression matches Components in Projects tagged as 3rd-party, with at least one Vulnerability
being any of the given blacklisted IDs.
1 2 3 4 5 6 | |
Vulnerabilities with high severity in public facing projects¶
The following expression matches Components in Projects tagged as public-facing, with at least one HIGH
or CRITICAL
Vulnerability, where the CVSSv3 attack vector is Network.
1 2 3 4 5 | |
Suppressing a specific CVE in a vulnerability policy¶
In a vulnerability policy, the subject is a single
vulnerability. Field accesses on vuln replace the earlier vulns.exists(...)
patterns:
1 2 3 4 5 6 | |
Hash mismatch with the upstream repository¶
The following expression matches Components whose declared hashes disagree with the hashes the upstream package repository reports for the same artifact. Useful for spotting tampered or mis-pinned components.
1 | |
To focus on Projects tagged as production:
1 2 | |
See has_package_artifact_hash_mismatch for the matching
table and a note on what a false result does and does not mean.
Version distance¶
The version_distance function allows matching based on how far behind a component's version
is from the latest known version. Specify the distance using a VersionDistance object with epoch, major,
minor, and patch fields.
The following expression matches components that are more than one major version behind:
1 | |
License expression handling¶
The spdx_expr_* functions check SPDX license expressions. They operate on expression strings
(typically component.license_expression) and also work with component.resolved_license.id
as a fallback for components without a license expression.
All license ID comparisons are case-insensitive per the SPDX specification.
Version equivalence¶
Deprecated license IDs match their modern counterparts.
For example, GPL-2.0 and GPL-2.0-only map to the same license.
Version ranges¶
The + operator and -or-later suffix mean "this version or any later
version in the same license family." For example, GPL-3.0-only satisfies an allow-list containing
GPL-2.0-or-later, and Apache-1.0+ satisfies an allow-list containing Apache-2.0.
Deprecated WITH-compounds¶
Legacy compound IDs like GPL-2.0-with-classpath-exception are automatically
resolved to their modern WITH expression form (GPL-2.0-only WITH Classpath-exception-2.0).
WITH composites¶
License-with-exception combinations act as atomic composites. The full
compound (for example, "GPL-2.0-only WITH Classpath-exception-2.0") must appear as a single entry in
allow-lists, not as separate license and exception IDs. The license part uses version-aware matching
(for example, GPL-2.0 WITH ... matches GPL-2.0-only WITH ...), while the exception part requires an exact match.
Function reference¶
For type definitions, refer to the schema reference.
Beyond the standard CEL library, policy conditions have access to the following custom functions registered by Dependency-Track.
depends_on¶
Checks whether a Project contains a Component matching the given criteria. Useful for enforcing policies only when specific components are present in a project.
| Name | Type | Description |
|---|---|---|
| receiver | Project | The project to check |
component |
Component | Criteria to match against. Supports re: and vers: prefixes. |
Returns: true if a matching component exists in the project.
1 | |
graph TD
P["Project"]:::match --> A["foo"]
P --> B["bar"]
A --> C["baz"]:::criteria
A --> D["qux"]
B --> D
classDef match stroke:#22c55e,stroke-width:3
classDef criteria fill:#22c55e,color:#fff
Tip
project matches because baz exists in its dependency graph.
has_package_artifact_hash_mismatch¶
Checks whether a Component's declared hashes disagree with the hashes the upstream package repository reports for the same artifact.
The function compares MD5, SHA-1, SHA-256, and SHA-512 (the algorithms package repositories typically report). All comparisons are case-insensitive.
| Name | Type | Description |
|---|---|---|
| receiver | Component | The component to check |
Returns: true if at least one shared algorithm has non-empty values on both sides that
differ. Returns false in all other cases, including when no upstream metadata is available
and when there is no shared algorithm to compare.
1 | |
| Component hashes | Upstream hashes | Result |
|---|---|---|
sha256: aaa… |
sha256: aaa… |
false |
sha256: aaa… (lowercase) |
sha256: AAA… (uppercase) |
false |
sha256: aaa… |
sha256: bbb… |
true |
sha256: aaa…, sha1: 012… |
sha256: aaa…, sha1: ff… |
true |
sha256: aaa… |
sha1: 012… only |
false |
sha256: aaa… |
none reported | false |
sha3_512: ccc… only |
sha256: aaa… |
false |
Tip
A false result does not confirm that hashes match. It only means there is no
positive evidence of a mismatch. Components without upstream hash data, or with
no shared algorithm to compare, also return false.
Note
Dependency-Track resolves upstream hashes asynchronously. On the first policy evaluation after a BOM
upload, they may not be available yet and the function returns false. Later evaluations
pick up the data once resolution completes.
is_dependency_of¶
Checks whether a Component is a (possibly transitive) dependency of another Component.
| Name | Type | Description |
|---|---|---|
| receiver | Component | The component under evaluation |
component |
Component | Criteria to match the parent against. Supports re: and vers: prefixes. |
Returns: true if the receiver is a dependency (direct or transitive) of a matching component.
1 | |
graph TD
P["Project"] --> A["foo"]:::criteria
P --> B["bar"]
A --> C["baz"]:::match
A --> D["qux"]:::match
B --> D
classDef match stroke:#22c55e,stroke-width:3
classDef criteria fill:#22c55e,color:#fff
Tip
baz and qux match since both are dependencies of foo.
qux matches even though it's also reachable through bar.
is_direct_dependency_of¶
Checks whether a Component is a direct (non-transitive) dependency of another Component.
| Name | Type | Description |
|---|---|---|
| receiver | Component | The component under evaluation |
component |
Component | Criteria to match the parent against. Supports re: and vers: prefixes. |
Returns: true if the receiver is a direct dependency of a matching component.
1 | |
graph TD
P["Project"] --> A["foo"]:::criteria
P --> B["bar"]
A --> C["baz"]:::match
A --> D["qux"]:::match
B --> D
classDef match stroke:#22c55e,stroke-width:3
classDef criteria fill:#22c55e,color:#fff
Tip
baz and qux match since both are direct children of foo.
With a deeper graph, transitive dependencies do not match:
graph TD
A["foo"]:::criteria --> C["baz"]:::match
C --> E["deep"]:::nomatch
classDef match stroke:#22c55e,stroke-width:3
classDef criteria fill:#22c55e,color:#fff
classDef nomatch stroke:#ef4444,stroke-width:3,stroke-dasharray:5
Tip
baz matches since it's a direct child of foo.
deep does not match, as it's a transitive dependency.
is_exclusive_dependency_of¶
Checks whether a Component is only introduced through another Component.
Returns true only if every path from the project root to the receiver passes through a matching component.
| Name | Type | Description |
|---|---|---|
| receiver | Component | The component under evaluation |
component |
Component | Criteria to match the parent against. Supports re: and vers: prefixes. |
Returns: true if the receiver is only introduced through a matching component.
1 | |
graph TD
P["Project"] --> A["foo"]:::criteria
P --> B["bar"]
A --> C["baz"]:::match
A --> D["qux"]:::nomatch
B --> D
classDef match stroke:#22c55e,stroke-width:3
classDef criteria fill:#22c55e,color:#fff
classDef nomatch stroke:#ef4444,stroke-width:3,stroke-dasharray:5
Tip
baz matches since it's only reachable through foo.
qux does not match, as it's also reachable through bar.
matches_range¶
Checks whether a Component's or Project's version falls within a vers range.
| Name | Type | Description |
|---|---|---|
| receiver | Component or Project | The component or project to check |
range |
string |
A vers range string (for example, "vers:maven/>1.0.0\|<2.0.0") |
Returns: true if the version is within the specified range.
1 | |
Currently supported versioning schemes:
| Versioning Scheme | Ecosystem |
|---|---|
deb |
Debian / Ubuntu |
generic |
Generic / Any |
golang |
Go |
maven |
Java / Maven |
npm |
JavaScript / NodeJS |
rpm |
CentOS / Fedora / Red Hat / SUSE |
Note
If you know the ecosystem of the components to match against upfront, it's good practice to use the according
versioning scheme in matches_range. This helps with accuracy, as versioning schemes have different nuances
across ecosystems, which makes comparisons error-prone.
spdx_expr_allows¶
Checks whether an SPDX license expression holds when limited to
the given set of licenses. For OR expressions, at least one branch must
be satisfiable. For AND expressions, all children must be satisfiable. WITH expressions
act as atomic composites (see below).
| Name | Type | Description |
|---|---|---|
expression |
string |
An SPDX license expression |
ids |
list(string) |
Allowed licenses, including WITH composites if needed |
Returns: true if the expression is satisfiable with the given IDs.
1 2 3 4 5 6 | |
Version-range matching applies automatically:
1 2 3 4 5 | |
Tip
WITH expressions (license-with-exception) match as a single unit.
The allowed set must contain the full compound entry, not the license and exception separately:
1 2 3 4 5 6 | |
spdx_expr_requires_any¶
Checks whether every possible satisfaction of an SPDX license expression
requires at least one of the given license IDs. For OR expressions, at least one of
the IDs must appear in all branches. For AND expressions, at least one of the IDs must
appear in at least one child.
| Name | Type | Description |
|---|---|---|
expression |
string |
An SPDX license expression |
ids |
list(string) |
License IDs to check |
Returns: true if every satisfaction requires at least one of the IDs.
1 2 3 4 5 | |
version_distance¶
Checks whether the distance between a Component's current version and its latest known version matches a given VersionDistance.
| Name | Type | Description |
|---|---|---|
| receiver | Component | The component to check |
operator |
string |
Numeric comparator: <, <=, =, !=, >, >= |
distance |
VersionDistance | The version distance to compare against |
Returns: true if the version distance satisfies the comparison.
1 | |