[GH-ISSUE #1816] [Bug] uninstall --purge-data follows a symlinked .rea root and deletes target data #611

Closed
opened 2026-10-15 18:26:37 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @shoyann on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1816

Before submitting

  • I searched open and closed issues and pull requests for a related report.
  • This report contains no credentials, private paths, or sensitive target data.

Area

Setup, packaging, or upgrade / CLI

Observed behavior

rea uninstall --purge-data follows a symbolic link at ~/.rea and recursively removes cache and state from the link target. It exits successfully and reports both items as removed.

This reproduces with the compiled CLI from f178bf1c00139e1b7fe2d14fcfe1f558fe08fbe2, using an isolated temporary HOME. Both sentinel files in a sibling directory outside the managed root were deleted. No real user data or installation was used.

Reproduction

From a built source checkout on Linux, create an isolated fixture and invoke the CLI with a fresh environment:

fixture="$(mktemp -d)"
mkdir -p "$fixture/home" "$fixture/unrelated-application/cache" "$fixture/unrelated-application/state"
printf 'keep cache\n' > "$fixture/unrelated-application/cache/keep.txt"
printf 'keep state\n' > "$fixture/unrelated-application/state/keep.txt"
ln -s "$fixture/unrelated-application" "$fixture/home/.rea"
env -i PATH="$PATH" HOME="$fixture/home" node scripts/rea.mjs uninstall --purge-data --json
ls "$fixture/unrelated-application/cache/keep.txt" "$fixture/unrelated-application/state/keep.txt"

The last command reports both files missing. The .rea link itself remains.

Expected behavior

Retain both target directories and their contents, and report the managed data root as a symbolic link. A dangling .rea link should also be retained and reported rather than treated as an absent cache/state path. Ordinary directories should keep the existing purge behavior.

The installation documentation states that purge removes only REA cache/state under ~/.rea and retains symbolic-link purge paths rather than following them.

Impact and scope

Explicit --purge-data can remove data outside the managed directory when .rea is a link. Existing leaf-link protection for .rea/cache and .rea/state does not cover this parent-link case. This is a local filesystem cleanup issue; no browser or analysis provider is involved.

REA version

Source revision f178bf1c00139e1b7fe2d14fcfe1f558fe08fbe2.

Runtime and platform

Node.js 24.18.0, npm 11.16.0, Ubuntu/WSL x64. Native Windows and macOS have not been exercised.

Earliest failure stage

Cleanup, cancellation, or lifecycle.

Relevant output

{
  "status": "complete",
  "items": [
    {"name": "cache", "status": "removed"},
    {"name": "state", "status": "removed"}
  ]
}

Excerpt only; unrelated skipped client entries are omitted.

Analysis

systemUninstallHost().purgeData() passes the cache/state paths directly to removeManagedPath. That function uses lstat only on each final path before recursive removal; a symbolic-link parent has already been followed at that point. The managed .rea root needs its own admission check before these removals.

I am preparing a focused fix with real-filesystem and public CLI regressions for this case.

Originally created by @shoyann on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1816 ### Before submitting - [x] I searched open and closed issues and pull requests for a related report. - [x] This report contains no credentials, private paths, or sensitive target data. ### Area Setup, packaging, or upgrade / CLI ### Observed behavior `rea uninstall --purge-data` follows a symbolic link at `~/.rea` and recursively removes `cache` and `state` from the link target. It exits successfully and reports both items as `removed`. This reproduces with the compiled CLI from `f178bf1c00139e1b7fe2d14fcfe1f558fe08fbe2`, using an isolated temporary HOME. Both sentinel files in a sibling directory outside the managed root were deleted. No real user data or installation was used. ### Reproduction From a built source checkout on Linux, create an isolated fixture and invoke the CLI with a fresh environment: ```sh fixture="$(mktemp -d)" mkdir -p "$fixture/home" "$fixture/unrelated-application/cache" "$fixture/unrelated-application/state" printf 'keep cache\n' > "$fixture/unrelated-application/cache/keep.txt" printf 'keep state\n' > "$fixture/unrelated-application/state/keep.txt" ln -s "$fixture/unrelated-application" "$fixture/home/.rea" env -i PATH="$PATH" HOME="$fixture/home" node scripts/rea.mjs uninstall --purge-data --json ls "$fixture/unrelated-application/cache/keep.txt" "$fixture/unrelated-application/state/keep.txt" ``` The last command reports both files missing. The `.rea` link itself remains. ### Expected behavior Retain both target directories and their contents, and report the managed data root as a symbolic link. A dangling `.rea` link should also be retained and reported rather than treated as an absent cache/state path. Ordinary directories should keep the existing purge behavior. The [installation documentation](https://github.com/morluto/rea/blob/f178bf1c00139e1b7fe2d14fcfe1f558fe08fbe2/docs/installation.md#L866-L871) states that purge removes only REA cache/state under `~/.rea` and retains symbolic-link purge paths rather than following them. ### Impact and scope Explicit `--purge-data` can remove data outside the managed directory when `.rea` is a link. Existing leaf-link protection for `.rea/cache` and `.rea/state` does not cover this parent-link case. This is a local filesystem cleanup issue; no browser or analysis provider is involved. ### REA version Source revision `f178bf1c00139e1b7fe2d14fcfe1f558fe08fbe2`. ### Runtime and platform Node.js 24.18.0, npm 11.16.0, Ubuntu/WSL x64. Native Windows and macOS have not been exercised. ### Earliest failure stage Cleanup, cancellation, or lifecycle. ### Relevant output ```json { "status": "complete", "items": [ {"name": "cache", "status": "removed"}, {"name": "state", "status": "removed"} ] } ``` Excerpt only; unrelated skipped client entries are omitted. ### Analysis `systemUninstallHost().purgeData()` passes the cache/state paths directly to `removeManagedPath`. That function uses `lstat` only on each final path before recursive removal; a symbolic-link parent has already been followed at that point. The managed `.rea` root needs its own admission check before these removals. I am preparing a focused fix with real-filesystem and public CLI regressions for this case.
bsakaguchi 2026-10-15 18:26:37 +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#611
No description provided.