[PR #1821] [MERGED] fix(setup): retain symlinked data roots during uninstall #4836

Closed
opened 2026-10-31 00:55:40 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1821
Author: @shoyann
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @morluto

Base: main ← Head: fix/uninstall-purge-root-symlink


📝 Commits (1)

  • be027f0 fix(setup): retain symlinked data roots during uninstall

📊 Changes

3 files changed (+231 additions, -5 deletions)

View changed files

📝 src/application/Uninstall.ts (+34 -4)
📝 tests/boundary/cli/clientProfileLifecycle.test.ts (+57 -1)
📝 tests/boundary/filesystem/clientLifecycle.test.ts (+140 -0)

📄 Description

Summary

Fixes #1816.

rea uninstall --purge-data followed a symlink at ~/.rea and deleted the target's cache and state directories. Validate the managed data root before inspecting either child, retaining linked roots and their target data.

Problem and expected behavior

When .rea links to an unrelated directory containing cache/ and state/, checking only the children with lstat sees ordinary directories and permits recursive deletion. The documented uninstall contract preserves symlinks and unknown paths; the managed root must satisfy that contract too, including dangling links.

Change and scope

The shared uninstall host checks .rea with its existing lstat boundary before purging either child. Linked or non-directory roots retain both entries; missing roots skip them; inspection errors fail both entries without deletion. Ordinary roots continue through the existing leaf checks. Legitimate HOME directory links remain supported.

Contract and boundary impact

  • Semantic owner and earliest changed stage: application uninstall host, managed data root admission before child cleanup.
  • CLI and MCP/tool-catalog contract: no schema changes; the uninstall CLI reports existing retained, skipped, and failed statuses for rejected or unavailable roots.
  • Provider, bridge, target-format, or platform compatibility: no provider or target-format changes; tests use directory symlinks on POSIX and junctions on Windows.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Process execution, authorization, cleanup, or containment impact: prevents purge from traversing a symlinked managed root into unrelated target data.
  • Generated metadata, package, or installation impact: no generated metadata changes; enforces the existing installation guide's uninstall retention contract.

Evidence and regression coverage

  • Tests added or updated: real-filesystem existing/dangling root links, a non-directory root, a legitimate HOME link, an injected root inspection error with zero removals, and a real public CLI regression checking external sentinel contents and JSON statuses.
  • Base reproduction: the two root-link filesystem cases and the CLI regression failed against f178bf1c; the CLI reported the target's cache and state as removed, and both sentinels were deleted.
  • Representative corrected CLI output (relevant fields): {"status":"complete","items":[{"name":"cache","status":"retained"},{"name":"state","status":"retained"}]}.
  • Remaining proof gaps: executed on WSL Ubuntu with Node 24.18.0 and npm 11.16.0; native Windows junction and macOS execution remain unverified. Permission failure is injected at the filesystem boundary.

Evidence-bearing analysis outputs are not changed by this PR.

Validation performed

  • npm run test:focused -- tests/boundary/filesystem/clientLifecycle.test.ts tests/boundary/cli/clientProfileLifecycle.test.ts — 52/52 passed.
  • npm run check — passed (repository lint reports warnings but no errors).
  • npm run verify:package — passed, including setup/uninstall, package update, CLI, and MCP checks. The first attempt hit the host proxy when connecting to the local registry fixture; rerunning with NO_PROXY, no_proxy, and npm_config_noproxy set to 127.0.0.1,localhost,::1 passed. No repository workaround was added.
  • npm pack --dry-run — passed.
  • Scoped lint on all three changed files and git diff --check — passed.

Compatibility, safety, and release

  • Breaking changes or migration steps: none; ordinary directory cleanup and existing leaf symlink retention continue unchanged.
  • Real Hopper/Ghidra, browser, or OS coverage: WSL Ubuntu filesystem and public CLI execution; optional real providers are not involved.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: this guards existing root links before deletion. It does not establish race-free containment against concurrent path replacement; cleanup still uses the existing path-based filesystem API.

Review checklist

  • This PR addresses a concrete problem or an agreed enhancement.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed (the existing documented contract is unchanged).
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1821 **Author:** [@shoyann](https://github.com/shoyann) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/uninstall-purge-root-symlink` --- ### 📝 Commits (1) - [`be027f0`](https://github.com/morluto/rea/commit/be027f0bd767ac3a840a20d83370cec86956fb0f) fix(setup): retain symlinked data roots during uninstall ### 📊 Changes **3 files changed** (+231 additions, -5 deletions) <details> <summary>View changed files</summary> 📝 `src/application/Uninstall.ts` (+34 -4) 📝 `tests/boundary/cli/clientProfileLifecycle.test.ts` (+57 -1) 📝 `tests/boundary/filesystem/clientLifecycle.test.ts` (+140 -0) </details> ### 📄 Description ## Summary Fixes #1816. `rea uninstall --purge-data` followed a symlink at `~/.rea` and deleted the target's `cache` and `state` directories. Validate the managed data root before inspecting either child, retaining linked roots and their target data. ## Problem and expected behavior When `.rea` links to an unrelated directory containing `cache/` and `state/`, checking only the children with `lstat` sees ordinary directories and permits recursive deletion. The documented uninstall contract preserves symlinks and unknown paths; the managed root must satisfy that contract too, including dangling links. ## Change and scope The shared uninstall host checks `.rea` with its existing `lstat` boundary before purging either child. Linked or non-directory roots retain both entries; missing roots skip them; inspection errors fail both entries without deletion. Ordinary roots continue through the existing leaf checks. Legitimate HOME directory links remain supported. ## Contract and boundary impact - Semantic owner and earliest changed stage: application uninstall host, managed data root admission before child cleanup. - CLI and MCP/tool-catalog contract: no schema changes; the uninstall CLI reports existing `retained`, `skipped`, and `failed` statuses for rejected or unavailable roots. - Provider, bridge, target-format, or platform compatibility: no provider or target-format changes; tests use directory symlinks on POSIX and junctions on Windows. - Evidence, artifact, provenance, or reconstruction contract: none. - Process execution, authorization, cleanup, or containment impact: prevents purge from traversing a symlinked managed root into unrelated target data. - Generated metadata, package, or installation impact: no generated metadata changes; enforces the existing installation guide's uninstall retention contract. ## Evidence and regression coverage - Tests added or updated: real-filesystem existing/dangling root links, a non-directory root, a legitimate HOME link, an injected root inspection error with zero removals, and a real public CLI regression checking external sentinel contents and JSON statuses. - Base reproduction: the two root-link filesystem cases and the CLI regression failed against `f178bf1c`; the CLI reported the target's cache and state as removed, and both sentinels were deleted. - Representative corrected CLI output (relevant fields): `{"status":"complete","items":[{"name":"cache","status":"retained"},{"name":"state","status":"retained"}]}`. - Remaining proof gaps: executed on WSL Ubuntu with Node 24.18.0 and npm 11.16.0; native Windows junction and macOS execution remain unverified. Permission failure is injected at the filesystem boundary. Evidence-bearing analysis outputs are not changed by this PR. ## Validation performed - `npm run test:focused -- tests/boundary/filesystem/clientLifecycle.test.ts tests/boundary/cli/clientProfileLifecycle.test.ts` — 52/52 passed. - `npm run check` — passed (repository lint reports warnings but no errors). - `npm run verify:package` — passed, including setup/uninstall, package update, CLI, and MCP checks. The first attempt hit the host proxy when connecting to the local registry fixture; rerunning with `NO_PROXY`, `no_proxy`, and `npm_config_noproxy` set to `127.0.0.1,localhost,::1` passed. No repository workaround was added. - `npm pack --dry-run` — passed. - Scoped lint on all three changed files and `git diff --check` — passed. ## Compatibility, safety, and release - Breaking changes or migration steps: none; ordinary directory cleanup and existing leaf symlink retention continue unchanged. - Real Hopper/Ghidra, browser, or OS coverage: WSL Ubuntu filesystem and public CLI execution; optional real providers are not involved. - Package or release metadata impact: none. - Security, privacy, process, or containment review: this guards existing root links before deletion. It does not establish race-free containment against concurrent path replacement; cleanup still uses the existing path-based filesystem API. ## Review checklist - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed (the existing documented contract is unchanged). - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:55:40 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4836
No description provided.