macOS Tahoe: working fully-offline unattended install
The base image (macos.images.tahoe.upstream) now installs and boots end to end with no dependency on Apple's servers — proven on the KVM host: the finished qcow2 boots standalone (OpenCore from its own ESP) to the macOS 26.6.2 loginwindow. Install driving (vm-driver.py, screenshot + OCR over QMP): - map the whole InstallAssistant.pkg as a raw disk and dd it byte-exact into the app as SharedSupport.dmg (it is a pkgdmg: xar + koly footer — the bare xar member fails startosinstall with "pkgdmg is missing a footer") - offline install: no NIC + /etc/hosts blackhole of Apple install/verify endpoints so startosinstall's calls fail fast instead of hanging (SecureBootModel=Disabled allows the sealed-volume install offline) - keep the recovery display awake with a tiny mouse jiggle; coarse settle fingerprint so the cursor is not seen as a change - guest watchdog re-erases/retries a startosinstall attempt that stalls or runs too long (prepare is intermittently slow) - disk-aware boot watchdog: QMP system_reset only when the screen is dark AND the disk is idle (never interrupts a slow-but-working boot); recovery-restart if a post-prepare reboot lands back on recovery - detect the bright loginwindow and power the VM down (install complete); a black + disk-idle screen is treated as a completed halt - copy OpenCore into the image ESP so it boots standalone recovery.file pins a content-addressed local BaseSystem.dmg (Apple's CDN load-balances Sequoia/Tahoe during the rollout). fetchRecovery retries to the pinned hash when used instead. Not yet done: .generalize (user creation) — the first-boot agent LaunchDaemon is blocked by Ventura+ Background Task Management on headless boots; next step is offline user injection from the agent pkg postinstall. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsESshRCoBoUVWV9qKURUF
This commit is contained in:
parent
242e48a5fc
commit
58a317f5d2
9 changed files with 415 additions and 128 deletions
|
|
@ -1,14 +1,25 @@
|
|||
#!/bin/sh
|
||||
# vmix agent: LaunchDaemon that runs at every boot as root. If a volume named
|
||||
# VMIX carrying vmix-run.sh is attached, run it, record the result on the
|
||||
# volume and power off. Without the volume it is a no-op (normal boot).
|
||||
# This is the macOS counterpart of the Windows Audit Mode RunOnce script.
|
||||
# vmix agent: LaunchDaemon that runs at every boot as root (installed by the vmix
|
||||
# agent pkg via startosinstall --installpackage). If a volume named VMIX carrying
|
||||
# vmix-run.sh is attached, run it, record the result on the volume and power off.
|
||||
# Without the volume it is a no-op (normal boot). Counterpart of the Windows Audit
|
||||
# Mode RunOnce script; the generalize step removes it once the image is sealed.
|
||||
LOG=/var/log/vmix-agent.log
|
||||
exec >>"$LOG" 2>&1
|
||||
echo "=== vmix agent: $(date) ==="
|
||||
# The agent pkg bootstraps this daemon during the OS install (to approve it past
|
||||
# Background Task Management, so launchd runs it at first boot). Don't do the job
|
||||
# in that installer environment — only on the installed system's first boot.
|
||||
if pgrep -x bootinstalld >/dev/null 2>&1 || pgrep -qx "Installer Progress" 2>/dev/null \
|
||||
|| [ -d /System/Volumes/Update/mnt1 ]; then
|
||||
echo "vmix agent: OS installer is running, skipping"
|
||||
exit 0
|
||||
fi
|
||||
# let DiskArbitration settle so the VMIX volume is mountable
|
||||
sleep 5
|
||||
V=/Volumes/VMIX
|
||||
i=0
|
||||
while [ ! -f "$V/vmix-run.sh" ] && [ $i -lt 60 ]; do
|
||||
while [ ! -f "$V/vmix-run.sh" ] && [ $i -lt 30 ]; do
|
||||
diskutil mount VMIX >/dev/null 2>&1
|
||||
sleep 2
|
||||
i=$((i + 1))
|
||||
|
|
@ -24,6 +35,7 @@ rc=$?
|
|||
echo "vmix agent: vmix-run.sh exited $rc"
|
||||
echo "$rc" >"$V/vmix-run.status"
|
||||
cp "$LOG" "$V/vmix-agent.log" 2>/dev/null
|
||||
cp /var/log/vmix-agent-install.log "$V/vmix-agent-install.log" 2>/dev/null
|
||||
sync
|
||||
sleep 2
|
||||
diskutil unmount force "$V" >/dev/null 2>&1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue