77
88from dojo .celery_dispatch import dojo_dispatch_task
99from dojo .finding import helper as finding_helper
10- from dojo .finding .deduplication import deduplication_ordering_key
1110from dojo .importers .base_importer import BaseImporter , Parser
1211from dojo .importers .base_location_manager import LocationHandler
1312from dojo .importers .options import ImporterOptions
@@ -204,66 +203,54 @@ def _process_findings_internal(
204203 logger .debug ("starting import of %i parsed findings." , len (parsed_findings ) if parsed_findings else 0 )
205204 group_names_to_findings_dict = {}
206205
207- # Pre-sanitize and filter by minimum severity. Findings are also fully
208- # prepared here (fields/overrides/hash_code) so they can be sorted by a
209- # stable content key below.
206+ # Pre-sanitize and filter by minimum severity
210207 cleaned_findings = []
211208 for raw_finding in parsed_findings or []:
212209 sanitized = self .sanitize_severity (raw_finding )
213210 if Finding .SEVERITIES [sanitized .severity ] > Finding .SEVERITIES [self .minimum_severity ]:
214211 logger .debug ("skipping finding due to minimum severity filter (finding=%s severity=%s min=%s)" , sanitized .title , sanitized .severity , self .minimum_severity )
215212 continue
213+ cleaned_findings .append (sanitized )
214+
215+ for idx , unsaved_finding in enumerate (cleaned_findings ):
216+ is_final_finding = idx == len (cleaned_findings ) - 1
217+
216218 # Some parsers provide "mitigated" field but do not set timezone (because they are probably not available in the report)
217219 # Finding.mitigated is DateTimeField and it requires timezone
218- if sanitized .mitigated and not sanitized .mitigated .tzinfo :
219- sanitized .mitigated = sanitized .mitigated .replace (tzinfo = self .now .tzinfo )
220+ if unsaved_finding .mitigated and not unsaved_finding .mitigated .tzinfo :
221+ unsaved_finding .mitigated = unsaved_finding .mitigated .replace (tzinfo = self .now .tzinfo )
220222 # Set some explicit fields on the finding
221- sanitized .test = self .test
222- sanitized .reporter = self .user
223- sanitized .last_reviewed_by = self .user
224- sanitized .last_reviewed = self .now
225- logger .debug ("process_parsed_finding: unique_id_from_tool: %s, hash_code: %s, active from report: %s, verified from report: %s" , sanitized .unique_id_from_tool , sanitized .hash_code , sanitized .active , sanitized .verified )
226- # indicates an override. Otherwise, do not change the value of sanitized .active
223+ unsaved_finding .test = self .test
224+ unsaved_finding .reporter = self .user
225+ unsaved_finding .last_reviewed_by = self .user
226+ unsaved_finding .last_reviewed = self .now
227+ logger .debug ("process_parsed_finding: unique_id_from_tool: %s, hash_code: %s, active from report: %s, verified from report: %s" , unsaved_finding .unique_id_from_tool , unsaved_finding .hash_code , unsaved_finding .active , unsaved_finding .verified )
228+ # indicates an override. Otherwise, do not change the value of unsaved_finding .active
227229 if self .active is not None :
228- sanitized .active = self .active
230+ unsaved_finding .active = self .active
229231 # indicates an override. Otherwise, do not change the value of verified
230232 if self .verified is not None :
231- sanitized .verified = self .verified
233+ unsaved_finding .verified = self .verified
232234 # scan_date was provided, override value from parser
233235 if self .scan_date_override :
234- sanitized .date = self .scan_date .date ()
236+ unsaved_finding .date = self .scan_date .date ()
235237 if self .service is not None :
236- sanitized .service = self .service
238+ unsaved_finding .service = self .service
237239
238240 # Parsers shouldn't use the tags field, and use unsaved_tags instead.
239241 # Merge any tags set by parser into unsaved_tags
240- tags_from_parser = sanitized .tags if isinstance (sanitized .tags , list ) else []
241- unsaved_tags_from_parser = sanitized .unsaved_tags if isinstance (sanitized .unsaved_tags , list ) else []
242+ tags_from_parser = unsaved_finding .tags if isinstance (unsaved_finding .tags , list ) else []
243+ unsaved_tags_from_parser = unsaved_finding .unsaved_tags if isinstance (unsaved_finding .unsaved_tags , list ) else []
242244 merged_tags = unsaved_tags_from_parser + tags_from_parser
243245 if merged_tags :
244- sanitized .unsaved_tags = merged_tags
245- sanitized .tags = None
246- prepared = self .process_cve (sanitized )
246+ unsaved_finding .unsaved_tags = merged_tags
247+ unsaved_finding .tags = None
248+ finding = self .process_cve (unsaved_finding )
247249 # Calculate hash_code before saving based on unsaved_endpoints/unsaved_locations and unsaved_vulnerability_ids
248- prepared .set_hash_code (True )
249- cleaned_findings .append (prepared )
250-
251- # Create findings in stable content-key order so their ids follow content, not
252- # the scanner's export order. Deduplication picks the lowest id among findings
253- # that collide on the dedupe key, so this makes the surviving "original" for
254- # intra-report collisions reproducible across re-scans regardless of the order
255- # the scanner emitted its findings. Unsaved findings have no id, so the id
256- # tiebreak is inert here and byte-identical findings keep their relative
257- # (immaterial) order via Python's stable sort.
258- cleaned_findings .sort (key = deduplication_ordering_key )
259-
260- for idx , finding in enumerate (cleaned_findings ):
261- is_final_finding = idx == len (cleaned_findings ) - 1
250+ finding .set_hash_code (True )
262251
263- # Findings are already prepared (fields/overrides/hash_code) and globally
264- # sorted above. postprocessing will be done after processing related
265- # fields like locations, vulnerability ids, etc.
266- finding .save_no_options ()
252+ # postprocessing will be done after processing related fields like locations, vulnerability ids, etc.
253+ unsaved_finding .save_no_options ()
267254
268255 # Determine how the finding should be grouped
269256 finding_will_be_grouped = self .process_finding_groups (
@@ -282,8 +269,8 @@ def _process_findings_internal(
282269 findings_with_parser_tags .append ((finding , [cleaned_tags ]))
283270 # Process any files
284271 self .process_files (finding )
285- # Process vulnerability IDs (mutates the finding in place)
286- self .store_vulnerability_ids (finding )
272+ # Process vulnerability IDs
273+ finding = self .store_vulnerability_ids (finding )
287274 # Categorize this finding as a new one
288275 new_findings .append (finding )
289276 # all data is already saved on the finding, we only need to trigger post processing in batches
0 commit comments