Skip to content

fix: clear reverse M2M through tables before cascade deletion#14630

Merged
rossops merged 1 commit intoDefectDojo:bugfixfrom
valentijnscholten:fix-reverse-m2m-cascade-delete
Apr 6, 2026
Merged

fix: clear reverse M2M through tables before cascade deletion#14630
rossops merged 1 commit intoDefectDojo:bugfixfrom
valentijnscholten:fix-reverse-m2m-cascade-delete

Conversation

@valentijnscholten
Copy link
Copy Markdown
Member

@valentijnscholten valentijnscholten commented Apr 2, 2026

Summary

The optimized Async Delete from #14566 correctly cascaded M2M relationships, but not reverse M2M relationships. I could have sworn I tested Finding Groups, but to be sure this PR has test cases for these M2M relationships.

  • Fixes FK violations during async object deletion caused by reverse M2M through tables not being cleared before finding/engagement deletion.
  • Both bulk_clear_finding_m2m and cascade_delete_related_objects only discovered forward M2M fields (model._meta.many_to_many). Reverse M2M fields defined on other models (Finding_Group.findings, Risk_Acceptance.accepted_findings, EnhancedRiskAcceptance.affected_engagements) were missed.
  • Uses get_fields() which returns both forward ManyToManyField (via field.remote_field.through) and reverse ManyToManyRel (via field.through) to discover all through tables.

Context

Follow-up to #14566. The error observed in production:

psycopg.errors.ForeignKeyViolation: update or delete on table "dojo_finding" violates foreign key constraint
"dojo_finding_group_f_finding_id_ID_fk_dojo_find" on table "dojo_finding_group_findings"

Triggered from async_delete_taskbulk_delete_findings when deleting a Product with findings in Finding Groups.

Both bulk_clear_finding_m2m and cascade_delete_related_objects only
cleared forward M2M tables (model._meta.many_to_many). Reverse M2M
fields defined on other models (Finding_Group.findings,
Risk_Acceptance.accepted_findings, EnhancedRiskAcceptance.affected_engagements)
were missed, causing FK violations during bulk deletion.

Use get_fields() which returns both forward ManyToManyField (via
field.remote_field.through) and reverse ManyToManyRel (via field.through)
to discover all through tables.

Add test covering Finding_Group and Risk_Acceptance reverse M2M cleanup.
Copy link
Copy Markdown
Contributor

@mtesauro mtesauro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@rossops rossops merged commit a3aa91e into DefectDojo:bugfix Apr 6, 2026
156 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants