Close the free headroom in the clean-machine simulation
Assert arch and signature on every downloaded Mach-O. This is the one genuine gap the simulation had: Rosetta 2 is preinstalled on hosted runners and absent from a factory-fresh Mac, so an x86_64-only llama.cpp, whisper.cpp, Node or uv payload runs green here and dies with "bad CPU type in executable" for the user. llama-server launching under `assert-llama-loads.sh` does not rule that out, because Rosetta makes it launch. The new `macho` check reads `file -b` (`lipo` is an xcrun shim and is gone after masking, as the desktop lane already notes) and keys the expected arch off `uname -m`, so macos-15-intel expects x86_64. It also requires at least an ad-hoc signature on arm64, which closes the AMFI "Killed: 9" class that uv has already been bitten by; the check is skipped on x86_64, where unsigned code loads fine and so is not the same defect. It fails when the scan finds nothing, since an empty scan reads exactly like a clean one. Make absence real rather than PATH-hidden. uv probes well-known interpreter locations and the framework loader ignores PATH entirely, so hiding the toolcache only hid it from `command -v`. Empty /usr/local (it EXISTS on a factory-fresh Mac as a SIP-exempt firmlink, and is empty; it is /usr/local/bin that is absent, so the directory itself stays), move the hosted toolcache and /Library/Frameworks/Python.framework aside, and clear the developer dotdirs and caches. A populated uv or pip cache can also satisfy a resolution that would fail on a user's machine. Every removal goes through --remove and is recorded in the generated restore.sh, guarded so a path the install recreated is not buried inside its own restore. Unset CI, GITHUB_* and RUNNER_* for the installer process only. An installer branching on CI=true is a hidden dependency no consumer exercises. Scoped to the child so the step's own $GITHUB_OUTPUT still resolves. Record spctl --status and csrutil status. Neither is documented for these images and both change what a binary is allowed to do.
This commit is contained in:
parent
7d4311fe58
commit
83c3dba5ab
3 changed files with 116 additions and 7 deletions
45
.github/scripts/clean-machine-env.sh
vendored
45
.github/scripts/clean-machine-env.sh
vendored
|
|
@ -49,6 +49,22 @@ TOOLS="xcode-select xcrun clang clang++ cc c++ gcc g++ git cmake make brew ninja
|
|||
|
||||
note() { echo "[clean-machine] $*"; }
|
||||
|
||||
# Move a path aside and record the reverse in restore.sh. PATH scrubbing only HIDES
|
||||
# these; uv, the py launcher and framework lookups find them regardless, so absence
|
||||
# has to be real. The restore line is guarded: the install may have recreated the
|
||||
# path, and an unguarded `mv` would bury the original inside it.
|
||||
mask_aside() {
|
||||
local src="$1" dst="${2:-$1.masked}" as=""
|
||||
[ -e "$src" ] || return 0
|
||||
[ -w "$(dirname "$src")" ] || as="sudo"
|
||||
if $as mv "$src" "$dst" 2>/dev/null; then
|
||||
note "moved $src aside"
|
||||
printf "[ -e '%s' ] || %s mv '%s' '%s' 2>/dev/null || true\n" "$src" "$as" "$dst" "$src" >> "$RESTORE"
|
||||
else
|
||||
note "WARN could not move $src"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── PATH scrub ────────────────────────────────────────────────────────────────
|
||||
# Keep only OS-default system dirs: drops Homebrew, the hosted Python toolcache,
|
||||
# setup-* shims, pipx, cargo and every other preinstalled developer dir.
|
||||
|
|
@ -116,6 +132,35 @@ if [ "$MODE" = "mask" ]; then
|
|||
note "WARN could not move $app"
|
||||
fi
|
||||
done
|
||||
# /usr/local EXISTS on a factory-fresh Mac: a SIP-exempt firmlink, and empty. What
|
||||
# is absent is its CONTENTS, /usr/local/bin included. So empty it rather than
|
||||
# remove it. Runs before the Homebrew block below so /usr/local/Homebrew is stashed
|
||||
# once, with one restore line, in the right order.
|
||||
if [ -d /usr/local ]; then
|
||||
STASH="$WORK/usr-local"
|
||||
mkdir -p "$STASH"
|
||||
for entry in /usr/local/* /usr/local/.[!.]*; do
|
||||
[ -e "$entry" ] || continue
|
||||
base="$(basename "$entry")"
|
||||
if sudo mv "$entry" "$STASH/$base" 2>/dev/null; then
|
||||
note "emptied /usr/local/$base"
|
||||
printf "[ -e '/usr/local/%s' ] || sudo mv '%s/%s' '/usr/local/%s' 2>/dev/null || true\n" \
|
||||
"$base" "$STASH" "$base" "$base" >> "$RESTORE"
|
||||
else
|
||||
note "WARN could not move $entry"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# The hosted toolcache and the python.org framework are what a PATH scrub cannot
|
||||
# reach: uv discovers interpreters by probing well-known locations.
|
||||
mask_aside "${AGENT_TOOLSDIRECTORY:-$HOME/hostedtoolcache}"
|
||||
mask_aside /Library/Frameworks/Python.framework
|
||||
# Developer dotdirs and caches. A virgin $HOME has none of these, and a populated
|
||||
# uv/pip cache can satisfy a resolution that would fail on a user's machine.
|
||||
for d in .cargo .rustup .nvm .rbenv .pyenv .local .cache \
|
||||
Library/Caches/uv Library/Caches/pip Library/Caches/Homebrew; do
|
||||
mask_aside "$HOME/$d"
|
||||
done
|
||||
for brewdir in /opt/homebrew /usr/local/Homebrew; do
|
||||
if [ -d "$brewdir" ]; then
|
||||
if sudo mv "$brewdir" "${brewdir}.masked" 2>/dev/null; then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue