Skip to content

feat(macos): qualify the Tahoe Lume seed and its Mac Studio host - #29

Merged
jmgilman merged 2 commits into
masterfrom
feat/phase8-macos-seed
Sep 16, 2026
Merged

jmgilman merged 2 commits into
masterfrom
feat/phase8-macos-seed

Conversation

@jmgilman

@jmgilman jmgilman commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Summary

The macOS backend's image side, built and gated on real hardware.
images/macos/:

  • pins.lock.yaml — Lume 0.5.3, Cua Driver 0.28.1 (darwin-arm64), and both the
    Tahoe and Sequoia IPSWs. Every digest was measured on the host and matched.
  • provision.sh, verify.sh, lib.sh — shared by every train; per-train
    directories hold only image.yaml and unattended.yaml.
  • tahoe/desktop/ — the qualified train. sequoia/desktop/ stays recorded.
  • README.md — operator runbook, measurements, findings.
  • images-validate.yml parses the scripts and asserts every pin they read.

Host: studio-1 (Mac Studio M2 Max, macOS 26.6.2), the owner's amendment to
design prerequisite 5 — an always-on workstation rather than a dedicated Mac
mini, with the backend confined to a dedicated agentcompute account.
Migration to a mini is moving that account's ~/.lume and re-issuing one key.

Evidence

Four clone cycles: clone 2–3 s, boot to NAT address 10–11 s, Driver
answering with both TCC grants ~30 s, verify.sh 6–7 s, ~26.5 GB
allocated per clone. No clone ever asked for consent again — that is the
Lume decision criterion, and it is met. lume create 287 s, IPSW fetch 212 s.

The seed passes all ten gate checks, including a desktop capture pulled over
scp from the host.

What the spike changed, all measured

  • Driver LaunchAgent execs the bundle binary under launchd
    (com.trycua.cua_driver_daemon). Upstream's open -g -a CuaDriver --args serve makes open the responsible process and the Driver then refuses to
    read its own TCC state.
  • AccountInfo:FirstLogins in loginwindow's preferences is what suppresses
    macOS's first-login Setup Assistant. Lume's offline setup does not complete
    it, and the documented com.apple.SetupAssistant keys do nothing on 26.6.2.
  • lume ssh is not argv-safe: it joins argv with spaces and the guest
    re-parses it, so lume ssh vm /bin/bash -c '<script>' arrives mangled.
    lib.sh composes one shell line and carries the payload as base64.
  • 1920x1200, not 1440x900: at the smaller size macOS clips Setup
    Assistant's buttons off-screen.
  • In-guest Screen Sharing dropped: launchctl enable system/com.apple.screensharing fails on macOS 26, and Lume already serves a
    per-VM VNC console.
  • Sequoia is not the train: its last full restore image is 15.6.1 (2025-08-20).

Findings for the backend

  1. A clone re-runs Setup Assistant even though the seed completed it and
    keeps it suppressed across its own reboots; killing it logs the session out.
    The Driver is unaffected, so verify.sh --clone skips only the
    desktop-session check — but an agent handed a clone sees the wizard. Open
    defect, documented, not hidden.
  2. Lume's API accepts a third macOS guest and silently ignores it:
    POST /lume/vms/<n>/run returns 202 {"status":"pending"}, the VM stays
    stopped, and only lume serve's log says The number of virtual machines exceeds the limit. The backend must count running guests itself.
  3. lume run --detach fails without a controlling terminal (nohup: can't detach from console); start VMs through the HTTP API.
  4. Lume's per-VM VNC server listens on every interface while the API is
    loopback-only.
  5. cua-driver status | head panics the CLI on a broken pipe.

Host hardening (owner's conditions)

  • lume serve runs as agentcompute and binds 127.0.0.1:7777 only —
    verified with lsof and by failed connects from the LAN and tailnet
    addresses.
  • The server key is forwarding-only: forced command, AllowTcpForwarding local, PermitOpen 127.0.0.1:7777, duplicated root-owned in
    /etc/ssh/sshd_config.d/110-agentcompute.conf. Proven: command execution
    refused, :7777 forward serves the API, :22 and :5900 forwards rejected
    administratively prohibited, remote forwarding rejected outright.
    Correction to the spec: restrict alone does not block command
    execution — without the forced command ssh host whoami succeeded.
  • Tailnet ACL is a separate PR, feat(tailscale): reserve the Mac backend's SSH port for the agentcompute server networking#21, deliberately unmerged
    until the host is tagged.

Still not in this PR: internal/lume, and no catalog.yaml row — the server
answers platform "mac" is not available yet, so a row would advertise an
image nothing can launch.

Phase 8 inputs for the macOS backend, reviewed but never executed: design
prerequisite 5 (a dedicated Apple Silicon host in the lab, reachable over
SSH) is not satisfied, so no VM, TCC, or clone experiment has run and none
may run on a personal workstation.

What is verified here: every pin resolves out of pins.lock.yaml and the
recipe, the scripts parse, the pin reader fails closed on a renamed key, and
the Driver archive digest, bundle id (com.trycua.driver), and signing team
(YCK386LBJ7) were measured from the pinned release. The Sequoia IPSW digest
is republished by AppleDB, not by Apple, so its pin gate stays open until it
is measured on the Mac host.

Two findings the host will have to settle: 15.6.1 (24G90) is the last Sequoia
release Apple published as a full restore image, so a Sequoia seed sits about
a year behind that train's security level, and upstream now calls `tahoe` the
verified unattended preset while still warning that `sequoia` can stop on
Setup Assistant. Changing trains is the design owner's call.

No catalog row is added: the server still answers `platform "mac" is not
available yet`, and a catalog entry would advertise an image no
instance.create can launch.
Built and gated the seed end to end on studio-1 (Mac Studio M2 Max, macOS
26.6.2) under a dedicated `agentcompute` account, per the owner's amendment
to design prerequisite 5. Every value in pins.lock.yaml is now measured
locally, not just publisher-verified.

Tahoe is the qualified train. Sequoia stays recorded: its last full restore
image is 15.6.1 (2025-08-20), a year behind that train's security level, and
it clears no gate Tahoe does not.

What the spike changed in the recipe, all measured rather than assumed:

- The Driver LaunchAgent execs the bundle binary under launchd
  (com.trycua.cua_driver_daemon). Upstream's `open -g -a CuaDriver --args
  serve` makes `open` the responsible process and the Driver then refuses to
  read its own TCC state.
- provision.sh raises AccountInfo:FirstLogins in loginwindow's preferences.
  Lume's offline setup does not complete Setup Assistant, and the documented
  com.apple.SetupAssistant keys do not suppress it on 26.6.2.
- lib.sh composes one shell line per guest command: `lume ssh` joins argv with
  spaces and the guest re-parses it, so a quoted script arrives mangled.
- The display is 1920x1200; at 1440x900 macOS clips Setup Assistant's buttons
  off-screen, which makes the console pass impossible.
- In-guest Screen Sharing is dropped. `launchctl enable
  system/com.apple.screensharing` fails on macOS 26 and Lume already serves a
  per-VM VNC console.
- verify.sh gained a desktop-session check, `--clone`, and a BSD-correct
  mktemp template.

Clone evidence over four cycles: clone 2-3 s, boot to NAT address 10-11 s,
Driver answering with both TCC grants about 30 s, no clone ever asking for
consent again. Two findings for the backend are in images/macos/README.md:
a clone re-runs Setup Assistant, and Lume's API accepts a third macOS guest
with 202 while silently leaving it stopped.
@jmgilman jmgilman changed the title feat(macos): add the Lume seed recipe, pins, and operator runbook feat(macos): qualify the Tahoe Lume seed and its Mac Studio host Sep 15, 2026
@jmgilman
jmgilman marked this pull request as ready for review September 15, 2026 08:08
@jmgilman
jmgilman merged commit 01e0e06 into master Sep 16, 2026
7 checks passed
@jmgilman
jmgilman deleted the feat/phase8-macos-seed branch September 16, 2026 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant