Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port: Webhook alert token and new user alerts #1338

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@ public enum NotificationGroup {
VEX_PROCESSED,
POLICY_VIOLATION,
PROJECT_CREATED,
PROJECT_VULN_ANALYSIS_COMPLETE
PROJECT_VULN_ANALYSIS_COMPLETE,
USER_CREATED,
USER_DELETED
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum KafkaTopic {
NOTIFICATION_PROJECT_AUDIT_CHANGE("dtrack.notification.project-audit-change"),
NOTIFICATION_REPOSITORY("dtrack.notification.repository"),
NOTIFICATION_VEX("dtrack.notification.vex"),
NOTIFICATION_USER("dtrack.notification.user"),
REPO_META_ANALYSIS_COMMAND("dtrack.repo-meta-analysis.component"),
REPO_META_ANALYSIS_RESULT("dtrack.repo-meta-analysis.result"),
VULN_ANALYSIS_SCANNER_RESULT("dtrack.vuln-analysis.scanner.result"),
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ services:
valueProtoType: org.cyclonedx.v1_4.Bom
- topicName: dtrack.epss
valueProtoType: org.dependencytrack.mirror.v1.EpssItem
- topicName: dtrack.notification.user
valueProtoType: org.dependencytrack.notification.v1.Notification
fileSystem:
enabled: true
paths: ["/etc/protos"]
Expand Down
1 change: 1 addition & 0 deletions docs/reference/topics.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
| `dtrack.notification.project-created` | 3 | |
| `dtrack.notification.repository` | 3 | |
| `dtrack.notification.vex` | 3 | |
| `dtrack.notification.user` | 3 | |
| `dtrack.notification.project-vuln-analysis-complete` <sup>3</sup> | 3 | `cleanup.policy=compact`<br/>`segment.bytes=67108864`<br/>`max.compaction.lag.ms=0` |
| `dtrack.repo-meta-analysis.component`<sup>1A</sup> | 3 | |
| `dtrack.repo-meta-analysis.result` | 3 | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public static class Title {
public static final String BOM_PROCESSING_FAILED = "Bill of Materials Processing Failed";
public static final String VEX_CONSUMED = "Vulnerability Exploitability Exchange (VEX) Consumed";
public static final String VEX_PROCESSED = "Vulnerability Exploitability Exchange (VEX) Processed";
public static final String USER_CREATED = "User Created";
public static final String USER_DELETED = "User Deleted";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisCompleteSubject;
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisStatus;
import org.dependencytrack.proto.notification.v1.Scope;
import org.dependencytrack.proto.notification.v1.UserPrincipalSubject;
import org.dependencytrack.proto.notification.v1.VexConsumedOrProcessedSubject;
import org.dependencytrack.proto.notification.v1.Vulnerability;
import org.dependencytrack.proto.notification.v1.VulnerabilityAnalysis;
Expand Down Expand Up @@ -73,6 +74,7 @@
PolicyViolationSubject.class,
Project.class,
ProjectVulnAnalysisCompleteSubject.class,
UserPrincipalSubject.class,
ProjectVulnAnalysisStatus.class,
Scope.class,
Timestamp.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public void publish(final PublishContext ctx, final PebbleTemplate template, fin
} else {
request.addHeader("Authorization", "Bearer " + credentials.password);
}
} else if (getToken(config) != null) {
request.addHeader(getTokenHeader(config), getToken(config));
}

StringEntity entity = new StringEntity(content);
Expand Down Expand Up @@ -109,5 +111,13 @@ protected record AuthCredentials(String user, String password) {
protected String getDestinationUrl(final JsonObject config) {
return config.getString(CONFIG_DESTINATION, null);
}

protected String getToken(final JsonObject config) {
return config.getString(CONFIG_TOKEN, null);
}

protected String getTokenHeader(final JsonObject config) {
return config.getString(CONFIG_TOKEN_HEADER, "X-Api-Key");
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.dependencytrack.proto.notification.v1.PolicyViolationAnalysisDecisionChangeSubject;
import org.dependencytrack.proto.notification.v1.PolicyViolationSubject;
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisCompleteSubject;
import org.dependencytrack.proto.notification.v1.UserPrincipalSubject;
import org.dependencytrack.proto.notification.v1.VexConsumedOrProcessedSubject;
import org.dependencytrack.proto.notification.v1.VulnerabilityAnalysisDecisionChangeSubject;

Expand Down Expand Up @@ -129,6 +130,9 @@ public static PublishContext fromRecord(final ConsumerRecord<String, Notificatio
} else if (notification.getSubject().is(VexConsumedOrProcessedSubject.class)) {
final VexConsumedOrProcessedSubject subject = notification.getSubject().unpack(VexConsumedOrProcessedSubject.class);
notificationSubjects.put(SUBJECT_PROJECT, Project.convert(subject.getProject()));
} else if (notification.getSubject().is(UserPrincipalSubject.class)) {
final UserPrincipalSubject subject = notification.getSubject().unpack(UserPrincipalSubject.class);
notificationSubjects.put("User", subject);
sahibamittal marked this conversation as resolved.
Show resolved Hide resolved
}

return new PublishContext(consumerRecord.topic(), consumerRecord.partition(), consumerRecord.offset(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.dependencytrack.proto.notification.v1.PolicyViolationAnalysisDecisionChangeSubject;
import org.dependencytrack.proto.notification.v1.PolicyViolationSubject;
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisCompleteSubject;
import org.dependencytrack.proto.notification.v1.UserPrincipalSubject;
import org.dependencytrack.proto.notification.v1.VexConsumedOrProcessedSubject;
import org.dependencytrack.proto.notification.v1.VulnerabilityAnalysisDecisionChangeSubject;
import org.eclipse.microprofile.config.ConfigProvider;
Expand All @@ -42,6 +43,7 @@
import java.util.Map;

import static org.dependencytrack.proto.notification.v1.Scope.SCOPE_PORTFOLIO;
import static org.dependencytrack.proto.notification.v1.Scope.SCOPE_SYSTEM;

public interface Publisher {

Expand All @@ -51,6 +53,10 @@

String CONFIG_DESTINATION = "destination";

String CONFIG_TOKEN = "token";

String CONFIG_TOKEN_HEADER = "tokenHeader";


void inform(final PublishContext ctx, final Notification notification, final JsonObject config) throws Exception;

Expand Down Expand Up @@ -125,6 +131,13 @@
context.put("subjectJson", JsonFormat.printer().print(subject));
}
}
else if (notification.getScope() == SCOPE_SYSTEM) {
if (notification.getSubject().is(UserPrincipalSubject.class)) {

Check warning on line 135 in notification-publisher/src/main/java/org/dependencytrack/notification/publisher/Publisher.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

notification-publisher/src/main/java/org/dependencytrack/notification/publisher/Publisher.java#L135

These nested if statements could be combined
final var subject = notification.getSubject().unpack(UserPrincipalSubject.class);
context.put("subject", subject);
context.put("subjectJson", JsonFormat.printer().print(subject));
}
}

enrichTemplateContext(context, config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public static NotificationGroup convert(final Group group) {
case GROUP_POLICY_VIOLATION -> NotificationGroup.POLICY_VIOLATION;
case GROUP_PROJECT_CREATED -> NotificationGroup.PROJECT_CREATED;
case GROUP_PROJECT_VULN_ANALYSIS_COMPLETE -> NotificationGroup.PROJECT_VULN_ANALYSIS_COMPLETE;
case GROUP_USER_CREATED -> NotificationGroup.USER_CREATED;
case GROUP_USER_DELETED -> NotificationGroup.USER_DELETED;
default -> throw new IllegalArgumentException("Unknown group: " + group);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ public void testConstants() {
Assertions.assertEquals("Analysis Decision: Finding Suppressed", NotificationConstants.Title.ANALYSIS_DECISION_SUPPRESSED);
Assertions.assertEquals("Analysis Decision: Finding UnSuppressed", NotificationConstants.Title.ANALYSIS_DECISION_UNSUPPRESSED);
Assertions.assertEquals("Analysis Decision: Finding Resolved", NotificationConstants.Title.ANALYSIS_DECISION_RESOLVED);
Assertions.assertEquals("User Created", NotificationConstants.Title.USER_CREATED);
Assertions.assertEquals("User Deleted", NotificationConstants.Title.USER_DELETED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.dependencytrack.proto.notification.v1.PolicyViolationAnalysisDecisionChangeSubject;
import org.dependencytrack.proto.notification.v1.PolicyViolationSubject;
import org.dependencytrack.proto.notification.v1.Project;
import org.dependencytrack.proto.notification.v1.UserPrincipalSubject;
import org.dependencytrack.proto.notification.v1.VexConsumedOrProcessedSubject;
import org.dependencytrack.proto.notification.v1.Vulnerability;
import org.dependencytrack.proto.notification.v1.VulnerabilityAnalysisDecisionChangeSubject;
Expand All @@ -62,10 +63,12 @@
import static org.dependencytrack.proto.notification.v1.Group.GROUP_NEW_VULNERABLE_DEPENDENCY;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_POLICY_VIOLATION;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_PROJECT_AUDIT_CHANGE;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_USER_CREATED;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_VEX_CONSUMED;
import static org.dependencytrack.proto.notification.v1.Level.LEVEL_ERROR;
import static org.dependencytrack.proto.notification.v1.Level.LEVEL_INFORMATIONAL;
import static org.dependencytrack.proto.notification.v1.Scope.SCOPE_PORTFOLIO;
import static org.dependencytrack.proto.notification.v1.Scope.SCOPE_SYSTEM;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -836,6 +839,30 @@
verify(consolePublisherMock).inform(any(), eq(notification), any());
}

@Test
@TestTransaction
void testResolveRulesUserCreatedNotification() throws Exception {

final Long publisherId = createConsolePublisher();
createRule("Limit To Test Rule",
NotificationScope.SYSTEM, NotificationLevel.INFORMATIONAL,
NotificationGroup.USER_CREATED, publisherId);

final var notificationUser = Notification.newBuilder()
.setScope(SCOPE_SYSTEM)
.setGroup(GROUP_USER_CREATED)
.setLevel(LEVEL_INFORMATIONAL)
.setSubject(Any.pack(UserPrincipalSubject.newBuilder()
.setUsername("username")
.setEmail("email.com")
.build()))
.build();

Assertions.assertThat(notificationRouter.resolveRules(PublisherTestUtil.createPublisherContext(notificationUser), notificationUser)).satisfiesExactly(

Check notice on line 861 in notification-publisher/src/test/java/org/dependencytrack/notification/NotificationRouterTest.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

notification-publisher/src/test/java/org/dependencytrack/notification/NotificationRouterTest.java#L861

Unnecessary use of fully qualified name 'Assertions.assertThat' due to existing static import 'org.assertj.core.api.Assertions.assertThat'
rule -> Assertions.assertThat(rule.getName()).isEqualTo("Limit To Test Rule")
);
}

private Long createConsolePublisher() {
return (Long) entityManager.createNativeQuery("""
INSERT INTO "NOTIFICATIONPUBLISHER" ("DEFAULT_PUBLISHER", "NAME", "PUBLISHER_CLASS", "TEMPLATE", "TEMPLATE_MIME_TYPE", "UUID") VALUES
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.dependencytrack.proto.notification.v1.PolicyViolationSubject;
import org.dependencytrack.proto.notification.v1.Project;
import org.dependencytrack.proto.notification.v1.ProjectVulnAnalysisCompleteSubject;
import org.dependencytrack.proto.notification.v1.UserPrincipalSubject;
import org.dependencytrack.proto.notification.v1.VexConsumedOrProcessedSubject;
import org.dependencytrack.proto.notification.v1.VulnerabilityAnalysisDecisionChangeSubject;
import org.junit.jupiter.api.Nested;
Expand All @@ -49,10 +50,12 @@
import static org.dependencytrack.proto.notification.v1.Group.GROUP_PROJECT_AUDIT_CHANGE;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_PROJECT_CREATED;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_PROJECT_VULN_ANALYSIS_COMPLETE;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_USER_CREATED;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_VEX_CONSUMED;
import static org.dependencytrack.proto.notification.v1.Group.GROUP_VEX_PROCESSED;
import static org.dependencytrack.proto.notification.v1.Level.LEVEL_INFORMATIONAL;
import static org.dependencytrack.proto.notification.v1.Scope.SCOPE_PORTFOLIO;
import static org.dependencytrack.proto.notification.v1.Scope.SCOPE_SYSTEM;

class PublishContextTest {

Expand Down Expand Up @@ -512,6 +515,34 @@ void testWithVexProcessedSubject() throws Exception {
});
}

@Test
void testWithUserPrincipalSubject() throws Exception {
final var notification = Notification.newBuilder()
.setGroup(GROUP_USER_CREATED)
.setLevel(LEVEL_INFORMATIONAL)
.setScope(SCOPE_SYSTEM)
.setTimestamp(Timestamps.fromSeconds(666))
.setSubject(Any.pack(UserPrincipalSubject.newBuilder()
.setUsername("username")
.setEmail("email.com")
.build()))
.build();

final PublishContext ctx = PublishContext.fromRecord(new ConsumerRecord<>("topic", 1, 2L, "key", notification));
assertThat(ctx.kafkaTopic()).isEqualTo("topic");
assertThat(ctx.kafkaTopicPartition()).isEqualTo(1);
assertThat(ctx.kafkaPartitionOffset()).isEqualTo(2L);
assertThat(ctx.notificationGroup()).isEqualTo("GROUP_USER_CREATED");
assertThat(ctx.notificationLevel()).isEqualTo("LEVEL_INFORMATIONAL");
assertThat(ctx.notificationScope()).isEqualTo("SCOPE_SYSTEM");
assertThat(ctx.notificationTimestamp()).isEqualTo("1970-01-01T00:11:06.000Z");
assertThat(ctx.notificationSubjects())
.hasEntrySatisfying("User", userObj -> {
final var user = (UserPrincipalSubject) userObj;
assertThat(user.getUsername()).isEqualTo("username");
assertThat(user.getEmail()).isEqualTo("email.com");
});
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ enum Group {
GROUP_PROJECT_CREATED = 16;
GROUP_BOM_PROCESSING_FAILED = 17;
GROUP_PROJECT_VULN_ANALYSIS_COMPLETE = 18;
GROUP_USER_CREATED = 19;
GROUP_USER_DELETED = 20;

// Indexing service has been removed as of
// https://github.com/DependencyTrack/hyades/issues/661
Expand Down Expand Up @@ -216,6 +218,11 @@ message ProjectVulnAnalysisCompleteSubject {
string token = 4;
}

message UserPrincipalSubject {
string username = 1;
string email = 2;
sahibamittal marked this conversation as resolved.
Show resolved Hide resolved
}

enum ProjectVulnAnalysisStatus {
PROJECT_VULN_ANALYSIS_STATUS_UNSPECIFIED = 0;
PROJECT_VULN_ANALYSIS_STATUS_FAILED = 1;
Expand Down
1 change: 1 addition & 0 deletions scripts/create-topics.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ notification_topics=(
"${KAFKA_TOPIC_PREFIX:-}dtrack.notification.project-vuln-analysis-complete"
"${KAFKA_TOPIC_PREFIX:-}dtrack.notification.repository"
"${KAFKA_TOPIC_PREFIX:-}dtrack.notification.vex"
"${KAFKA_TOPIC_PREFIX:-}dtrack.notification.user"
)
for topic_name in "${notification_topics[@]}"; do
create_topic "$topic_name" "${NOTIFICATION_TOPICS_PARTITIONS:-1}" "retention.ms=${NOTIFICATION_TOPICS_RETENTION_MS:-43200000}"
Expand Down
Loading