Describe the bug
Same root-cause family as #79 and #943: a bare stat call resolves to GNU coreutils' stat when gnubin is earlier in PATH. This instance is in needs_permissions_repair() (lib/optimize/tasks.sh) — and unlike #943 it fails silently, by returning a wrong answer instead of crashing:
owner=$(stat -f %Su "$HOME" 2> /dev/null || echo "")
if [[ -n "$owner" && "$owner" != "$USER" ]]; then
return 0 # "repair needed"
fi
With GNU stat, -f means "filesystem mode" and %Su is treated as a filename. The command exits 1 (the %Su "file" doesn't exist — that error goes to stderr, suppressed by 2>/dev/null) but still prints a multi-line filesystem report for $HOME to stdout:
$ stat -f %Su "$HOME"
stat: cannot read file system information for '%Su': No such file or directory
File: "/Users/xxx"
ID: 10000110000001a Namelen: ? Type: apfs
Block size: 4096 Fundamental block size: 4096
...
So owner captures that multi-line text, which is non-empty and never equals $USER, and the function always returns 0. Result: every mo optimize run executes sudo diskutil resetUserPermissions / $uid, which traverses the entire home directory resetting ownership/ACLs — several minutes on a typical dev machine — and can strip custom ACLs the user set intentionally. It then reports success ("User directory permissions repaired"), so the misfire is invisible.
Actual home directory permissions are fine (verified with /usr/bin/stat below).
STAT_BSD already exists for exactly this reason (lib/core/base.sh) — this call site just doesn't use it.
Steps to reproduce
- Have GNU coreutils' gnubin before
/usr/bin in PATH (brew install coreutils, PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH")
- Run
sudo -v && mo optimize
- The "Permission Repair" step runs the full multi-minute
diskutil resetUserPermissions on every invocation, despite correct permissions
The detection logic in isolation:
$ v=$(stat -f %Su "$HOME" 2>/dev/null || echo ""); [[ -n "$v" && "$v" != "$USER" ]] && echo "false positive"
false positive
Expected behavior
With correct ownership/writability, the step should print "User directory permissions already optimal" and skip the repair. One-word fix:
owner=$($STAT_BSD -f %Su "$HOME" 2> /dev/null || echo "")
Given #79 and #943 fixed the same class at other call sites, it may be worth a sweep for remaining bare stat calls.
Debug logs
Debug output
➤ Permission Repair
[DEBUG] === Disk Permissions Repair ===
[DEBUG] Reset user directory permissions
[DEBUG] Method: Run diskutil resetUserPermissions on user home directory
[DEBUG] Condition: Only runs if permissions issues are detected
[DEBUG] Expected outcome: Fixed file access issues, correct ownership
[DEBUG] Risk Level: MEDIUM, Requires sudo, modifies permissions
- Repairing disk permissions...
Verification that actual permissions are healthy (BSD stat):
$ /usr/bin/stat -f "%N owner=%Su mode=%Sp" "$HOME" "$HOME/Library" "$HOME/Library/Preferences"
/Users/xxx owner=xxx mode=drwxr-x---
/Users/xxx/Library owner=xxx mode=drwx------
/Users/xxx/Library/Preferences owner=xxx mode=drwx------
Environment
Mole version 1.44.1
macOS: 26.5.2
Architecture: arm64
Kernel: 25.5.0
SIP: Enabled
Disk Free: 213.21GB
Install: Manual
Shell: /bin/zsh
Additional context
Related: #79 (introduced the STAT_BSD compatibility helper), #943 (same root cause in the Periodic Maintenance freshness check, fixed in 4aaad95). This call site was likely missed because it misdetects silently rather than erroring.
Describe the bug
Same root-cause family as #79 and #943: a bare
statcall resolves to GNU coreutils'statwhen gnubin is earlier in PATH. This instance is inneeds_permissions_repair()(lib/optimize/tasks.sh) — and unlike #943 it fails silently, by returning a wrong answer instead of crashing:With GNU stat,
-fmeans "filesystem mode" and%Suis treated as a filename. The command exits 1 (the%Su"file" doesn't exist — that error goes to stderr, suppressed by2>/dev/null) but still prints a multi-line filesystem report for$HOMEto stdout:So
ownercaptures that multi-line text, which is non-empty and never equals$USER, and the function always returns 0. Result: everymo optimizerun executessudo diskutil resetUserPermissions / $uid, which traverses the entire home directory resetting ownership/ACLs — several minutes on a typical dev machine — and can strip custom ACLs the user set intentionally. It then reports success ("User directory permissions repaired"), so the misfire is invisible.Actual home directory permissions are fine (verified with
/usr/bin/statbelow).STAT_BSDalready exists for exactly this reason (lib/core/base.sh) — this call site just doesn't use it.Steps to reproduce
/usr/binin PATH (brew install coreutils,PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH")sudo -v && mo optimizediskutil resetUserPermissionson every invocation, despite correct permissionsThe detection logic in isolation:
Expected behavior
With correct ownership/writability, the step should print "User directory permissions already optimal" and skip the repair. One-word fix:
owner=$($STAT_BSD -f %Su "$HOME" 2> /dev/null || echo "")Given #79 and #943 fixed the same class at other call sites, it may be worth a sweep for remaining bare
statcalls.Debug logs
Debug output
Verification that actual permissions are healthy (BSD stat):
Environment
Additional context
Related: #79 (introduced the
STAT_BSDcompatibility helper), #943 (same root cause in the Periodic Maintenance freshness check, fixed in 4aaad95). This call site was likely missed because it misdetects silently rather than erroring.