Nucleic: The MacOS VM Base Image Provisioning
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# 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 direct
|
||||
`MacVMInstance`.
|
||||
- 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 `mdmclient`
|
||||
signatures, 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
|
||||
|
||||
- [x] Package the built-in MDM policy profiles in `Resources/macvm`.
|
||||
- [x] Add Network Volumes to the VM-agent PPPC policy.
|
||||
- [x] Resolve packaged policy assets through one tested engine helper.
|
||||
- [x] Stop blindly confirming the graphical CLT installer.
|
||||
- [x] Keep the unattended path headless; if CLT cannot be installed headlessly, fail with an
|
||||
actionable diagnostic rather than wait behind an unknown sheet.
|
||||
- [x] 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:
|
||||
1. declarative account creation and minimal exec-agent install through the automount;
|
||||
2. MDM enrollment and required policy installation;
|
||||
3. 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 `mdmclient` request 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.
|
||||
|
||||
## Verification notes
|
||||
|
||||
- The two existing policy files parse as configuration-profile plists.
|
||||
- `scripts/provision-macos-guest.sh` and `scripts/build-macos-base.sh` pass `bash -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`.
|
||||
Reference in New Issue
Block a user