Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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 @@ -39,6 +39,7 @@ public enum ConfigPropertyConstants {
EMAIL_SMTP_PASSWORD("email", "smtp.password", null, PropertyType.ENCRYPTEDSTRING, "The optional password for the username used for authentication"),
EMAIL_SMTP_SSLTLS("email", "smtp.ssltls", "false", PropertyType.BOOLEAN, "Flag to enable/disable the use of SSL/TLS when connecting to the SMTP server"),
EMAIL_SMTP_TRUSTCERT("email", "smtp.trustcert", "false", PropertyType.BOOLEAN, "Flag to enable/disable the trust of the certificate presented by the SMTP server"),
EMAIL_SUBJECT_SHOW_LEVEL("email", "subject.show.level", "false", PropertyType.BOOLEAN,"If true, email subjects include the notification level"),
INTERNAL_COMPONENTS_GROUPS_REGEX("internal-components", "groups.regex", null, PropertyType.STRING, "Regex that matches groups of internal components"),
INTERNAL_COMPONENTS_NAMES_REGEX("internal-components", "names.regex", null, PropertyType.STRING, "Regex that matches names of internal components"),
INTERNAL_COMPONENTS_MATCH_MODE("internal-components", "match-mode", "OR", PropertyType.STRING, "Determines how internal component regexes are combined: OR (default) or AND"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SMTP_SSLTLS;
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SMTP_TRUSTCERT;
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SMTP_USERNAME;
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SUBJECT_SHOW_LEVEL;

public class SendMailPublisher implements Publisher {

Expand Down Expand Up @@ -98,7 +99,9 @@ private void sendNotification(final PublishContext ctx, Notification notificatio
final String encryptedSmtpPassword;
final boolean smtpSslTls;
final boolean smtpTrustCert;
final boolean showLevel;
String emailSubjectPrefix;
String subject;

try (QueryManager qm = new QueryManager()) {
smtpEnabled = qm.isEnabled(EMAIL_SMTP_ENABLED);
Expand All @@ -116,6 +119,11 @@ private void sendNotification(final PublishContext ctx, Notification notificatio
encryptedSmtpPassword = qm.getConfigProperty(EMAIL_SMTP_PASSWORD.getGroupName(), EMAIL_SMTP_PASSWORD.getPropertyName()).getPropertyValue();
smtpSslTls = qm.isEnabled(EMAIL_SMTP_SSLTLS);
smtpTrustCert = qm.isEnabled(EMAIL_SMTP_TRUSTCERT);
showLevel = qm.isEnabled(EMAIL_SUBJECT_SHOW_LEVEL);
subject = emailSubjectPrefix.trim()
+ (showLevel ? " [" + ctx.notificationLevel() + "] " : " ")
+ notification.getTitle();

} catch (RuntimeException e) {
LOGGER.error("Failed to load SMTP configuration from datastore (%s)".formatted(ctx), e);
return;
Expand All @@ -130,12 +138,12 @@ private void sendNotification(final PublishContext ctx, Notification notificatio
return;
}
String unescapedContent = StringEscapeUtils.unescapeHtml4(content);

try {
final SendMail sendMail = new SendMail()
.from(smtpFrom)
.to(destinations)
.subject(emailSubjectPrefix + " " + notification.getTitle())
.subject(subject)
.body(MediaType.TEXT_HTML.equals(mimeType) ? StringEscapeUtils.escapeHtml4(unescapedContent) : unescapedContent)
.bodyMimeType(mimeType)
.host(smtpHostname)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SMTP_SSLTLS;
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SMTP_TRUSTCERT;
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SMTP_USERNAME;
import static org.dependencytrack.model.ConfigPropertyConstants.EMAIL_SUBJECT_SHOW_LEVEL;

class SendMailPublisherTest extends AbstractPublisherTest<SendMailPublisher> {

Expand Down Expand Up @@ -121,6 +122,13 @@ public void setUp() throws Exception {
EMAIL_SMTP_TRUSTCERT.getPropertyType(),
EMAIL_SMTP_TRUSTCERT.getDescription()
);
qm.createConfigProperty(
EMAIL_SUBJECT_SHOW_LEVEL.getGroupName(),
EMAIL_SUBJECT_SHOW_LEVEL.getPropertyName(),
"true",
EMAIL_SUBJECT_SHOW_LEVEL.getPropertyType(),
EMAIL_SUBJECT_SHOW_LEVEL.getDescription()
);
}

@Test
Expand All @@ -129,7 +137,7 @@ public void testMailSubjectIsSetCorrectly() {

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message ->
assertThat(message.getSubject())
.isEqualTo("[Dependency-Track] New Vulnerability Identified on Project: [projectName : projectVersion]")
.isEqualTo("[Dependency-Track] [INFORMATIONAL] New Vulnerability Identified on Project: [projectName : projectVersion]")
);
}

Expand All @@ -138,7 +146,7 @@ public void testInformWithBomConsumedNotification() {
super.baseTestInformWithBomConsumedNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Bill of Materials Consumed");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [INFORMATIONAL] Bill of Materials Consumed");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -170,7 +178,7 @@ public void testInformWithBomProcessingFailedNotification() {
super.baseTestInformWithBomProcessingFailedNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Bill of Materials Processing Failed");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [ERROR] Bill of Materials Processing Failed");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -206,7 +214,7 @@ public void testInformWithBomValidationFailedNotification() {
super.baseTestInformWithBomValidationFailedNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Bill of Materials Validation Failed");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [ERROR] Bill of Materials Validation Failed");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -238,7 +246,7 @@ public void testInformWithBomProcessingFailedNotificationAndNoSpecVersionInSubje
super.baseTestInformWithBomProcessingFailedNotificationAndNoSpecVersionInSubject();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Bill of Materials Processing Failed");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [ERROR] Bill of Materials Processing Failed");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -274,7 +282,7 @@ public void testInformWithDataSourceMirroringNotification() {
super.baseTestInformWithDataSourceMirroringNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] GitHub Advisory Mirroring");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [ERROR] GitHub Advisory Mirroring");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -304,7 +312,7 @@ public void testInformWithNewVulnerabilityNotification() {
super.baseTestInformWithNewVulnerabilityNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] New Vulnerability Identified on Project: [projectName : projectVersion]");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [INFORMATIONAL] New Vulnerability Identified on Project: [projectName : projectVersion]");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -341,7 +349,7 @@ public void testPublishWithScheduledNewVulnerabilitiesNotification() {
super.baseTestPublishWithScheduledNewVulnerabilitiesNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] New Vulnerabilities Summary");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [INFORMATIONAL] New Vulnerabilities Summary");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -399,7 +407,7 @@ public void testPublishWithScheduledNewPolicyViolationsNotification() {
super.baseTestPublishWithScheduledNewPolicyViolationsNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] New Policy Violations Summary");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [INFORMATIONAL] New Policy Violations Summary");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -458,7 +466,7 @@ public void testInformWithNewVulnerableDependencyNotification() {
super.baseTestInformWithNewVulnerableDependencyNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Vulnerable Dependency Introduced");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [INFORMATIONAL] Vulnerable Dependency Introduced");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -500,7 +508,7 @@ public void testInformWithProjectAuditChangeNotification() {
super.baseTestInformWithProjectAuditChangeNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Analysis Decision: Finding Suppressed");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [INFORMATIONAL] Analysis Decision: Finding Suppressed");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -541,7 +549,7 @@ public void testInformWithEscapedData() {
super.baseTestInformWithEscapedData();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> {
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Notification Test");
assertThat(message.getSubject()).isEqualTo("[Dependency-Track] [ERROR] Notification Test");
assertThat(message.getContent()).isInstanceOf(MimeMultipart.class);
final MimeMultipart content = (MimeMultipart) message.getContent();
assertThat(content.getCount()).isEqualTo(1);
Expand Down Expand Up @@ -954,6 +962,21 @@ void testEmptyOidcUsersAsDestination() {
"steve@jobs.org");
}

@Test
public void testMailSubjectWithoutLevelWhenDisabled() {
qm.getConfigProperty(
EMAIL_SUBJECT_SHOW_LEVEL.getGroupName(),
EMAIL_SUBJECT_SHOW_LEVEL.getPropertyName())
.setPropertyValue("false");

super.baseTestInformWithNewVulnerabilityNotification();

assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message ->
assertThat(message.getSubject())
.isEqualTo("[Dependency-Track] New Vulnerability Identified on Project: [projectName : projectVersion]")
);
}

private NotificationRule createNotificationRule() {
final NotificationPublisher publisher = qm.createNotificationPublisher(
DefaultNotificationPublishers.EMAIL.getPublisherName(),
Expand Down
Loading