8.1 KiB
macOS VM base-image provisioning repair
Status: implementation in progress
Opened: 2026-07-23
Objective
Make the macOS 27 golden-base build genuinely unattended: no unrecognized GUI permission sheets, no blind keystrokes into whichever dialog happens to have focus, and no base marked ready until a production-shaped clone can boot, mount its workspace, and execute through the in-guest agent.
The existing lightweight MDM is the policy plane for permissions macOS allows device management to grant. Host-side display capture and virtual HID remain the default computer-use path, so guest Screen Recording and Accessibility are not prerequisites for an ordinary usable base.
Findings
1. MDM is implemented but disconnected
MacVMEngine+MDM.swift contains Mode A enrollment and Mode B profile-push helpers, while
NucleicMDM contains a CA, enrollment profile, HTTPS server, command queue, and tests. The
production base build never calls those helpers. It runs the shell provisioner and then answers the
Network Volumes dialog with a separate OCR/click pass.
The MacVMBaseStatus.mdmEnrolled and profilesInstalled fields therefore describe planned state,
not a readiness invariant. Recipe v7 can be stamped while both remain false.
2. Provisioning creates policy prompts before policy exists
The bootstrap enters through Apple's VirtioFS automount, then remounts the same directory at a custom path and executes the full provisioner there. The custom mount is treated as a network volume, so the build touches a protected resource before any Network Volumes policy is installed.
The later consent pass repairs only NucleicVMAgent access. It is exact-English OCR for Allow,
cannot establish which dialog owns that button, and is fragile when more than one sheet is visible.
3. GUI fallback handling is not a state machine
When Command Line Tools are absent from the Software Update catalog, the guest launches
xcode-select --install and writes a sentinel. While the sentinel exists, the host sends Return
every three seconds. Return may accept the CLT sheet, an unrelated privacy sheet, or any other
focused control. Provisioning must recognize the expected UI state or stop; it must never treat all
dialogs as equivalent.
4. The MDM integration is still spike-grade
- UAMDM approval opens Device Management and sends one Return; Install, authentication, and verification are placeholders.
- The built-in FDA and notification profiles are not copied into the shipped app.
- The CA, MDM configuration, device identity, and installed profile identifiers are not persisted per base.
- Enrollment orchestration uses registry-based
run(name:), but maintenance boots hold a directMacVMInstance. - A drained command queue may contain errored commands, and enrollment returning false is not currently fatal.
- CA trust, guest-to-host TLS reachability, initial no-APNs command drain, real
mdmclientsignatures, and headless UAMDM approval still need a live macOS 27 validation pass.
5. macOS 27 narrows the policy scope
Classic MDM profiles remain appropriate for Full Disk Access, Network Volumes, and targeted
notification settings. Classic PPPC Accessibility grants are removed in macOS 27 in favor of the
declarative com.apple.configuration.app-settings privacy model. Screen Recording cannot be
silently granted.
This does not block the base: pixel computer use is host-side and needs no guest TCC. Semantic AX remains optional until the lightweight MDM supports Declarative Device Management.
Implementation plan
P0 — deterministic bootstrap
- Package the built-in MDM policy profiles in
Resources/macvm. - Add Network Volumes to the VM-agent PPPC policy.
- Resolve packaged policy assets through one tested engine helper.
- Stop blindly confirming the graphical CLT installer.
- Keep the unattended path headless; if CLT cannot be installed headlessly, fail with an actionable diagnostic rather than wait behind an unknown sheet.
- Do not execute the full provisioner from a custom network-volume mount before policy exists.
- Record screenshots, recognized text, frontmost UI state, and TCC attribution when an unexpected modal blocks progress.
P1 — production Mode A enrollment
- Split the base build into:
- declarative account creation and minimal exec-agent install through the automount;
- MDM enrollment and required policy installation;
- full toolchain provisioning after policy is active.
- Refactor enrollment to operate on a direct
MacVMInstance. - Persist the MDM CA, configuration, device identity, and profile identifiers beside the base metadata with credential-appropriate permissions.
- Replace the UAMDM placeholder with a bounded, state-aware Device Management flow that enters the generated guest password only in the expected authentication sheet.
- Treat enrollment false, command errors, missing profile identifiers, or failed functional probes as fatal.
- Make re-provisioning update policy without attempting a second enrollment.
- Require
mdmEnrolled, required profiles, agent readiness, and a production-shaped workspace mount before stamping the provisioning recipe. - Remove
MacVMEngine+ConsentGrant.swift's Network Volumes click path once the MDM path is proven.
P2 — live macOS 27 validation
- Validate local-CA trust without a SecurityAgent prompt.
- Validate guest-to-host gateway/TLS reachability and check whether the listener introduces host Local Network or incoming-connection prompts.
- Validate enrollment's initial command drain without an MDM APNs push certificate.
- Capture real
mdmclientrequest signatures, then enable strict signature verification. - Verify reboot, clone, reprovision, and app-update behavior.
- Test a non-English guest and reject any automation dependent on English-only button matching.
P3 — optional semantic AX policy
- Implement Declarative Device Management enablement and declaration endpoints.
- Deliver macOS 27 app-settings privacy defaults for Accessibility/PostEvent only when semantic AX is enabled.
- Keep Screen Recording and semantic AX out of ordinary base readiness.
Release gate
A base is releasable only when a clean macOS 27 build proves:
- no unrecognized GUI sheets from restore through shutdown;
- required MDM enrollment and exact profile identifiers survive reboot;
- the first production-shaped workspace mount succeeds without a prompt;
- VM-agent FDA works without a Data Access Blocked notification;
- Tips/BTM noise is suppressed without disabling arbitrary app notifications;
- re-provisioning performs no duplicate enrollment;
- a fresh clone boots, mounts, executes, and shuts down unattended.
Implementation checkpoint — persisted Mode A state
mdm-state.jsonnow retains a versioned CA, configuration, device certificate/private key, PKCS#12 password, and the profile identifiers verified in the guest. It is mode0600, remains in the golden-base directory, and is deliberately excluded by the explicit clone copier.- Mode A accepts a direct maintenance
MacVMInstanceand uses the existing bounded vsock/nash exec channel instead of requiring the base to appear in the ordinary session registry. - A drained MDM queue is no longer sufficient: every UUID from the current policy batch must report
Acknowledged, enrollment must report User Approved, and the guest's XML profile inventory must contain the exact top-level identifiers before they are persisted. - The production provisioning call site remains intentionally disabled until the macOS 27 UAMDM UI flow and guest-to-host listener binding are validated; enabling the current placeholder would replace one unattended prompt failure with another.
Verification notes
- The two existing policy files parse as configuration-profile plists.
scripts/provision-macos-guest.shandscripts/build-macos-base.shpassbash -n.- The MDM protocol unit tests cover generated artifacts and a synthetic TLS command drain, but do not
exercise a real macOS guest or
mdmclient.