@@ -887,7 +887,9 @@ def test_clear_vulnerability_ids_on_empty_list(self):
887887
888888 # Process with empty list - should clear all IDs
889889 finding .unsaved_vulnerability_ids = []
890- DefaultReImporter (test = self .test , environment = self .importer_data ["environment" ], scan_type = self .importer_data ["scan_type" ]).reconcile_vulnerability_ids (finding )
890+ reimporter = DefaultReImporter (test = self .test , environment = self .importer_data ["environment" ], scan_type = self .importer_data ["scan_type" ])
891+ reimporter .reconcile_vulnerability_ids (finding )
892+ reimporter .flush_vulnerability_ids ()
891893 # Save the finding to persist the cve=None change
892894 finding .save ()
893895
@@ -924,7 +926,9 @@ def test_change_vulnerability_ids_on_reimport(self):
924926 # Process with different IDs - should replace old IDs
925927 new_vulnerability_ids = ["CVE-2021-9999" , "GHSA-xxxx-yyyy" ]
926928 finding .unsaved_vulnerability_ids = new_vulnerability_ids
927- DefaultReImporter (test = self .test , environment = self .importer_data ["environment" ], scan_type = self .importer_data ["scan_type" ]).reconcile_vulnerability_ids (finding )
929+ reimporter = DefaultReImporter (test = self .test , environment = self .importer_data ["environment" ], scan_type = self .importer_data ["scan_type" ])
930+ reimporter .reconcile_vulnerability_ids (finding )
931+ reimporter .flush_vulnerability_ids ()
928932 # Save the finding to persist the cve change
929933 finding .save ()
930934
@@ -940,3 +944,90 @@ def test_change_vulnerability_ids_on_reimport(self):
940944 vuln_ids = list (Vulnerability_Id .objects .filter (finding = finding ).values_list ("vulnerability_id" , flat = True ))
941945 self .assertEqual (set (new_vulnerability_ids ), set (vuln_ids ))
942946 finding .delete ()
947+
948+ def test_reconcile_vulnerability_ids_cross_finding_batch (self ):
949+ """Multiple findings accumulated before flush — one delete+insert pair per changed finding."""
950+ reimporter = DefaultReImporter (test = self .test , environment = self .importer_data ["environment" ], scan_type = self .importer_data ["scan_type" ])
951+
952+ # finding_a: IDs change (CVE-A → CVE-B)
953+ finding_a = Finding (test = self .test , reporter = self .testuser )
954+ finding_a .save ()
955+ Vulnerability_Id .objects .create (finding = finding_a , vulnerability_id = "CVE-A-OLD" )
956+ finding_a .cve = "CVE-A-OLD"
957+ finding_a .save ()
958+
959+ # finding_b: IDs change (CVE-B1, CVE-B2 → CVE-B-NEW)
960+ finding_b = Finding (test = self .test , reporter = self .testuser )
961+ finding_b .save ()
962+ Vulnerability_Id .objects .create (finding = finding_b , vulnerability_id = "CVE-B1" )
963+ Vulnerability_Id .objects .create (finding = finding_b , vulnerability_id = "CVE-B2" )
964+ finding_b .cve = "CVE-B1"
965+ finding_b .save ()
966+
967+ # finding_c: IDs unchanged — should not appear in delete/insert buffers
968+ finding_c = Finding (test = self .test , reporter = self .testuser )
969+ finding_c .save ()
970+ Vulnerability_Id .objects .create (finding = finding_c , vulnerability_id = "CVE-C-SAME" )
971+ finding_c .cve = "CVE-C-SAME"
972+ finding_c .save ()
973+
974+ finding_a .unsaved_vulnerability_ids = ["CVE-A-NEW" ]
975+ finding_b .unsaved_vulnerability_ids = ["CVE-B-NEW" ]
976+ finding_c .unsaved_vulnerability_ids = ["CVE-C-SAME" ]
977+
978+ # Accumulate all three before any flush
979+ reimporter .reconcile_vulnerability_ids (finding_a )
980+ reimporter .reconcile_vulnerability_ids (finding_b )
981+ reimporter .reconcile_vulnerability_ids (finding_c )
982+
983+ # pending_vuln_id_deletes only contains changed findings, not finding_c
984+ self .assertIn (finding_a .id , reimporter .pending_vuln_id_deletes )
985+ self .assertIn (finding_b .id , reimporter .pending_vuln_id_deletes )
986+ self .assertNotIn (finding_c .id , reimporter .pending_vuln_id_deletes )
987+ self .assertEqual (2 , len (reimporter .pending_vulnerability_ids ))
988+
989+ # Old IDs still in DB (not yet deleted)
990+ self .assertEqual (1 , Vulnerability_Id .objects .filter (finding = finding_a ).count ())
991+ self .assertEqual (2 , Vulnerability_Id .objects .filter (finding = finding_b ).count ())
992+
993+ reimporter .flush_vulnerability_ids ()
994+
995+ # Buffers cleared
996+ self .assertEqual ([], reimporter .pending_vuln_id_deletes )
997+ self .assertEqual ([], reimporter .pending_vulnerability_ids )
998+
999+ # finding_a: old deleted, new inserted
1000+ vuln_ids_a = list (Vulnerability_Id .objects .filter (finding = finding_a ).values_list ("vulnerability_id" , flat = True ))
1001+ self .assertEqual (["CVE-A-NEW" ], vuln_ids_a )
1002+ self .assertEqual ("CVE-A-NEW" , finding_a .cve )
1003+
1004+ # finding_b: both old deleted, new inserted
1005+ vuln_ids_b = list (Vulnerability_Id .objects .filter (finding = finding_b ).values_list ("vulnerability_id" , flat = True ))
1006+ self .assertEqual (["CVE-B-NEW" ], vuln_ids_b )
1007+ self .assertEqual ("CVE-B-NEW" , finding_b .cve )
1008+
1009+ # finding_c: unchanged — IDs untouched
1010+ vuln_ids_c = list (Vulnerability_Id .objects .filter (finding = finding_c ).values_list ("vulnerability_id" , flat = True ))
1011+ self .assertEqual (["CVE-C-SAME" ], vuln_ids_c )
1012+
1013+ finding_a .delete ()
1014+ finding_b .delete ()
1015+ finding_c .delete ()
1016+
1017+ def test_reconcile_vulnerability_ids_unchanged_no_db_write (self ):
1018+ """Early-exit path: unchanged IDs never touch pending buffers."""
1019+ reimporter = DefaultReImporter (test = self .test , environment = self .importer_data ["environment" ], scan_type = self .importer_data ["scan_type" ])
1020+
1021+ finding = Finding (test = self .test , reporter = self .testuser )
1022+ finding .save ()
1023+ Vulnerability_Id .objects .create (finding = finding , vulnerability_id = "CVE-2020-1234" )
1024+ finding .cve = "CVE-2020-1234"
1025+ finding .save ()
1026+
1027+ finding .unsaved_vulnerability_ids = ["CVE-2020-1234" ]
1028+ reimporter .reconcile_vulnerability_ids (finding )
1029+
1030+ self .assertEqual ([], reimporter .pending_vuln_id_deletes )
1031+ self .assertEqual ([], reimporter .pending_vulnerability_ids )
1032+
1033+ finding .delete ()
0 commit comments