@@ -182,8 +182,12 @@ def _process_findings_internal(
182182 parsed_findings : list [Finding ],
183183 ** kwargs : dict ,
184184 ) -> list [Finding ]:
185- # Batched post-processing (no chord): dispatch a task per 1000 findings or on final finding
186- batch_finding_ids : list [int ] = []
185+ # Batched post-processing (no chord): dispatch a task per 1000 findings or on final finding.
186+ # Each entry carries the finding's own push_to_jira flag: grouped findings are pushed to
187+ # JIRA as a group after the loop, so their individual push is suppressed while ungrouped
188+ # findings in the same batch must still be pushed. The batch is partitioned by flag at
189+ # dispatch time instead of applying one finding's flag to the whole batch.
190+ batch_finding_ids : list [tuple [int , bool ]] = []
187191 batch_findings : list [Finding ] = []
188192 batch_max_size = getattr (settings , "IMPORT_REIMPORT_DEDUPE_BATCH_SIZE" , 1000 )
189193
@@ -274,7 +278,7 @@ def _process_findings_internal(
274278 self .push_to_jira , self .findings_groups_enabled , self .group_by )
275279 push_to_jira = self .push_to_jira and ((not self .findings_groups_enabled or not self .group_by ) or not finding_will_be_grouped )
276280 logger .debug ("process_findings: computed push_to_jira=%s" , push_to_jira )
277- batch_finding_ids .append (finding .id )
281+ batch_finding_ids .append (( finding .id , push_to_jira ) )
278282 batch_findings .append (finding )
279283
280284 # If batch is full or we're at the end, persist locations/endpoints and dispatch
@@ -293,25 +297,31 @@ def _process_findings_internal(
293297 # dispatches, so rules/dedup see inherited tags on .tags.
294298 apply_inherited_tags_for_findings (batch_findings )
295299 batch_findings .clear ()
296- finding_ids_batch = list (batch_finding_ids )
300+ # Partition the batch by each finding's own push_to_jira flag so one
301+ # finding's grouping state is not applied to the whole batch. Uniform
302+ # batches (grouping disabled, or push_to_jira off) stay a single dispatch.
303+ finding_ids_by_push : dict [bool , list [int ]] = {}
304+ for finding_id , finding_push_to_jira in batch_finding_ids :
305+ finding_ids_by_push .setdefault (finding_push_to_jira , []).append (finding_id )
297306 batch_finding_ids .clear ()
298- logger .debug ("process_findings: dispatching batch with push_to_jira=%s (batch_size=%d, is_final=%s)" ,
299- push_to_jira , len (finding_ids_batch ), is_final_finding )
300- result = dojo_dispatch_task (
301- finding_helper .post_process_findings_batch ,
302- finding_ids_batch ,
303- dedupe_option = True ,
304- rules_option = True ,
305- product_grading_option = True ,
306- issue_updater_option = True ,
307- push_to_jira = push_to_jira ,
308- # 'async_wait' joins on this dispatch via AsyncResult.get(), so its
309- # result must be stored despite the global CELERY_TASK_IGNORE_RESULT.
310- ** ({"ignore_result" : False } if self .deduplication_execution_mode == DEDUPLICATION_EXECUTION_MODE_ASYNC_WAIT else {}),
311- ** self .post_processing_dispatch_kwargs (** kwargs ),
312- )
313- if self .deduplication_execution_mode == DEDUPLICATION_EXECUTION_MODE_ASYNC_WAIT :
314- self .record_post_processing_result (result )
307+ for push_to_jira_batch , finding_ids_batch in finding_ids_by_push .items ():
308+ logger .debug ("process_findings: dispatching batch with push_to_jira=%s (batch_size=%d, is_final=%s)" ,
309+ push_to_jira_batch , len (finding_ids_batch ), is_final_finding )
310+ result = dojo_dispatch_task (
311+ finding_helper .post_process_findings_batch ,
312+ finding_ids_batch ,
313+ dedupe_option = True ,
314+ rules_option = True ,
315+ product_grading_option = True ,
316+ issue_updater_option = True ,
317+ push_to_jira = push_to_jira_batch ,
318+ # 'async_wait' joins on this dispatch via AsyncResult.get(), so its
319+ # result must be stored despite the global CELERY_TASK_IGNORE_RESULT.
320+ ** ({"ignore_result" : False } if self .deduplication_execution_mode == DEDUPLICATION_EXECUTION_MODE_ASYNC_WAIT else {}),
321+ ** self .post_processing_dispatch_kwargs (** kwargs ),
322+ )
323+ if self .deduplication_execution_mode == DEDUPLICATION_EXECUTION_MODE_ASYNC_WAIT :
324+ self .record_post_processing_result (result )
315325
316326 # No chord: tasks are dispatched immediately above per batch
317327
@@ -402,7 +412,7 @@ def close_old_findings(
402412 # Remove all the findings that are coming from the report already mitigated
403413 new_hash_codes = []
404414 new_unique_ids_from_tool = []
405- for finding in findings .values ():
415+ for finding in findings .values ("is_mitigated" , "hash_code" , "unique_id_from_tool" ):
406416 # Do not process closed findings in the report
407417 if finding .get ("is_mitigated" , False ):
408418 continue
0 commit comments