@@ -468,6 +468,11 @@ def setUp(self):
468468 self .product = self .create_product ("Tag Perf Import Product" , tags = ["inherit" , "these" ])
469469 self .engagement = self .create_engagement ("Tag Perf Import Engagement" , self .product )
470470 self .scan_path = get_unit_tests_scans_path ("zap" ) / "dvwa_baseline_dojo.xml"
471+ # Subset of the full report (10 findings vs 19) used to exercise the
472+ # reimport-with-new-findings code path: initial import uses the subset,
473+ # then reimport uses the full report so 9 findings get created during
474+ # reimport while 10 match existing ones.
475+ self .scan_path_subset = get_unit_tests_scans_path ("zap" ) / "dvwa_baseline_dojo_subset.xml"
471476
472477 @override_settings (V3_FEATURE_LOCATIONS = False )
473478 def test_baseline_zap_scan_import_v2 (self ):
@@ -534,6 +539,42 @@ def test_baseline_zap_scan_reimport_no_change_v3(self):
534539 finding = Finding .objects .filter (test_id = test_id ).first ()
535540 self .assertEqual ({"inherit" , "these" }, {t .name for t in finding .tags .all ()})
536541
542+ @override_settings (V3_FEATURE_LOCATIONS = False )
543+ def test_baseline_zap_scan_reimport_with_new_findings_v2 (self ):
544+ """
545+ V2: import 10-finding subset, then reimport 19-finding full report.
546+
547+ 9 findings are NEW (must run inheritance), 10 are matched (skip).
548+ Exercises the realistic "scheduled rescan with drift" path where a
549+ reimport actually creates findings.
550+ """
551+ response = self .import_scan_with_params (
552+ self .scan_path_subset ,
553+ engagement = self .engagement .id ,
554+ )
555+ test_id = response ["test" ]
556+
557+ with self .assertNumQueries (self .EXPECTED_ZAP_REIMPORT_WITH_NEW_V2 ):
558+ self .reimport_scan_with_params (test_id , str (self .scan_path ))
559+
560+ finding = Finding .objects .filter (test_id = test_id ).first ()
561+ self .assertEqual ({"inherit" , "these" }, {t .name for t in finding .tags .all ()})
562+
563+ @override_settings (V3_FEATURE_LOCATIONS = True )
564+ def test_baseline_zap_scan_reimport_with_new_findings_v3 (self ):
565+ """V3: same as V2 but Location-backed."""
566+ response = self .import_scan_with_params (
567+ self .scan_path_subset ,
568+ engagement = self .engagement .id ,
569+ )
570+ test_id = response ["test" ]
571+
572+ with self .assertNumQueries (self .EXPECTED_ZAP_REIMPORT_WITH_NEW_V3 ):
573+ self .reimport_scan_with_params (test_id , str (self .scan_path ))
574+
575+ finding = Finding .objects .filter (test_id = test_id ).first ()
576+ self .assertEqual ({"inherit" , "these" }, {t .name for t in finding .tags .all ()})
577+
537578 # Pinned baselines per mode. Each test forces its own V3_FEATURE_LOCATIONS
538579 # via @override_settings so all four import paths run in a single suite
539580 # invocation regardless of the ambient `DD_V3_FEATURE_LOCATIONS` env var.
@@ -548,3 +589,5 @@ def test_baseline_zap_scan_reimport_no_change_v3(self):
548589 EXPECTED_ZAP_IMPORT_V3 = 444
549590 EXPECTED_ZAP_REIMPORT_NO_CHANGE_V2 = 69
550591 EXPECTED_ZAP_REIMPORT_NO_CHANGE_V3 = 81
592+ EXPECTED_ZAP_REIMPORT_WITH_NEW_V2 = 169
593+ EXPECTED_ZAP_REIMPORT_WITH_NEW_V3 = 198
0 commit comments