Replace the screenshot/OCR/keystroke driving of Apple's Recovery with a "PE": BaseSystem.dmg (a journaled HFS+ volume, writable from Linux) with one LaunchDaemon added (makeRecoveryPE) that runs /Volumes/VMIX/run.sh as root at boot, records the status and powers off. launchd loads it alongside its signed cache (verified on Tahoe 26.6.2); same idea as AutoNBI/Imagr NetBoot images. - makeImage: the PE runs vmix-install.sh (erase, installer app, SharedSupport pkgdmg, startosinstall). Progress is read from the serial console (boot-args serial=3 -v, VMIX-* markers) and screenshots (brightness only). Fully offline; prepare now takes ~5 min instead of ~10. - customizeImage: boots the PE with the image attached and runs the template offline against the mounted System/Data volumes; OpenCore ScanPolicy restricted to HFS+/SATA so only the PE can boot. One PE boot ~30 s. The installed macOS is never booted for customization, so nothing depends on launchd/BTM approval or a first-boot agent (removed). - templates rewritten for offline use: generalize creates the user with dscl -f (admin, home, auto-login kcpassword, Setup Assistant suppression, hostname, locale, timezone, keyboard type, container resize); remote-access, no-updates, performance edit the target's plists. - makeBootDisk: build-time OpenCore variant (serial console, ScanPolicy). - vm-driver.py rewritten: passive observation only (serial markers, kernel boots, panics, brightness), disk+serial-aware hang watchdog, reboot-death reset, halt/loginwindow detection. No OCR/tesseract. - OpenCore: four SMBIOS DIMMs for MacPro7,1 (no "Memory Modules Misconfigured" warning). - tools/soak.sh: repeatability harness. Verified on daku: base install 23 min end to end; basic + generalize in three ~30 s PE boots; the result auto-logs into the desktop with the created user. Root cause of the "first-boot hang" (from the serial log): the guest's restart path panics (IOPlatformHaltRestartAction -> AppleSMC, SMCWDT smcWriteKey kSMCBadCommand, nested panic) because the pinned OSX-KVM Lilu disables itself on macOS 26, so VirtualSMC never loads. Handled by the driver (reset within 60 s); kext update to follow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsESshRCoBoUVWV9qKURUF
45 lines
2.1 KiB
Nix
45 lines
2.1 KiB
Nix
{ pkgs, lib, system, ... }:
|
|
let
|
|
upstream = (lib.importJSON ./upstream.json).${system};
|
|
macos = rec {
|
|
inherit upstream;
|
|
qemu = import ./helpers/qemu.nix { inherit pkgs lib; };
|
|
ident = import ./helpers/ident.nix { inherit lib; };
|
|
macserial = import ./helpers/macserial.nix { inherit pkgs upstream; };
|
|
fetchRecovery = import ./helpers/fetchRecovery.nix { inherit pkgs upstream; };
|
|
installerPayload = import ./helpers/installerPayload.nix { inherit pkgs lib; };
|
|
makeOpenCore = import ./helpers/makeOpenCore.nix { inherit pkgs lib upstream macserial qemu; };
|
|
makeBootDisk = import ./helpers/makeBootDisk.nix { inherit pkgs lib; };
|
|
makeRecoveryPE = import ./helpers/makeRecoveryPE.nix { inherit pkgs lib; };
|
|
makeVmixVolume = import ./helpers/makeVmixVolume.nix { inherit pkgs lib; };
|
|
installBootloader = import ./helpers/installBootloader.nix { inherit pkgs lib; };
|
|
vmixReadback = import ./helpers/vmix-readback.nix { inherit pkgs lib; };
|
|
vmDriver = ./helpers/vm-driver.py;
|
|
makeImage = import ./helpers/makeImage.nix {
|
|
inherit pkgs lib qemu ident installerPayload makeOpenCore makeBootDisk makeVmixVolume installBootloader vmixReadback vmDriver;
|
|
};
|
|
customizeImage = import ./helpers/customizeImage.nix {
|
|
inherit pkgs lib qemu ident makeVmixVolume makeOpenCore makeBootDisk installBootloader vmixReadback vmDriver;
|
|
};
|
|
customizeImageFold = builtins.foldl' customizeImage;
|
|
templates = import ./templates { inherit pkgs lib; };
|
|
};
|
|
|
|
tahoe = import ./tahoe { inherit pkgs lib system macos; };
|
|
|
|
# Recursively add .generalize to every image leaf (same shape as windows)
|
|
addGeneralize = val:
|
|
if val ? _vmixOsType then
|
|
val // { generalize = args:
|
|
let
|
|
templateArgs = builtins.removeAttrs args [ "vncDisplay" ];
|
|
displayArgs = lib.optionalAttrs (args ? vncDisplay) { inherit (args) vncDisplay; };
|
|
in macos.customizeImage val (macos.templates.generalize templateArgs // displayArgs);
|
|
}
|
|
else if builtins.isAttrs val then
|
|
lib.mapAttrs (_: addGeneralize) val
|
|
else val;
|
|
in
|
|
macos // {
|
|
images = addGeneralize { inherit tahoe; };
|
|
}
|