Skip to content

Commit b54f1d1

Browse files
reimport: close_old_findings must respect service field
1 parent b5f3286 commit b54f1d1

4 files changed

Lines changed: 65 additions & 4 deletions

File tree

dojo/importers/default_reimporter.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,15 @@ def process_findings(
162162
at import time
163163
"""
164164
self.deduplication_algorithm = self.determine_deduplication_algorithm()
165-
self.original_items = list(self.test.finding_set.all())
165+
# Only process findings with the same service value (or None)
166+
# Even though the service values is used in the hash_code calculation,
167+
# we need to make sure there are no side effects such as closing findings
168+
# for findings with a different service value
169+
# https://github.com/DefectDojo/django-DefectDojo/issues/12754
170+
original_findings = self.test.finding_set.all().filter(service=self.service)
171+
logger.debug(f"original_findings_qyer: {original_findings.query}")
172+
self.original_items = list(original_findings)
173+
logger.debug(f"original_items: {[(item.id, item.hash_code) for item in self.original_items]}")
166174
self.new_items = []
167175
self.reactivated_items = []
168176
self.unchanged_items = []

dojo/importers/endpoint_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def add_endpoints_to_unsaved_finding(
5252
finding=finding,
5353
endpoint=ep,
5454
defaults={"date": finding.date})
55-
logger.debug(f"IMPORT_SCAN: {len(endpoints)} imported")
55+
logger.debug(f"IMPORT_SCAN: {len(endpoints)} endpoints imported")
5656
return
5757

5858
@dojo_async_task

unittests/dojo_test_case.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ def import_scan_with_params(self, filename, scan_type="ZAP Scan", engagement=1,
594594
return self.import_scan(payload, expected_http_status_code)
595595

596596
def reimport_scan_with_params(self, test_id, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", *, active=True, verified=False, push_to_jira=None,
597-
tags=None, close_old_findings=True, group_by=None, engagement_name=None, scan_date=None,
597+
tags=None, close_old_findings=True, group_by=None, engagement_name=None, scan_date=None, service=None,
598598
product_name=None, product_type_name=None, auto_create_context=None, expected_http_status_code=201, test_title=None):
599599
with Path(filename).open(encoding="utf-8") as testfile:
600600
payload = {
@@ -640,6 +640,9 @@ def reimport_scan_with_params(self, test_id, filename, scan_type="ZAP Scan", eng
640640
if scan_date is not None:
641641
payload["scan_date"] = scan_date
642642

643+
if service is not None:
644+
payload["service"] = service
645+
643646
return self.reimport_scan(payload, expected_http_status_code=expected_http_status_code)
644647

645648
def endpoint_meta_import_scan_with_params(self, filename, product=1, product_name=None, *,

unittests/test_import_reimport.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,53 @@ def test_import_param_close_old_findings_with_and_without_service_2(self):
13351335
engagement_findings_count = Finding.objects.filter(test__engagement_id=1, test__test_type=test.test_type, active=True, is_mitigated=False).count()
13361336
self.assertEqual(engagement_findings_count, 4)
13371337

1338+
# close_old_findings functionality: second import to different engagement with different service should not close findings from the first engagement
1339+
def test_import_param_close_old_findings_different_engagements_different_services(self):
1340+
logger.debug("importing clair report with service A into engagement 1")
1341+
with assertTestImportModelsCreated(self, imports=1, affected_findings=4, created=4):
1342+
import1 = self.import_scan_with_params(self.clair_few_findings, scan_type=self.scan_type_clair, engagement=1, close_old_findings=True, service="service_A")
1343+
1344+
test_id = import1["test"]
1345+
test = self.get_test(test_id)
1346+
findings = self.get_test_findings_api(test_id)
1347+
self.log_finding_summary_json_api(findings)
1348+
# imported count must match count in the report
1349+
self.assert_finding_count_json(4, findings)
1350+
1351+
# imported findings should be active in engagement 1
1352+
engagement1_findings = Finding.objects.filter(test__engagement_id=1, test__test_type=test.test_type, active=True, is_mitigated=False)
1353+
self.assertEqual(engagement1_findings.count(), 4)
1354+
1355+
# reimporting the same report into the same test with a different service should not close any findings and create 4 new findings
1356+
self.reimport_scan_with_params(test_id, self.clair_few_findings, scan_type=self.scan_type_clair, close_old_findings=True, service="service_B")
1357+
1358+
engagement1_active_finding_count = Finding.objects.filter(test__engagement_id=1, test__test_type=test.test_type, active=True, is_mitigated=False)
1359+
self.assertEqual(engagement1_active_finding_count.count(), 8)
1360+
engagement1_mitigated_finding_count = Finding.objects.filter(test__engagement_id=1, test__test_type=test.test_type, active=False, is_mitigated=True)
1361+
self.assertEqual(engagement1_mitigated_finding_count.count(), 0)
1362+
# verify findings from engagement 1 are still the same (not mitigated/closed)
1363+
for finding in engagement1_active_finding_count:
1364+
self.assertTrue(finding.active)
1365+
self.assertFalse(finding.is_mitigated)
1366+
1367+
# reimporting an empty report with service A should close all findings from the first import, but not the reimported ones with service B
1368+
self.reimport_scan_with_params(test_id, self.clair_empty, scan_type=self.scan_type_clair, close_old_findings=True, service="service_A")
1369+
1370+
engagement1_active_finding_count = Finding.objects.filter(test__engagement_id=1, test__test_type=test.test_type, active=True, is_mitigated=False)
1371+
self.assertEqual(engagement1_active_finding_count.count(), 4)
1372+
engagement1_mitigated_finding_count = Finding.objects.filter(test__engagement_id=1, test__test_type=test.test_type, active=False, is_mitigated=True)
1373+
self.assertEqual(engagement1_mitigated_finding_count.count(), 4)
1374+
1375+
for finding in engagement1_active_finding_count:
1376+
self.assertTrue(finding.active)
1377+
self.assertFalse(finding.is_mitigated)
1378+
self.assertEqual(finding.service, "service_B")
1379+
1380+
for finding in engagement1_mitigated_finding_count:
1381+
self.assertFalse(finding.active)
1382+
self.assertTrue(finding.is_mitigated)
1383+
self.assertEqual(finding.service, "service_A")
1384+
13381385
def test_import_reimport_generic(self):
13391386
"""
13401387
This test do a basic import and re-import of a generic JSON report
@@ -1873,7 +1920,7 @@ def import_scan_with_params_ui(self, filename, scan_type="ZAP Scan", engagement=
18731920

18741921
return self.import_scan_ui(engagement, payload)
18751922

1876-
def reimport_scan_with_params_ui(self, test_id, filename, scan_type="ZAP Scan", minimum_severity="Low", *, active=True, verified=False, push_to_jira=None, tags=None, close_old_findings=True, scan_date=None):
1923+
def reimport_scan_with_params_ui(self, test_id, filename, scan_type="ZAP Scan", minimum_severity="Low", *, active=True, verified=False, push_to_jira=None, tags=None, close_old_findings=True, scan_date=None, service=None):
18771924
# Mimic old functionality for active/verified to avoid breaking tests
18781925
activePayload = "force_to_true"
18791926
if not active:
@@ -1902,6 +1949,9 @@ def reimport_scan_with_params_ui(self, test_id, filename, scan_type="ZAP Scan",
19021949
if scan_date is not None:
19031950
payload["scan_date"] = scan_date
19041951

1952+
if service is not None:
1953+
payload["service"] = service
1954+
19051955
return self.reimport_scan_ui(test_id, payload)
19061956

19071957
# Observations:

0 commit comments

Comments
 (0)