Skip to content

Persist path_pairs before integrations on detach (#469.3)#496

Merged
nitrobass24 merged 2 commits into
developfrom
fix/integrations-detach-ordering
May 20, 2026
Merged

Persist path_pairs before integrations on detach (#469.3)#496
nitrobass24 merged 2 commits into
developfrom
fix/integrations-detach-ordering

Conversation

@nitrobass24
Copy link
Copy Markdown
Owner

@nitrobass24 nitrobass24 commented May 20, 2026

Summary

Addresses item #3 in #469.

`IntegrationsHandler.__handle_delete` writes integrations.json after path_pairs.json (instead of before). Process death between the two writes previously left the on-disk integrations file without the instance but the on-disk path_pairs file still referencing it — a dangling `arr_target_id`, which the cross-validation added in #426 rejects when the path_pairs config loads on next start.

The new order downgrades the worst-case crash outcome to an orphaned (no-longer-referenced) instance in integrations.json. That's harmless: load succeeds, and the next delete attempt cleans it up.

Test plan

  • `cd src/python && pytest tests/integration/test_web/test_handler/test_integrations.py` — 28 tests pass (2 new + 26 existing)
  • New tests:
    • `test_delete_persists_path_pairs_before_integrations` — spies both `to_file` calls and asserts the captured order is `["path_pairs", "integrations"]`
    • `test_delete_with_integrations_write_failure_leaves_no_dangling_refs` — patches `integrations_config.to_file` to raise `OSError`, asserts the on-disk `path_pairs.json` has the detach applied (instance is no longer referenced)

🤖 Generated with Claude Code

Summary by CodeRabbit

Bug Fixes

  • Fixed a data consistency issue in deletion operations where crashes could leave orphaned references. The operation now properly cleans up dependencies before removing primary records.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d90c6eb0-6027-45c5-ac23-31657251285c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR fixes a crash vulnerability in the integration deletion endpoint by reversing the persistence order: path_pairs.json is now written before integrations.json. If a crash occurs between writes, the previously persisted path_pairs no longer references the deleted integration. The handler implementation change is validated by two integration tests covering normal deletion and failure recovery scenarios.

Changes

Integration deletion persistence order fix

Layer / File(s) Summary
Handler persistence order fix
src/python/web/handler/integrations.py
IntegrationsHandler.__handle_delete writes path_pairs before integrations with comments describing recovery behavior on partial failure.
Persistence order validation tests
src/python/tests/integration/test_web/test_handler/test_integrations.py
Two new tests: one asserts write order by intercepting to_file calls; another simulates integrations.to_file failure and verifies persisted path_pairs contains no dangling references.
Changelog documentation
CHANGELOG.md
Unreleased Fixed entry documents the write-order change and the crash scenario it prevents.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: reordering persistence to write path_pairs before integrations on detach, which is the core fix implemented across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/integrations-detach-ordering

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

In IntegrationsHandler.__handle_delete the two on-disk writes ran in
the wrong order: integrations.json first, then path_pairs.json. A
crash between writes left integrations.json without the instance but
path_pairs.json still referencing it — a dangling arr_target_id that
the cross-validation in #426 rejects on next load.

Swap the order so path_pairs persists first. The worst-case crash
outcome is now an orphaned (no-longer-referenced) instance in
integrations.json, which is harmless — it survives load and gets
cleaned up the next time the user retries the delete.

Adds two integration tests: one spying both to_file calls to assert
the call order, one patching the second write to raise OSError and
verifying the persisted path_pairs.json has the detach applied.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nitrobass24 nitrobass24 force-pushed the fix/integrations-detach-ordering branch from 5f50de4 to 4ea8f6c Compare May 20, 2026 02:49
@nitrobass24
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nitrobass24
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Line 12: The changelog entry titled "Integration delete persistence ordering"
currently ends with the wrong PR reference "(`#469`)"; update that trailing
reference to the correct PR number (e.g., "(`#496`)" if that is the intended PR)
so the entry text "Integration delete persistence ordering —
`/server/integrations/<id>` DELETE ..." ends with the accurate "(`#NNN`)" value;
confirm the correct PR and replace the existing "(`#469`)" accordingly.

In `@src/python/tests/integration/test_web/test_handler/test_integrations.py`:
- Around line 255-257: The test currently calls self.test_app.delete(...,
expect_errors=True) with integrations_config.to_file patched to raise OSError
but doesn't assert the response status; update the test to capture the response
(e.g., resp = self.test_app.delete(..., expect_errors=True)) and add an explicit
assertion that resp.status_int (or resp.status_code depending on test client)
equals 500 to ensure the handler returns a server error when
integrations_config.to_file raises OSError; reference the patched method
integrations_config.to_file and the DELETE request to
"/server/integrations/{inst.id}" when making the change.

In `@src/python/web/handler/integrations.py`:
- Around line 119-120: The current delete flow persists __path_pairs_config to
__path_pairs_path then __config to __integrations_path which can leave a partial
on-disk state if the second write fails; change the flow to perform atomic disk
updates and keep in-memory state consistent by (a) serializing both updated
configs to temporary files (or use a transactional temp dir), (b) fsync/flushing
each temp file and then atomically rename/replace them into __path_pairs_path
and __integrations_path (os.replace or equivalent), and only after both atomic
replaces succeed apply the in-memory mutation; if any step fails, delete temp
files and do not mutate in-memory state (or restore it) to avoid runtime/disk
divergence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 67e66c8d-fe4b-4c3e-a354-3e8a29caaf56

📥 Commits

Reviewing files that changed from the base of the PR and between eda0a36 and 4ea8f6c.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/python/tests/integration/test_web/test_handler/test_integrations.py
  • src/python/web/handler/integrations.py

Comment thread CHANGELOG.md Outdated
Comment thread src/python/web/handler/integrations.py
CodeRabbit follow-up on #496.

- CHANGELOG: change the integration delete entry's reference from the
  umbrella issue #469 to the actual PR #496 — matches the more common
  convention in this file (#456, #458#466, #437, etc.).
- test_delete_with_integrations_write_failure_leaves_no_dangling_refs:
  capture the response and assert status_int == 500. Without it, a
  regression where the handler returns 200 on a failed write would
  still pass the on-disk assertions below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nitrobass24 nitrobass24 merged commit 8579b45 into develop May 20, 2026
18 checks passed
@nitrobass24 nitrobass24 deleted the fix/integrations-detach-ordering branch May 20, 2026 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant