Skip to content

Commit

Permalink
Reduce quantity of notifications generated and emit events from misse…
Browse files Browse the repository at this point in the history
…d NVD updates

Signed-off-by: 4naesthetic <[email protected]>
  • Loading branch information
4naesthetic committed Aug 12, 2024
1 parent f8402c9 commit 91332a2
Show file tree
Hide file tree
Showing 24 changed files with 301 additions and 183 deletions.
135 changes: 68 additions & 67 deletions docs/_docs/integrations/notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,25 @@ Notification levels behave identical to logging levels:
Each scope contains a set of notification groups that can be subscribed to. Some groups contain notifications of
multiple levels, while others can only ever have a single level.

| Scope | Group | Level(s) | Description |
|-----------|---------------------------|-----------------|-----------------------------------------------------------------------------------------------------------------------------------|
| SYSTEM | ANALYZER | (Any) | Notifications generated as a result of interacting with an external source of vulnerability intelligence |
| SYSTEM | DATASOURCE_MIRRORING | (Any) | Notifications generated when performing mirroring of one of the supported datasources such as the NVD |
| SYSTEM | INDEXING_SERVICE | (Any) | Notifications generated as a result of performing maintenance on Dependency-Tracks internal index used for global searching |
| SYSTEM | FILE_SYSTEM | (Any) | Notifications generated as a result of a file system operation. These are typically only generated on error conditions |
| SYSTEM | REPOSITORY | (Any) | Notifications generated as a result of interacting with one of the supported repositories such as Maven Central, RubyGems, or NPM |
| SYSTEM | USER_CREATED | INFORMATIONAL | Notifications generated as a result of a user creation |
| SYSTEM | USER_DELETED | INFORMATIONAL | Notifications generated as a result of a user deletion |
| PORTFOLIO | NEW_VULNERABILITY | INFORMATIONAL | Notifications generated whenever a new vulnerability is identified |
| PORTFOLIO | VULNERABILITY_UPDATED | INFORMATIONAL | Notifications generated if the severity of a vulnerability changes after it has been created |
| PORTFOLIO | NEW_VULNERABLE_DEPENDENCY | INFORMATIONAL | Notifications generated as a result of a vulnerable component becoming a dependency of a project |
| PORTFOLIO | GLOBAL_AUDIT_CHANGE | INFORMATIONAL | Notifications generated whenever an analysis or suppression state has changed on a finding from a component (global) |
| PORTFOLIO | PROJECT_AUDIT_CHANGE | INFORMATIONAL | Notifications generated whenever an analysis or suppression state has changed on a finding from a project |
| PORTFOLIO | BOM_CONSUMED | INFORMATIONAL | Notifications generated whenever a supported BOM is ingested and identified |
| PORTFOLIO | BOM_PROCESSED | INFORMATIONAL | Notifications generated after a supported BOM is ingested, identified, and successfully processed |
| PORTFOLIO | BOM_PROCESSING_FAILED | ERROR | Notifications generated whenever a BOM upload process fails |
| PORTFOLIO | BOM_VALIDATION_FAILED | ERROR | Notifications generated whenever an invalid BOM is uploaded |
| PORTFOLIO | POLICY_VIOLATION | INFORMATIONAL | Notifications generated whenever a policy violation is identified |
| Scope | Group | Level(s) | Description |
|-----------|-------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------|
| SYSTEM | ANALYZER | (Any) | Notifications generated as a result of interacting with an external source of vulnerability intelligence |
| SYSTEM | DATASOURCE_MIRRORING | (Any) | Notifications generated when performing mirroring of one of the supported datasources such as the NVD |
| SYSTEM | INDEXING_SERVICE | (Any) | Notifications generated as a result of performing maintenance on Dependency-Tracks internal index used for global searching |
| SYSTEM | FILE_SYSTEM | (Any) | Notifications generated as a result of a file system operation. These are typically only generated on error conditions |
| SYSTEM | REPOSITORY | (Any) | Notifications generated as a result of interacting with one of the supported repositories such as Maven Central, RubyGems, or NPM |
| SYSTEM | USER_CREATED | INFORMATIONAL | Notifications generated as a result of a user creation |
| SYSTEM | USER_DELETED | INFORMATIONAL | Notifications generated as a result of a user deletion |
| PORTFOLIO | NEW_VULNERABILITY | INFORMATIONAL | Notifications generated whenever a new vulnerability is identified |
| PORTFOLIO | NEW_VULNERABLE_DEPENDENCY | INFORMATIONAL | Notifications generated as a result of a vulnerable component becoming a dependency of a project |
| PORTFOLIO | PROJECT_VULNERABILITY_UPDATED | INFORMATIONAL | Notifications generated if a vulnerability associated with a project is updated after creation. Currently only triggers on severity updates. |
| PORTFOLIO | GLOBAL_AUDIT_CHANGE | INFORMATIONAL | Notifications generated whenever an analysis or suppression state has changed on a finding from a component (global) |
| PORTFOLIO | PROJECT_AUDIT_CHANGE | INFORMATIONAL | Notifications generated whenever an analysis or suppression state has changed on a finding from a project |
| PORTFOLIO | BOM_CONSUMED | INFORMATIONAL | Notifications generated whenever a supported BOM is ingested and identified |
| PORTFOLIO | BOM_PROCESSED | INFORMATIONAL | Notifications generated after a supported BOM is ingested, identified, and successfully processed |
| PORTFOLIO | BOM_PROCESSING_FAILED | ERROR | Notifications generated whenever a BOM upload process fails |
| PORTFOLIO | BOM_VALIDATION_FAILED | ERROR | Notifications generated whenever an invalid BOM is uploaded |
| PORTFOLIO | POLICY_VIOLATION | INFORMATIONAL | Notifications generated whenever a policy violation is identified |

## Configuring Publishers

Expand Down Expand Up @@ -161,54 +161,6 @@ This type of notification will always contain:

> The `cwe` field is deprecated and will be removed in a later version. Please use `cwes` instead.

#### VULNERABILITY_UPDATED
This type of notification will always contain:
* 1 component
* 1 vulnerability
* 1 or more affected projects

```json
{
"notification": {
"level": "INFORMATIONAL",
"scope": "PORTFOLIO",
"group": "VULNERABILITY_UPDATED",
"timestamp": "2018-08-27T23:26:22.961",
"title": "Change in Severity of a Vulnerability on Project: [Acme Example]",
"content": "The vulnerability CVE-2012-5784 on component axis has changed severity from LOW to MEDIUM",
"subject": {
"vulnerability": {
"uuid": "941a93f5-e06b-4304-84de-4d788eeb4969",
"old": {
"severity": "MEDIUM"
},
"new": {
"severity": "HIGH"
}
},
"component": {
"uuid": "4d5cd8df-cff7-4212-a038-91ae4ab79396",
"group": "apache",
"name": "axis",
"version": "1.4",
"md5": "03dcfdd88502505cc5a805a128bfdd8d",
"sha1": "94a9ce681a42d0352b3ad22659f67835e560d107",
"sha256": "05aebb421d0615875b4bf03497e041fe861bf0556c3045d8dda47e29241ffdd3",
"purl": "pkg:maven/apache/[email protected]"
},
"affectedProjects": [
{
"uuid": "6fb1820f-5280-4577-ac51-40124aabe307",
"name": "Acme Example",
"version": "1.0.0"
}
]
}
}
}
```

#### NEW_VULNERABLE_DEPENDENCY
This type of notification will always contain:
* 1 project
Expand Down Expand Up @@ -282,6 +234,55 @@ This type of notification will always contain:

> The `cwe` field is deprecated and will be removed in a later version. Please use `cwes` instead.
#### PROJECT_VULNERABILITY_UPDATED
This type of notification will always contain:
* 1 vulnerability update
* 1 component

To minimise noise, a notification will only be published if the vulnerability already affects an existing project. This can be scoped down further by limiting notifications to specific projects when configuring an alert rule.

```json
{
"notification": {
"level": "INFORMATIONAL",
"scope": "PORTFOLIO",
"group": "PROJECT_VULNERABILITY_UPDATED",
"timestamp": "2018-08-27T23:26:22.961",
"title": "Vulnerability Update",
"content": "The vulnerability CVE-2012-5784 on component axis has changed severity from LOW to MEDIUM",
"subject": {
"vulnerability": {
"uuid": "941a93f5-e06b-4304-84de-4d788eeb4969",
"vulnId": "CVE-2012-5784",
"source": "NVD",
"aliases": [
{
"vulnId": "GHSA-55w9-c3g2-4rrh",
"source": "GITHUB"
}
],
"old": {
"severity": "LOW"
},
"new": {
"severity": "MEDIUM"
}
},
"component": {
"uuid": "4d5cd8df-cff7-4212-a038-91ae4ab79396",
"group": "apache",
"name": "axis",
"version": "1.4",
"md5": "03dcfdd88502505cc5a805a128bfdd8d",
"sha1": "94a9ce681a42d0352b3ad22659f67835e560d107",
"sha256": "05aebb421d0615875b4bf03497e041fe861bf0556c3045d8dda47e29241ffdd3",
"purl": "pkg:maven/apache/[email protected]"
}
}
}
}
```

#### PROJECT_AUDIT_CHANGE and GLOBAL_AUDIT_CHANGE
This type of notification will always contain:
* 1 component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
import org.dependencytrack.tasks.VexUploadProcessingTask;
import org.dependencytrack.tasks.VulnDbSyncTask;
import org.dependencytrack.tasks.VulnerabilityAnalysisTask;
import org.dependencytrack.tasks.VulnerabilityUpdateTask;
import org.dependencytrack.tasks.ProjectVulnerabilityUpdateTask;
import org.dependencytrack.tasks.metrics.ComponentMetricsUpdateTask;
import org.dependencytrack.tasks.metrics.PortfolioMetricsUpdateTask;
import org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask;
Expand Down Expand Up @@ -119,7 +119,7 @@ public void contextInitialized(final ServletContextEvent event) {
EVENT_SERVICE.subscribe(ClearComponentAnalysisCacheEvent.class, ClearComponentAnalysisCacheTask.class);
EVENT_SERVICE.subscribe(CallbackEvent.class, CallbackTask.class);
EVENT_SERVICE.subscribe(NewVulnerableDependencyAnalysisEvent.class, NewVulnerableDependencyAnalysisTask.class);
EVENT_SERVICE.subscribe(VulnerabilityUpdateEvent.class, VulnerabilityUpdateTask.class);
EVENT_SERVICE.subscribe(ProjectVulnerabilityUpdateEvent.class, ProjectVulnerabilityUpdateTask.class);
EVENT_SERVICE.subscribe(NistMirrorEvent.class, NistMirrorTask.class);
EVENT_SERVICE.subscribe(NistApiMirrorEvent.class, NistApiMirrorTask.class);
EVENT_SERVICE.subscribe(EpssMirrorEvent.class, EpssMirrorTask.class);
Expand Down Expand Up @@ -162,6 +162,7 @@ public void contextDestroyed(final ServletContextEvent event) {
EVENT_SERVICE.unsubscribe(InternalComponentIdentificationTask.class);
EVENT_SERVICE.unsubscribe(CallbackTask.class);
EVENT_SERVICE.unsubscribe(NewVulnerableDependencyAnalysisTask.class);
EVENT_SERVICE.unsubscribe(ProjectVulnerabilityUpdateTask.class);
EVENT_SERVICE.unsubscribe(NistMirrorTask.class);
EVENT_SERVICE.unsubscribe(NistApiMirrorTask.class);
EVENT_SERVICE.unsubscribe(EpssMirrorTask.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) Steve Springett. All Rights Reserved.
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.event;

Expand All @@ -23,11 +23,11 @@
import org.dependencytrack.model.VulnerabilityUpdateDiff;


public class VulnerabilityUpdateEvent extends SingletonCapableEvent {
public class ProjectVulnerabilityUpdateEvent extends SingletonCapableEvent {
private final VulnerabilityUpdateDiff vulnerabilityUpdateDiff;
private final Vulnerability vulnerability;

public VulnerabilityUpdateEvent(Vulnerability vulnerability, VulnerabilityUpdateDiff vulnerabilityUpdateDiff) {
public ProjectVulnerabilityUpdateEvent(Vulnerability vulnerability, VulnerabilityUpdateDiff vulnerabilityUpdateDiff) {
this.vulnerability = vulnerability;
this.vulnerabilityUpdateDiff = vulnerabilityUpdateDiff;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) Steve Springett. All Rights Reserved.
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.model;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public static class Title {
public static final String ANALYZER_ERROR = "Analyzer Error";
public static final String INTEGRATION_ERROR = "Integration Error";
public static final String NEW_VULNERABILITY = "New Vulnerability Identified";
public static final String VULNERABILITY_UPDATED = "Change in Severity of a Vulnerability";
public static final String NEW_VULNERABLE_DEPENDENCY = "Vulnerable Dependency Introduced";
public static final String VULNERABILITY_UPDATED = "Vulnerability Updated";
public static final String ANALYSIS_DECISION_EXPLOITABLE = "Analysis Decision: Exploitable";
public static final String ANALYSIS_DECISION_IN_TRIAGE = "Analysis Decision: In Triage";
public static final String ANALYSIS_DECISION_FALSE_POSITIVE = "Analysis Decision: False Positive";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public enum NotificationGroup {
// Portfolio Groups
NEW_VULNERABILITY,
NEW_VULNERABLE_DEPENDENCY,
VULNERABILITY_UPDATED,
PROJECT_VULNERABILITY_UPDATED,
//NEW_OUTDATED_COMPONENT,
//FIXED_VULNERABILITY,
//FIXED_OUTDATED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.dependencytrack.model.NotificationPublisher;
import org.dependencytrack.model.NotificationRule;
import org.dependencytrack.model.Project;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.ComponentIdentity;
import org.dependencytrack.notification.publisher.PublishContext;
import org.dependencytrack.notification.publisher.Publisher;
import org.dependencytrack.notification.publisher.SendMailPublisher;
Expand All @@ -38,7 +40,7 @@
import org.dependencytrack.notification.vo.PolicyViolationIdentified;
import org.dependencytrack.notification.vo.VexConsumedOrProcessed;
import org.dependencytrack.notification.vo.ViolationAnalysisDecisionChange;
import org.dependencytrack.notification.vo.VulnerabilityUpdate;
import org.dependencytrack.notification.vo.ProjectVulnerabilityUpdate;
import org.dependencytrack.persistence.QueryManager;

import jakarta.json.Json;
Expand Down Expand Up @@ -180,20 +182,29 @@ List<NotificationRule> resolveRules(final PublishContext ctx, final Notification
}
}
} else if (NotificationScope.PORTFOLIO.name().equals(notification.getScope())
&& notification.getSubject() instanceof final VulnerabilityUpdate subject) {
&& notification.getSubject() instanceof final ProjectVulnerabilityUpdate subject) {
for (final NotificationRule rule: result) {
// As above, reduce the execution of the notification down to those projects that the rule matches.
// As we only emit a single notification per vulnerability, we need to check if any affected component
// matches the rule projects, not just the component included in the notification subject.
if (rule.getNotifyOn().contains(NotificationGroup.valueOf(notification.getGroup()))) {
if (rule.getProjects() != null && rule.getProjects().size() > 0
&& subject.getComponent() != null) {
if (subject.getComponent().getProject() != null) {
for (final Project project : rule.getProjects()) {
if (subject.getComponent().getProject().getUuid().equals(project.getUuid()) || (Boolean.TRUE.equals(rule.isNotifyChildren() && checkIfChildrenAreAffected(project, subject.getComponent().getProject().getUuid())))) {
rules.add(rule);
if (subject.getComponent() != null) {
final List<Component> components = qm.matchIdentity(new ComponentIdentity(subject.getComponent()));
if (components != null && !components.isEmpty()) {
if (rule.getProjects() != null && !rule.getProjects().isEmpty()) {
for (final Component component : components) {
if (component.getProject() != null) {
for (final Project project : rule.getProjects()) {
if (component.getProject().getUuid().equals(project.getUuid()) || (Boolean.TRUE.equals(rule.isNotifyChildren() && checkIfChildrenAreAffected(project, component.getProject().getUuid())))) {
rules.add(rule);
}
}
}
}
} else {
rules.add(rule);
}
}
} else {
rules.add(rule);
}
}
}
Expand Down
Loading

0 comments on commit 91332a2

Please sign in to comment.