From 4a7a835c0f5be2170435fe2ca28d1215131d8cc2 Mon Sep 17 00:00:00 2001 From: Neil Date: Sun, 20 Sep 2026 22:46:35 -0700 Subject: [PATCH] fix(worktree): refuse the drvfs volume root and the automount under a WSL UNC alias `\\wsl.localhost\Ubuntu\mnt\c` is the whole C: volume and `\\wsl.localhost\Ubuntu\mnt` holds every drvfs volume. Neither is caught by the root check in `isDangerousWorktreeRemovalPath` (their win32 root is the distro share) nor by the Windows-profile rule on the drive form (`C:\` is not `C:\Users`), so both read as deletable. Measured on a Windows 11 host with WSL2: `rm -rf` inside the distro on the `/mnt/c` spelling deletes on the Windows drive. --- src/main/worktree-removal-home-guard.test.ts | 5 +++++ src/main/worktree-removal-home-guard.ts | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/worktree-removal-home-guard.test.ts b/src/main/worktree-removal-home-guard.test.ts index 14ab1ac674f..e9e434b2ed2 100644 --- a/src/main/worktree-removal-home-guard.test.ts +++ b/src/main/worktree-removal-home-guard.test.ts @@ -93,7 +93,12 @@ describe('path-shape home detection', () => { // `C:\Users\bob` wearing a Linux spelling, not a directory in the distro. ['\\\\wsl.localhost\\Ubuntu\\mnt\\c\\Users\\bob', true], ['\\\\wsl$\\Ubuntu\\mnt\\c\\Users', true], + // The volume itself, and the automount that holds every volume, contain the profile. + ['\\\\wsl.localhost\\Ubuntu\\mnt\\c', true], + ['\\\\wsl.localhost\\Ubuntu\\mnt\\c\\', true], + ['\\\\wsl.localhost\\Ubuntu\\mnt', true], ['\\\\wsl.localhost\\Ubuntu\\mnt\\c\\Users\\bob\\ws\\wt', false], + ['\\\\wsl.localhost\\Ubuntu\\mnt\\c\\src\\repo', false], // `/MNT` is an ordinary case-sensitive Linux directory, never the automount. ['\\\\wsl.localhost\\Ubuntu\\MNT\\c\\Users\\bob', false] ])('WSL drvfs %s -> %s', (worktreePath, expected) => { diff --git a/src/main/worktree-removal-home-guard.ts b/src/main/worktree-removal-home-guard.ts index c8466610cc8..7dde11b53d8 100644 --- a/src/main/worktree-removal-home-guard.ts +++ b/src/main/worktree-removal-home-guard.ts @@ -189,9 +189,16 @@ function isLikelyWslDistroHomeDirectory(resolvedWorktreePath: string, pathOps: P const linuxPath = trimTrailingSlash(wsl.linuxPath) const drivePath = toWindowsWslDrivePath(linuxPath) if (drivePath) { - return isLikelyWindowsUserProfileDirectory(win32.resolve(drivePath), win32) + const resolvedDrivePath = win32.resolve(drivePath) + // Why: `/mnt/c` is the whole volume. `C:\` is refused as a root before this guard runs; its + // drvfs spelling has to be refused here, since its win32 root is the distro share. + return ( + win32.parse(resolvedDrivePath).root === resolvedDrivePath || + isLikelyWindowsUserProfileDirectory(resolvedDrivePath, win32) + ) } - return wsl.linuxPath === '/' || isPosixHomeRoot(linuxPath) + // Why `/mnt`: the automount parent holds every drvfs volume, so it contains every profile. + return wsl.linuxPath === '/' || linuxPath === '/mnt' || isPosixHomeRoot(linuxPath) } function isWslUncRemovalPath(resolvedWorktreePath: string): boolean {