improve(setup): keep WSL operations inside the app-owned directory#1006
improve(setup): keep WSL operations inside the app-owned directory#1006calebeden wants to merge 2 commits into
Conversation
Validate distro names and canonical install paths before setup cleanup, installation, and rollback filesystem operations. Reject reparse-point ancestors and revalidate ownership before each recursive-delete retry. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f19f98b7-f377-4da5-a7ce-0f1ae34153cf
Preserve the finalized WSL quoting ownership rows from openclaw#1001 and append the WSL distro install-path policy row. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f19f98b7-f377-4da5-a7ce-0f1ae34153cf
|
Codex review: found issues before merge. Reviewed July 17, 2026, 8:53 PM ET / July 18, 2026, 00:53 UTC. Summary Reproducibility: yes. for the reported unsafe-path behavior: the new tests and current-head Dev Box proof exercise traversal rejection before distro-targeting and recursive-delete operations. The compatibility regression is source-reproducible because the new policy rejects any configured name outside its ASCII allowlist before cleanup begins. Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Maintainer decision needed
Security Review findings
Review detailsBest possible solution: Preserve already-safe custom distro names through canonical immediate-child containment and reparse-point checks, rejecting only names or paths that resolve outside the app-owned root; adopt the narrower name grammar only if maintainers explicitly choose that compatibility break and document an upgrade path. Do we have a high-confidence way to reproduce the issue? Yes for the reported unsafe-path behavior: the new tests and current-head Dev Box proof exercise traversal rejection before distro-targeting and recursive-delete operations. The compatibility regression is source-reproducible because the new policy rejects any configured name outside its ASCII allowlist before cleanup begins. Is this the best way to solve the issue? No, not yet: centralized canonical containment and reparse validation are the right safety mechanism, but an unconditional broad name allowlist is not the narrowest solution until maintainers approve breaking existing safe custom-name workflows. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 4518dd87ed2b. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (4 earlier review cycles)
|
|
Marking as draft until I can further test this tomorrow |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
The containment policy is well designed: canonical immediate-child checks, tight distro-name allowlisting, reparse-point ancestor rejection, retry-time revalidation, and real junction-based TOCTOU tests are strong. There is no existing repository path-policy utility that should replace this owner. The remaining merge blocker is compatibility for existing custom distro names. Previously accepted names containing spaces or non-ASCII characters can now fail before replacement, cleanup, rollback, or uninstall filesystem work. That can strand an existing managed installation even though the new-install policy is safer. Please choose and prove a migration contract:
Add integration-style tests for replacement and uninstall/rollback of a legacy custom-name distro, proving nothing outside the app-owned root is touched. Also add boundary coverage for exactly 64 vs 65 characters and a rollback test asserting invalid/traversal names fail closed without deleting external paths. The first-use TOCTOU limitation is documented and acceptable for this PR, but the legacy-name upgrade/uninstall path needs a concrete supported behavior before merge. |
Additional instructions
MUST: Keep Allow edits from maintainers enabled for this PR so maintainers
can help update the branch when needed.
What Problem This Solves
Resolves a problem where developers running the standalone SetupEngine with a custom WSL distro name could cause cleanup or installation paths to resolve outside
%LOCALAPPDATA%\OpenClawTray\wsl. Because cleanup recursively deletes the resolved path, a traversal value such as..\..could target an unintended directory.No known user incident prompted this change. The packaged application supplies its fixed distro name after config/environment loading, so the exposed path is the repository/developer SetupEngine flow.
Why This Change Was Made
Setup now derives every WSL distro install path through one policy that validates the distro name, canonicalizes the path, requires it to be an immediate child of the app-owned
wslroot, and rejects reparse points at the trusted local-data root or WSL root. Recursive cleanup revalidates ownership before every retry, and rollback unregisters the name-based distro before attempting guarded filesystem cleanup.The remaining same-user check-to-use filesystem race is accepted as a non-goal: additional checks can narrow it, but fully atomic deletion or
wsl --installwould require handle-based operating-system support that these APIs do not expose.User Impact
Developers invoking SetupEngine directly now receive a terminal validation error before distro-targeting WSL commands or recursive cleanup run when a distro name or install path is unsafe. Generic WSL availability preflight may run first. Shipped/default distro names continue to work unchanged; packaged application users should see no behavioral difference.
Evidence
The SetupEngine tests exercise real Windows junctions and verify that traversal values are rejected before distro-targeting commands run, paths outside the expected immediate child are never deleted, reparse-point ancestors are rejected, and a parent swapped to a junction during retry backoff is detected before the next recursive-delete attempt. The redirected sentinel file remains intact.
A current-head live Dev Box run additionally verified a valid WSL install and uninstall, followed by rejection of
..\..with the outside sentinel preserved and no distro-targeting or recursive-delete operation logged.Three independent dual-model review passes found no blocking correctness issue. The only recurring observation was the documented same-user check-to-use limitation.
Change Type
Scope
winnodeValidation
./build.ps1— passed; Shared, CLI, WinNode CLI, SetupEngine, and WinUI built successfullydotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restore— 2,863 passed, 31 skipped, 0 faileddotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore— 1,717 passed, 0 skipped, 0 faileddotnet test ./tests/OpenClaw.SetupEngine.Tests/OpenClaw.SetupEngine.Tests.csproj --no-restore— 443 passed, 0 skipped, 0 failedReal Behavior Proof
63e5a9b9cb3939b2e462c708d702c22e66ca8018OpenClaw.SetupEngine, ran valid headless setup and destructive uninstall against isolated paths underC:\OpenClawProof, then ran setup with distro name..\..and an outside sentinelOpenClawProofatC:\OpenClawProof\Local\wsl\OpenClawProof; uninstall removed both the registration and install path; the unsafe name exited 1 atcleanup-distro, preservedPRESERVE-ME, and logged zero distro-targeting commands and zero recursive distro deletionsLive Dev Box proof
1. Current branch, full head SHA, and successful runner build
2. Valid install: setup complete, registered distro, and canonical install path
3. Valid uninstall: distro registration and install path absent
4. Unsafe name: terminal rejection, preserved outside sentinel, and zero destructive operations
Security Impact
Yes, explain the risk and mitigation: Existingwsl --install --locationand recursive cleanup inputs are now constrained to a validated app-owned path. This reduces the execution/data risk; it does not add a new command or expand access. A same-user process can still theoretically race a filesystem check, which is documented as an accepted limitation.Compatibility and Migration
Review Conversations