Add a macOS image pipeline mirroring the Windows one: unattended install,
generalization and user creation, driven end to end in QEMU on a KVM host.
lib/images/macos:
- makeOpenCore: OSX-KVM OpenCore ESP with a config.plist rewritten per image —
SMBIOS model + serial/MLB (macserial) + UUID + ROM=en0 MAC (built-in NIC pinned
to PciRoot(0x0)/Pci(0x12,0x0)) for Apple ID / iMessage / App Store; boot disk;
OpenCore self-entry hidden. ident.nix derives MAC+UUID from a seed so the NixOS
module and CLI know the NIC MAC at eval time.
- makeImage: one QEMU session driven by vm-driver.py (QMP + screenshot settle
detection + OCR of the menu bar) — boots the recovery via OpenCore, opens
Terminal (Ctrl-F2 -> Utilities -> Terminal), types the bootstrap command;
vmix-install.sh erases the disk as APFS, lays down the host-extracted installer
app skeleton + a byte-exact SharedSupport.dmg (raw disk mapped to that byte range
of the pkg, dd'd in — Recovery's xar truncates an 18 GB member), runs
startosinstall with the vmix agent pkg. OpenCore is then copied into the image's
ESP so it boots standalone with OVMF.
- customizeImage / templates: boot the image with a FAT-then-HFS+ VMIX volume; the
vmix agent (LaunchDaemon) runs a script as root, records status and powers off —
the macOS counterpart of Windows Audit Mode. generalize creates the admin user +
auto-login (kcpassword), suppresses Setup Assistant, sets hostname/timezone,
grows APFS, and assigns a fresh SMBIOS identity. Templates: noUpdates,
performance, remoteAccess (ssh + screen sharing).
- fetchRecovery: Apple recovery BaseSystem, retried until the pinned Tahoe build
(osrecovery load-balances Sequoia/Tahoe during the rollout). makeAgentPkg builds
a distribution flat pkg on Linux (xar+bom+cpio) for startosinstall --installpackage.
CLI: vmix build/copy/run for macOS (run --macos --vnc, reads the image's MAC from
its ESP), and a `vmix macserial` helper. NixOS module: disks.os.file carrying
_vmixOsType="macos" auto-enables the macOS QEMU profile (AppleSMC+OSK, Skylake
CPU spoof, AHCI system disk, VMware SVGA, pinned NIC); macos.{enable,cpu,mac}.
Status: proven through the installer prepare phase (SharedSupport.dmg mounts,
version 26.6.2 read, SU catalog loads). Two blockers remain, documented in
lib/images/macos/README.md: (1) startosinstall's OSISVerifyBaseSystemOperation
rejects the byte-identical plain-UDIF SharedSupport as "pkgdmg missing a footer"
in this Tahoe recovery/VM; (2) Apple's CDN unreliably serves the Tahoe recovery
during rollout (self-hosting the verified BaseSystem is the robust fix).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsESshRCoBoUVWV9qKURUF
75 lines
3 KiB
Nix
75 lines
3 KiB
Nix
# Distribution-style flat package (xar + bom + cpio, built on Linux) for
|
|
# `startosinstall --installpackage`: installs the vmix agent LaunchDaemon and
|
|
# marks Setup Assistant as done so the first boot lands on loginwindow.
|
|
{ pkgs, lib, ... }:
|
|
{ version ? "1.0" }:
|
|
let
|
|
id = "ch.vmix.agent";
|
|
# nixpkgs' bomutils aborts under _FORTIFY_SOURCE
|
|
bomutils = pkgs.bomutils.overrideAttrs (_: { hardeningDisable = [ "fortify" ]; });
|
|
postinstall = pkgs.writeText "postinstall" ''
|
|
#!/bin/sh
|
|
# $3 = target volume
|
|
T="$3"
|
|
mkdir -p "$T/private/var/db"
|
|
touch "$T/private/var/db/.AppleSetupDone"
|
|
chown root:wheel "$T/private/var/db/.AppleSetupDone"
|
|
chmod 755 "$T/Library/vmix/agent.sh"
|
|
chown -R root:wheel "$T/Library/vmix" "$T/Library/LaunchDaemons/${id}.plist"
|
|
exit 0
|
|
'';
|
|
in
|
|
pkgs.runCommand "vmix-agent-${version}.pkg" {
|
|
nativeBuildInputs = [ pkgs.xar bomutils pkgs.cpio pkgs.gzip ];
|
|
} ''
|
|
mkdir -p root/Library/LaunchDaemons root/Library/vmix scripts flat/vmix-agent.pkg
|
|
cp ${../guest/agent.sh} root/Library/vmix/agent.sh
|
|
cp ${../guest/ch.vmix.agent.plist} root/Library/LaunchDaemons/${id}.plist
|
|
chmod 755 root/Library/vmix/agent.sh
|
|
chmod 644 root/Library/LaunchDaemons/${id}.plist
|
|
cp ${postinstall} scripts/postinstall
|
|
chmod 755 scripts/postinstall
|
|
|
|
NFILES=$(find root | wc -l)
|
|
KBYTES=$(du -sk root | cut -f1)
|
|
(cd root && find . | cpio -o --format odc --owner 0:0 --quiet | gzip -c > ../flat/vmix-agent.pkg/Payload)
|
|
(cd scripts && find . | cpio -o --format odc --owner 0:0 --quiet | gzip -c > ../flat/vmix-agent.pkg/Scripts)
|
|
mkbom -u 0 -g 80 root flat/vmix-agent.pkg/Bom
|
|
|
|
cat > flat/vmix-agent.pkg/PackageInfo <<XML
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<pkg-info overwrite-permissions="true" relocatable="false" identifier="${id}" postinstall-action="none" version="${version}" format-version="2" generated-by="vmix" auth="root">
|
|
<payload installKBytes="$KBYTES" numberOfFiles="$NFILES"/>
|
|
<bundle-version/>
|
|
<upgrade-bundle/>
|
|
<update-bundle/>
|
|
<atomic-update-bundle/>
|
|
<strict-identifier/>
|
|
<relocate/>
|
|
<scripts>
|
|
<postinstall file="./postinstall"/>
|
|
</scripts>
|
|
</pkg-info>
|
|
XML
|
|
cat > flat/Distribution <<XML
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<installer-gui-script minSpecVersion="1">
|
|
<title>vmix agent</title>
|
|
<options customize="never" require-scripts="false" hostArchitectures="x86_64,arm64" rootVolumeOnly="true"/>
|
|
<product id="${id}" version="${version}"/>
|
|
<choices-outline>
|
|
<line choice="default">
|
|
<line choice="${id}"/>
|
|
</line>
|
|
</choices-outline>
|
|
<choice id="default"/>
|
|
<choice id="${id}" visible="false">
|
|
<pkg-ref id="${id}"/>
|
|
</choice>
|
|
<pkg-ref id="${id}" version="${version}" onConclusion="none" installKBytes="$KBYTES">#vmix-agent.pkg</pkg-ref>
|
|
</installer-gui-script>
|
|
XML
|
|
sed -i 's/^ //' flat/vmix-agent.pkg/PackageInfo flat/Distribution
|
|
(cd flat && xar --compression none -cf $out Distribution vmix-agent.pkg)
|
|
xar -t -f $out
|
|
''
|