fix(create): avoid following target symlinks - #2418
Conversation
✅ Deploy Preview for viteplus-preview canceled.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5de4880171
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const stats = fs.lstatSync(projectDirFullPath, { throwIfNoEntry: false }); | ||
| if (!stats || (stats.isDirectory() && isEmpty(projectDirFullPath))) { |
There was a problem hiding this comment.
Remove trailing separators before calling lstat
When the requested target ends in a separator (for example, vp create vite:application --directory linked-project/), path.normalize preserves that separator and POSIX lstatSync("linked-project/") dereferences the final symlink. The link is therefore classified as a real directory, and after the user confirms the ordinary overwrite prompt, clearTargetPath traverses the link and deletes files in its destination—the data-loss case this change is intended to prevent. Strip trailing separators (while preserving filesystem roots) before every classification and cleanup operation, and cover this input in the symlink regression tests.
Useful? React with 👍 / 👎.
Fixes #2419
Summary
lstatSyncinstead of following the final symbolic link.gitRoot cause
The availability check used
existsSyncfollowed byreaddirSync, so a directory symbolic link was treated as the directory it referenced. The cleanup loop then removed child paths through that link.existsSyncalso treated dangling links as missing, while existing regular files reached directory-only operations.Implementation
The target is now inspected with:
This keeps the final filesystem entry distinct from its destination:
The cleanup function performs a fresh
lstatSyncimmediately before mutation, so it also handles a target that disappears while the prompt is open.Validation
vitest run packages/cli/src/create/__tests__: 13 files, 185 tests passedtsc -p packages/cli/tsconfig.json --noEmitgit diff --checkRegression coverage includes real directories, links to empty and populated directories, dangling links, regular files, linked-target preservation, and the existing
.gitpreservation behavior.