Skip to content

Commit 4175ecb

Browse files
committed
Add deduplicationOnEngagement
Signed-off-by: Martin Wrona <martin.wrona@digitecgalaxus.ch>
1 parent e1bbec9 commit 4175ecb

4 files changed

Lines changed: 37 additions & 6 deletions

File tree

docs/_docs/integrations/defectdojo.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ Enable auto-create by setting the following configuration property:
119119
| `defectdojo.autocreate.enabled` | `false` | Enable/disable auto context creation |
120120
| `defectdojo.autocreate.engagementName` | `dependencytrack` | Default engagement name for all projects |
121121
| `defectdojo.autocreate.productTypeName` | `Dependency Track` | Default product type name for all projects |
122+
| `defectdojo.autocreate.deduplicationOnEngagement` | `false` | Enable deduplication at engagement level instead of product level |
123+
124+
**About Deduplication:**
125+
By default, DefectDojo deduplicates findings at the **Product level**, meaning duplicate findings are identified across all engagements within a product. Setting `deduplicationOnEngagement` to `true` changes this to deduplicate at the **Engagement level** instead, isolating duplicate detection within each engagement.
122126

123127
#### Per-project Property Overrides (Optional)
124128

@@ -145,6 +149,13 @@ You can override the default names on a per-project basis:
145149
| Property Value | Custom product type name (defaults to global config if not set) |
146150
| Property Type | `STRING` |
147151

152+
| Attribute | Value |
153+
| ---------------| --------------------------------- |
154+
| Group Name | `integrations` |
155+
| Property Name | `defectdojo.autocreate.deduplicationOnEngagement` |
156+
| Property Value | `true` or `false` (defaults to global config if not set) |
157+
| Property Type | `BOOLEAN` |
158+
148159
#### Configuration Priority
149160

150161
The configuration follows this priority order:

src/main/java/org/dependencytrack/integrations/defectdojo/DefectDojoClient.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ public DefectDojoClient(final DefectDojoUploader uploader, final URL baseURL) {
5656
}
5757

5858
public void uploadDependencyTrackFindings(final String token, final String engagementId, final InputStream findingsJson, final Boolean verifyFindings, final String testTitle) {
59-
uploadDependencyTrackFindings(token, engagementId, findingsJson, verifyFindings, testTitle, null, null, null, false);
59+
uploadDependencyTrackFindings(token, engagementId, findingsJson, verifyFindings, testTitle, null, null, null, false, false);
6060
}
6161

6262
public void uploadDependencyTrackFindings(final String token, final String engagementId, final InputStream findingsJson, final Boolean verifyFindings, final String testTitle,
63-
final String productTypeName, final String productName, final String engagementName, final boolean autoCreateContext) {
63+
final String productTypeName, final String productName, final String engagementName, final boolean autoCreateContext, final boolean deduplicationOnEngagement) {
6464
LOGGER.debug("Uploading Dependency-Track findings to DefectDojo");
6565
HttpPost request = new HttpPost(baseURL + "/api/v2/import-scan/");
6666
InputStreamBody inputStreamBody = new InputStreamBody(findingsJson, ContentType.APPLICATION_OCTET_STREAM, "findings.json");
@@ -80,6 +80,7 @@ public void uploadDependencyTrackFindings(final String token, final String engag
8080
if (autoCreateContext) {
8181
// Use auto_create_context with product and engagement names
8282
builder.addPart("auto_create_context", new StringBody("true", ContentType.MULTIPART_FORM_DATA));
83+
builder.addPart("deduplication_on_engagement", new StringBody(Boolean.toString(deduplicationOnEngagement), ContentType.MULTIPART_FORM_DATA));
8384
if (productTypeName != null) {
8485
builder.addPart("product_type_name", new StringBody(productTypeName, ContentType.MULTIPART_FORM_DATA));
8586
}
@@ -183,15 +184,15 @@ public ArrayList<String> jsonToList(final JSONArray jsonArray) {
183184
}
184185

185186
public void reimportDependencyTrackFindings(final String token, final String engagementId, final InputStream findingsJson, final String testId, final Boolean doNotReactivate, final Boolean verifyFindings, final String testTitle) {
186-
reimportDependencyTrackFindings(token, engagementId, findingsJson, testId, doNotReactivate, verifyFindings, testTitle, null, null, null, false);
187+
reimportDependencyTrackFindings(token, engagementId, findingsJson, testId, doNotReactivate, verifyFindings, testTitle, null, null, null, false, false);
187188
}
188189

189190
/*
190191
* A Reimport will reuse (overwrite) the existing test, instead of create a new test.
191192
* The Successfully reimport will also increase the reimport counter by 1.
192193
*/
193194
public void reimportDependencyTrackFindings(final String token, final String engagementId, final InputStream findingsJson, final String testId, final Boolean doNotReactivate, final Boolean verifyFindings, final String testTitle,
194-
final String productTypeName, final String productName, final String engagementName, final boolean autoCreateContext) {
195+
final String productTypeName, final String productName, final String engagementName, final boolean autoCreateContext, final boolean deduplicationOnEngagement) {
195196
LOGGER.debug("Reimporting Dependency-Track findings to DefectDojo");
196197
HttpPost request = new HttpPost(baseURL + "/api/v2/reimport-scan/");
197198
InputStreamBody inputStreamBody = new InputStreamBody(findingsJson, ContentType.APPLICATION_OCTET_STREAM, "findings.json");
@@ -212,6 +213,7 @@ public void reimportDependencyTrackFindings(final String token, final String eng
212213
if (autoCreateContext) {
213214
// Use auto_create_context with product and engagement names
214215
builder.addPart("auto_create_context", new StringBody("true", ContentType.MULTIPART_FORM_DATA));
216+
builder.addPart("deduplication_on_engagement", new StringBody(Boolean.toString(deduplicationOnEngagement), ContentType.MULTIPART_FORM_DATA));
215217
if (productTypeName != null) {
216218
builder.addPart("product_type_name", new StringBody(productTypeName, ContentType.MULTIPART_FORM_DATA));
217219
}

src/main/java/org/dependencytrack/integrations/defectdojo/DefectDojoUploader.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import static org.dependencytrack.model.ConfigPropertyConstants.DEFECTDOJO_AUTOCREATE_ENABLED;
4242
import static org.dependencytrack.model.ConfigPropertyConstants.DEFECTDOJO_AUTOCREATE_ENGAGEMENT_NAME;
4343
import static org.dependencytrack.model.ConfigPropertyConstants.DEFECTDOJO_AUTOCREATE_PRODUCT_TYPE_NAME;
44+
import static org.dependencytrack.model.ConfigPropertyConstants.DEFECTDOJO_AUTOCREATE_DEDUPLICATION_ON_ENGAGEMENT;
4445

4546
public class DefectDojoUploader extends AbstractIntegrationPoint implements ProjectFindingUploader {
4647

@@ -53,6 +54,7 @@ public class DefectDojoUploader extends AbstractIntegrationPoint implements Proj
5354
private static final String AUTOCREATE_PRODUCT_NAME_PROPERTY = "defectdojo.autocreate.productName";
5455
private static final String AUTOCREATE_ENGAGEMENT_NAME_PROPERTY = "defectdojo.autocreate.engagementName";
5556
private static final String AUTOCREATE_PRODUCT_TYPE_NAME_PROPERTY = "defectdojo.autocreate.productTypeName";
57+
private static final String AUTOCREATE_DEDUPLICATION_ON_ENGAGEMENT_PROPERTY = "defectdojo.autocreate.deduplicationOnEngagement";
5658

5759
public boolean isReimportConfigured(final Project project) {
5860
final ProjectProperty reimport = qm.getProjectProperty(project, DEFECTDOJO_ENABLED.getGroupName(), REIMPORT_PROPERTY);
@@ -127,6 +129,18 @@ public String getProductTypeName(final Project project) {
127129
return "Dependency Track";
128130
}
129131

132+
public boolean isDeduplicationOnEngagementEnabled(final Project project) {
133+
final ProjectProperty deduplicationOnEngagement = qm.getProjectProperty(project, DEFECTDOJO_ENABLED.getGroupName(), AUTOCREATE_DEDUPLICATION_ON_ENGAGEMENT_PROPERTY);
134+
if (deduplicationOnEngagement != null) {
135+
return Boolean.parseBoolean(deduplicationOnEngagement.getPropertyValue());
136+
}
137+
final ConfigProperty globalDeduplicationOnEngagement = qm.getConfigProperty(DEFECTDOJO_AUTOCREATE_DEDUPLICATION_ON_ENGAGEMENT.getGroupName(), DEFECTDOJO_AUTOCREATE_DEDUPLICATION_ON_ENGAGEMENT.getPropertyName());
138+
if (globalDeduplicationOnEngagement != null) {
139+
return Boolean.parseBoolean(globalDeduplicationOnEngagement.getPropertyValue());
140+
}
141+
return false;
142+
}
143+
130144
@Override
131145
public String name() {
132146
return "DefectDojo";
@@ -166,6 +180,7 @@ public void upload(final Project project, final InputStream payload) {
166180
final boolean globalReimportEnabled = qm.isEnabled(DEFECTDOJO_REIMPORT_ENABLED);
167181
final ProjectProperty engagementId = qm.getProjectProperty(project, DEFECTDOJO_ENABLED.getGroupName(), ENGAGEMENTID_PROPERTY);
168182
final boolean verifyFindings = isVerifiedConfigured(project);
183+
final boolean deduplicationOnEngagement = isDeduplicationOnEngagementEnabled(project);
169184

170185
try {
171186
final DefectDojoClient client = new DefectDojoClient(this, URI.create(defectDojoUrl.getPropertyValue()).toURL());
@@ -207,7 +222,8 @@ public void upload(final Project project, final InputStream payload) {
207222
productTypeName,
208223
productName,
209224
engagementName,
210-
true // Enable auto-create context
225+
true, // Enable auto-create context
226+
deduplicationOnEngagement
211227
);
212228
} else {
213229
// Use import-scan for first-time creation
@@ -221,7 +237,8 @@ public void upload(final Project project, final InputStream payload) {
221237
productTypeName,
222238
productName,
223239
engagementName,
224-
true // Enable auto-create context
240+
true, // Enable auto-create context
241+
deduplicationOnEngagement
225242
);
226243
}
227244
LOGGER.info("Successfully uploaded findings to DefectDojo with auto-created context");

src/main/java/org/dependencytrack/model/ConfigPropertyConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public enum ConfigPropertyConstants {
102102
DEFECTDOJO_AUTOCREATE_ENABLED("integrations", "defectdojo.autocreate.enabled", "false", PropertyType.BOOLEAN, "Flag to enable/disable DefectDojo auto context creation"),
103103
DEFECTDOJO_AUTOCREATE_ENGAGEMENT_NAME("integrations", "defectdojo.autocreate.engagementName", "dependencytrack", PropertyType.STRING, "Default engagement name for DefectDojo auto context creation"),
104104
DEFECTDOJO_AUTOCREATE_PRODUCT_TYPE_NAME("integrations", "defectdojo.autocreate.productTypeName", "Dependency Track", PropertyType.STRING, "Default product type name for DefectDojo auto context creation"),
105+
DEFECTDOJO_AUTOCREATE_DEDUPLICATION_ON_ENGAGEMENT("integrations", "defectdojo.autocreate.deduplicationOnEngagement", "false", PropertyType.BOOLEAN, "Flag to enable deduplication on engagement level instead of product level"),
105106
KENNA_ENABLED("integrations", "kenna.enabled", "false", PropertyType.BOOLEAN, "Flag to enable/disable Kenna Security integration"),
106107
KENNA_API_URL("integrations", "kenna.api.url", "https://api.kennasecurity.com", PropertyType.STRING, "Kenna Security API URL"),
107108
KENNA_SYNC_CADENCE("integrations", "kenna.sync.cadence", "60", PropertyType.INTEGER, "The cadence (in minutes) to upload to Kenna Security"),

0 commit comments

Comments
 (0)