Repository navigation
fix(bootstrap): preserve symlinks when extracting dmgs - #10949
Conversation
Entire-Checkpoint: 38d01854a6c7
📝 WalkthroughWalkthroughDMG extraction now copies mounted contents without following symlinks, recreates symlink targets, always attempts detachment, and tests loop-like symlink handling on Unix. ChangesDMG symlink-preserving copy
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR fixes a symlink-loop crash in DMG extraction by replacing the generic recursive copy (which followed symlinks) with a new
Confidence Score: 5/5Safe to merge; the scope is narrow (macOS DMG extraction only), the logic is straightforward, and a targeted regression test covers the loop-avoidance behavior. The new helper correctly handles directory symlinks, file symlinks, and regular files without following loops. The un_dmg error-handling rewrite is clean and covers all four outcome combinations. No edge cases appear to be missed. No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "fix(bootstrap): report dmg detach failur..." | Re-trigger Greptile |
Entire-Checkpoint: ac5ac64cabc5
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.5 x -- echo |
20.3 ± 0.9 | 18.4 | 24.0 | 1.00 |
mise x -- echo |
20.9 ± 1.2 | 18.9 | 34.0 | 1.03 ± 0.08 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.5 env |
19.8 ± 0.9 | 17.9 | 25.8 | 1.00 |
mise env |
20.3 ± 1.0 | 18.4 | 24.9 | 1.03 ± 0.07 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.5 hook-env |
20.5 ± 0.9 | 18.7 | 25.5 | 1.00 |
mise hook-env |
20.9 ± 0.9 | 19.1 | 24.4 | 1.02 ± 0.06 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.5 ls |
17.7 ± 0.8 | 16.2 | 21.9 | 1.00 |
mise ls |
18.3 ± 0.9 | 16.9 | 22.9 | 1.04 ± 0.07 |
xtasks/test/perf
| Command | mise-2026.7.5 | mise | Variance |
|---|---|---|---|
| install (cached) | 166ms | 165ms | +0% |
| ls (cached) | 61ms | 60ms | +1% |
| bin-paths (cached) | 63ms | 64ms | -1% |
| task-ls (cached) | 126ms | 128ms | -1% |
Summary
Root cause
DMG images commonly contain an
Applicationssymlink. The generic recursive copy followed that link into the host/Applicationsdirectory, eventually encountering a symlink loop in the installed Xcode SDK. Returning from that copy error also skippedhdiutil detach, leaving the image mounted.Impact
mise bootstrap packages applycan extract DMG-backed brew casks without traversing the host filesystem or leaking mounts after copy failures.Validation
cargo fmt --all -- --checkcargo test --all-features file::tests::test_copy_dir_all_preserve_symlinks_does_not_follow_loopsbrew-cask:kittybootstrap reached successful DMG copy and ejection; it then stopped at the separate existingon_system_conditionallimitationNote
Medium Risk
Changes filesystem behavior on macOS for all
un_dmgcallers (aqua DMG installs and brew cask bootstrap); scope is localized but mistakes could still corrupt installs or leave mounts attached.Overview
DMG extraction now copies mounted volume contents with
copy_dir_all_preserve_symlinksinstead of the generic recursive copy, so entries like anApplicationssymlink are recreated rather than followed into the host filesystem (avoiding symlink loops and accidental traversal of/Applications).un_dmgalways runshdiutil detachafter the copy attempt, surfacing copy failures first and attaching detach errors when both fail.Adds a Unix regression test for a self-referential directory symlink alongside normal file copy.
Reviewed by Cursor Bugbot for commit 057e15a. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit