ENG-3507: Unlink StagedResources before system deletion#8032
Conversation
When deleting a System that was promoted from an IDP monitor StagedResource, the FK constraint on stagedresource.system_id blocks the delete. Fix by nulling system_id and resetting diff_status to ADDITION before deletion, within the same transaction. This preserves the StagedResource for re-promotion while allowing the System to be removed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e-staged-resource
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
Codecov Report✅ All modified and coverable lines are covered by tests. ❌ Your project status has failed because the head coverage (84.97%) is below the target coverage (85.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #8032 +/- ##
========================================
Coverage 84.96% 84.97%
========================================
Files 632 633 +1
Lines 41471 41663 +192
Branches 4836 4879 +43
========================================
+ Hits 35235 35402 +167
- Misses 5136 5151 +15
- Partials 1100 1110 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
The DB FK has no ondelete clause; annotating the model with ondelete="SET NULL" is misleading since it doesn't take effect without a migration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the StagedResource unlinking from the system delete endpoints into a SQLAlchemy before_delete event listener on the System model, registered from the discovery module. This keeps the dependency direction correct (discovery → system) and ensures cleanup happens for any code path that deletes a System. Follows the same pattern as fidesplus/jira/jira_credential_sync.py which listens for ConnectionConfig before_delete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| ) -> None: | ||
| """Null out system_id and reset diff_status on StagedResources before a System is deleted. | ||
|
|
||
| This keeps the dependency direction correct: the discovery module knows about |
There was a problem hiding this comment.
Follows the same pattern as
fidesplus/jira/jira_credential_sync.py which listens for ConnectionConfig deletion.
- Capture system.id and system.fides_key into locals before the delete API call to avoid ObjectDeletedError on the stale ORM instance - Add changelog entry for PR #8032 - Add debug logging to the before_delete event listener - Refactor tests: yield fixture for cleanup safety, add no-op test case Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vcruces
left a comment
There was a problem hiding this comment.
Looks great to me, thanks for making this change! It was needed, and blocking users when trying to delete a system was the wrong behavior
The before_delete listener already handles all StagedResources generically, but the tests, docstring, changelog, and PR description only referenced IDP monitors. Website monitor resources also get system_id set (via vendor_id matching) and hit the same IntegrityError on system deletion. - Add test for web monitor resource type (Cookie) unlinking on system delete - Update docstring to document both IDP and website monitor paths - Update changelog to mention website monitor discovery Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
IntegrityErrorwhen deleting a System that has linked StagedResourcesbefore_deleteevent listener onSystemto null outsystem_idand resetdiff_statustoADDITIONon any referencing StagedResourcesProblem
The
stagedresource.system_idFK toctl_systems.idwas created without anondeleteclause, defaulting to PostgreSQL's RESTRICT. When a user tries to delete a System that is referenced by any StagedResource, the FK constraint blocks the delete with anIntegrityError.Steps to Reproduce
IDP Monitor path
stagedresource.system_idanddiff_statustoMONITOREDIntegrityError— the FK constraint onstagedresource.system_idblocks the deleteWebsite Monitor path
vendor_idmatches an existing System →system_idis set viaassociate_resource_with_system_or_vendor()and resource is promoted toMONITOREDIntegrityErrorApproach
SQLAlchemy
before_deleteevent listener onSystem(_unlink_staged_resources_on_system_delete). Before the DELETE is issued, the listener executes an UPDATE to nullsystem_idand resetdiff_statustoADDITIONon any referencing StagedResources. This keeps the dependency direction correct — the discovery module knows about System (via the FK), not the other way around — and requires no migration.Test plan
test_single_delete_unlinks_staged_resource— single system delete unlinks IDP monitor StagedResourcetest_single_delete_unlinks_web_monitor_staged_resource— single system delete unlinks website monitor StagedResource (Cookie)test_bulk_delete_systems_with_staged_resources— bulk delete unlinks StagedResourcestest_delete_system_without_staged_resources— delete succeeds when no StagedResources reference the system🤖 Generated with Claude Code