From 731eb4a699e3bfb55cda0ed5a33df31e86efb0b2 Mon Sep 17 00:00:00 2001 From: Matt Finkel Date: Fri, 9 Oct 2026 12:40:50 +0100 Subject: [PATCH 1/2] Document violation messages from condition expressions Condition expressions may return a string that becomes the violation message. Describe the result types, add an example, and regenerate the notification schema for the new message fields. Signed-off-by: Matt Finkel --- docs/concepts/component-policies.md | 2 ++ .../notifications/notification.proto | 4 +++ docs/reference/notifications/schema.md | 2 ++ .../policies/condition-expressions.md | 31 +++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/docs/concepts/component-policies.md b/docs/concepts/component-policies.md index 8839dce2..bb9c9bf0 100644 --- a/docs/concepts/component-policies.md +++ b/docs/concepts/component-policies.md @@ -55,6 +55,8 @@ vulnerability policies, with the same custom functions [`version_distance`](../reference/policies/condition-expressions.md#version_distance), and others). Expression conditions let an organization encode rules that combine component fields, traverse the dependency graph, or operate on SPDX license expressions directly. +An expression can also return a message instead of `true`, so the resulting violation explains +what matched. See [Result](../reference/policies/condition-expressions.md#result). ## Where a policy applies diff --git a/docs/reference/notifications/notification.proto b/docs/reference/notifications/notification.proto index 98ed5fe8..fe34ef2e 100644 --- a/docs/reference/notifications/notification.proto +++ b/docs/reference/notifications/notification.proto @@ -189,6 +189,8 @@ message PolicyViolation { string type = 2; google.protobuf.Timestamp timestamp = 3; PolicyCondition condition = 4; + // Message produced by the policy condition expression, if any. + optional string message = 5; } message PolicyCondition { @@ -362,5 +364,7 @@ message NewPolicyViolationsSummarySubject { google.protobuf.Timestamp timestamp = 5; optional string analysis_state = 6; bool suppressed = 7; + // Message produced by the policy condition expression, if any. + optional string message = 8; } } diff --git a/docs/reference/notifications/schema.md b/docs/reference/notifications/schema.md index f5bfccd5..c016dbdf 100644 --- a/docs/reference/notifications/schema.md +++ b/docs/reference/notifications/schema.md @@ -657,6 +657,7 @@ Subject for GROUP_NEW_VULNERABILITIES_SUMMARY notifications. | `timestamp` | `google.protobuf.Timestamp` | | - | | `analysis_state` | `string` | | - | | `suppressed` | `bool` | | - | +| `message` | `string` | Message produced by the policy condition expression, if any. | - | @@ -880,6 +881,7 @@ Subject for GROUP_NEW_VULNERABILITIES_SUMMARY notifications. | `type` | `string` | | - | | `timestamp` | `google.protobuf.Timestamp` | | - | | `condition` | [`PolicyCondition`](#org-dependencytrack-notification-v1-PolicyCondition) | | - | +| `message` | `string` | Message produced by the policy condition expression, if any. | - | diff --git a/docs/reference/policies/condition-expressions.md b/docs/reference/policies/condition-expressions.md index 0baec8b6..dbca9d6f 100644 --- a/docs/reference/policies/condition-expressions.md +++ b/docs/reference/policies/condition-expressions.md @@ -40,6 +40,22 @@ custom functions documented below are available to both contexts. Use the `has()` macro to [check for presence of optional fields](../cel-expressions.md#optional-field-checking) before accessing them. +## Result + +A condition expression returns either a `bool` or a `string`. + +* `true` records a violation, `false` does not. +* A non-blank string records a violation and uses the string as the violation message. + Dependency-Track trims the message and truncates it to 1024 characters. It appears in the + violation's `text` field in the REST API, and in `POLICY_VIOLATION` and + `NEW_POLICY_VIOLATIONS_SUMMARY` notifications. +* A blank string does not record a violation. + +Dependency-Track rejects component policy conditions whose expression returns any other type. +Returning a string lets a condition explain *what* matched, for example which vulnerability +or which license, instead of only that something matched. +See [Violation messages](#violation-messages) for an example. + ## Examples ### Component age @@ -217,6 +233,21 @@ To also cover vulnerabilities that are not in a catalog yet, but that [EPSS] giv vulns.exists(vuln, vuln.is_kev || vuln.epss_score > 0.5) ``` +### Violation messages + +The following expression matches [Component]s with a known exploited [Vulnerability], and +names the first one in the violation message. `cel.bind` assigns the matching vulnerabilities +to a variable so the expression does not repeat the filter: + +```js linenums="1" +cel.bind(kev, vulns.filter(vuln, vuln.is_kev), + kev.size() > 0 + ? "Component is affected by known exploited vulnerability " + kev[0].id + : "") +``` + +Returning `""` when nothing matches records no violation. + ### Suppressing a specific CVE in a vulnerability policy In a [vulnerability policy](vulnerability-policies.md), the subject is a single From fa572d5c883f94366746170b46da59109278a883 Mon Sep 17 00:00:00 2001 From: Matt Finkel Date: Sun, 11 Oct 2026 18:40:13 +0100 Subject: [PATCH 2/2] Note that string results need 5.3.0 or later Users on older versions would otherwise expect violation messages that their release does not produce. Signed-off-by: Matt Finkel --- docs/reference/policies/condition-expressions.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/reference/policies/condition-expressions.md b/docs/reference/policies/condition-expressions.md index dbca9d6f..4341d854 100644 --- a/docs/reference/policies/condition-expressions.md +++ b/docs/reference/policies/condition-expressions.md @@ -42,6 +42,10 @@ custom functions documented below are available to both contexts. ## Result +!!! note "Available in 5.3.0 and later" + + Earlier versions require condition expressions to return `bool`. + A condition expression returns either a `bool` or a `string`. * `true` records a violation, `false` does not. @@ -235,6 +239,10 @@ vulns.exists(vuln, vuln.is_kev || vuln.epss_score > 0.5) ### Violation messages +!!! note "Available in 5.3.0 and later" + + Earlier versions require condition expressions to return `bool`. + The following expression matches [Component]s with a known exploited [Vulnerability], and names the first one in the violation message. `cel.bind` assigns the matching vulnerabilities to a variable so the expression does not repeat the filter: