Skip to content

Commit 702cb3d

Browse files
authored
Merge pull request #1515 from DependencyTrack/notification-router
2 parents 5e35ac1 + 060f032 commit 702cb3d

File tree

12 files changed

+878
-25
lines changed

12 files changed

+878
-25
lines changed

apiserver/src/main/java/org/dependencytrack/model/NotificationRule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import javax.jdo.annotations.Column;
3838
import javax.jdo.annotations.Element;
3939
import javax.jdo.annotations.Extension;
40+
import javax.jdo.annotations.Extensions;
4041
import javax.jdo.annotations.ForeignKey;
4142
import javax.jdo.annotations.ForeignKeyAction;
4243
import javax.jdo.annotations.IdGeneratorStrategy;
@@ -110,6 +111,10 @@ public class NotificationRule implements Serializable {
110111

111112
@Persistent(defaultFetchGroup = "true")
112113
@Column(name = "NOTIFICATION_LEVEL", jdbcType = "VARCHAR")
114+
@Extensions(value = {
115+
@Extension(vendorName = "datanucleus", key = "insert-function", value = "CAST(? AS notification_level)"),
116+
@Extension(vendorName = "datanucleus", key = "update-function", value = "CAST(? AS notification_level)")
117+
})
113118
private NotificationLevel notificationLevel;
114119

115120
@Persistent(table = "NOTIFICATIONRULE_PROJECTS", defaultFetchGroup = "true")

apiserver/src/main/java/org/dependencytrack/notification/NotificationFactory.java

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
*/
1919
package org.dependencytrack.notification;
2020

21-
import alpine.model.LdapUser;
22-
import alpine.model.ManagedUser;
23-
import alpine.model.OidcUser;
2421
import com.fasterxml.uuid.Generators;
2522
import com.fasterxml.uuid.impl.TimeBasedEpochRandomGenerator;
2623
import com.google.protobuf.Any;
@@ -46,6 +43,7 @@
4643
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisCompleteSubject;
4744
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisStatus;
4845
import org.dependencytrack.proto.notification.v1.Scope;
46+
import org.dependencytrack.proto.notification.v1.UserSubject;
4947
import org.dependencytrack.proto.notification.v1.VexConsumedOrProcessedSubject;
5048
import org.dependencytrack.proto.notification.v1.Vulnerability;
5149
import org.dependencytrack.proto.notification.v1.VulnerabilityAnalysis;
@@ -453,33 +451,29 @@ public static Notification createUserCreatedNotification(
453451
final alpine.model.User user) {
454452
requireNonNull(user, "user must not be null");
455453

454+
return createUserCreatedNotification(convert(user));
455+
}
456+
457+
static Notification createUserCreatedNotification(final UserSubject user) {
456458
return newNotificationBuilder(SCOPE_SYSTEM, GROUP_USER_CREATED, LEVEL_INFORMATIONAL)
457459
.setTitle("User Created")
458-
.setContent(switch (user) {
459-
case LdapUser ignored -> "LDAP";
460-
case ManagedUser ignored -> "Managed";
461-
case OidcUser ignored -> "OpenID Connect";
462-
default -> throw new IllegalStateException(
463-
"Unexpected user type: " + user.getClass());
464-
} + " user created")
465-
.setSubject(Any.pack(convert(user)))
460+
.setContent("User %s was created".formatted(user.getUsername()))
461+
.setSubject(Any.pack(user))
466462
.build();
467463
}
468464

469465
public static Notification createUserDeletedNotification(
470466
final alpine.model.User user) {
471467
requireNonNull(user, "user must not be null");
472468

469+
return createUserDeletedNotification(convert(user));
470+
}
471+
472+
static Notification createUserDeletedNotification(final UserSubject user) {
473473
return newNotificationBuilder(SCOPE_SYSTEM, GROUP_USER_DELETED, LEVEL_INFORMATIONAL)
474474
.setTitle("User Deleted")
475-
.setContent(switch (user) {
476-
case LdapUser ignored -> "LDAP";
477-
case ManagedUser ignored -> "Managed";
478-
case OidcUser ignored -> "OpenID Connect";
479-
default -> throw new IllegalStateException(
480-
"Unexpected user type: " + user.getClass());
481-
} + " user deleted")
482-
.setSubject(Any.pack(convert(user)))
475+
.setContent("User %s was deleted".formatted(user.getUsername()))
476+
.setSubject(Any.pack(user))
483477
.build();
484478
}
485479

apiserver/src/main/java/org/dependencytrack/notification/NotificationOutboxRelay.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ final class NotificationOutboxRelay implements Closeable {
6969

7070
private final KafkaEventDispatcher delegateDispatcher;
7171
private final MeterRegistry meterRegistry;
72+
private final boolean routerEnabled;
7273
private final long pollIntervalMillis;
7374
private final int batchSize;
7475
private final BlockingQueue<Notification> currentBatch;
@@ -83,6 +84,7 @@ final class NotificationOutboxRelay implements Closeable {
8384
public NotificationOutboxRelay(
8485
final KafkaEventDispatcher delegateDispatcher,
8586
final MeterRegistry meterRegistry,
87+
final boolean routerEnabled,
8688
final long pollIntervalMillis,
8789
final int batchSize) {
8890
this.delegateDispatcher = requireNonNull(delegateDispatcher, "delegate dispatcher must not be null");
@@ -93,6 +95,7 @@ public NotificationOutboxRelay(
9395
if (batchSize <= 0) {
9496
throw new IllegalArgumentException("batchSize must be greater than 0");
9597
}
98+
this.routerEnabled = routerEnabled;
9699
this.pollIntervalMillis = pollIntervalMillis;
97100
this.batchSize = batchSize;
98101
this.currentBatch = new ArrayBlockingQueue<>(batchSize);
@@ -222,6 +225,18 @@ private RelayCycleOutcome executeRelayCycle() {
222225
return RelayCycleOutcome.COMPLETED;
223226
}
224227

228+
if (routerEnabled) {
229+
try {
230+
final List<NotificationPublishTask> publishTasks =
231+
new NotificationRouter(handle, meterRegistry).route(currentBatch);
232+
LOGGER.debug("Router generated {} publish tasks", publishTasks.size());
233+
} catch (RuntimeException e) {
234+
LOGGER.warn("""
235+
Router failed, but since routing results are not currently used,
236+
the failure is ignored. If it continues to fail, consider disabling the router.""", e);
237+
}
238+
}
239+
225240
final Timer.Sample sendLatencySample = Timer.start();
226241
try {
227242
sendAll(currentBatch);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* This file is part of Dependency-Track.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* Copyright (c) OWASP Foundation. All Rights Reserved.
18+
*/
19+
package org.dependencytrack.notification;
20+
21+
import org.dependencytrack.proto.notification.v1.Notification;
22+
23+
/**
24+
* Unit of work for publishing a notification.
25+
*
26+
* @param ruleId ID of the applicable notification rule.
27+
* @param ruleName Name of the applicable notification rule.
28+
* @param notification The notification to publish.
29+
* @since 5.7.0
30+
*/
31+
record NotificationPublishTask(
32+
long ruleId,
33+
String ruleName,
34+
Notification notification) {
35+
}

0 commit comments

Comments
 (0)