Skip to content

feat(#430): macOS lifecycle — login autostart, no-admin IT remedy, first-launch prompt - #526

Merged
shujaatTracebloc merged 8 commits into
developfrom
fix/430-macos-lifecycle
Aug 3, 2026
Merged

feat(#430): macOS lifecycle — login autostart, no-admin IT remedy, first-launch prompt#526
shujaatTracebloc merged 8 commits into
developfrom
fix/430-macos-lifecycle

Conversation

@shujaatTracebloc

@shujaatTraceblocshujaatTracebloc commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

#430 — macOS lifecycle: autostart, first-launch prompt, no-admin path

macOS had the weakest lifecycle story of the three OSes:

  • No autostart at all — a rebooted headless Mac stayed down until someone re-ran the installer manually; the k3d --restart unless-stopped policy is useless until the runtime itself starts.
  • Up-front admin gate failed managed/standard accounts with a generic sudo authentication failed, not a path forward.
  • Docker Desktop's privileged-helper dialog (admin auth) was never mentioned.

Fix

1. Login autostart — _install_macos_autostart
Writes a per-user LaunchAgent (~/Library/LaunchAgents/io.tracebloc.runtime.plist, no admin needed) with RunAtLoad that starts the runtime at each login:

  • GUI Mac → open -a Docker
  • headless Mac → colima start

Combined with the k3d --restart unless-stopped policy, a rebooted Mac (GUI or headless) returns with zero human action. Best-effort (never fails the install); sets TB_MACOS_AUTOSTART=1.

2. No-admin named remedy — _macos_require_admin
Fails fast on a no-admin Mac with a named, IT-facing remedy (the macOS analog of Linux prepare-host) — install Docker Desktop + grant access, grant admin rights, or have IT run the installer once — instead of preflight_sudo's generic error after a wasted password prompt. Admins/root pass straight through.

3. First-launch prompt
Names the privileged-helper dialog ("macOS asks for your admin password once") alongside the license note, so the auth prompt isn't a surprise.

4. Summary
_reboot_note now says "After a reboot, tracebloc restarts automatically (login item configured)" when autostart is set; the no-autostart output is byte-identical (golden-safe).

Acceptance criteria

  • ✅ Rebooted Mac (GUI and headless) brings tracebloc back with zero human action (LaunchAgent + restart policy), and the summary states it.
  • ✅ No-admin runs end in a specific IT-facing instruction.

Tests / gates

  • New scripts/tests/setup-macos-lifecycle.bats (9): admin detection, no-admin remedy, LaunchAgent GUI/headless/best-effort-failure, reboot-note both ways.
  • Separate test file from setup-macos.bats / setup-macos-arch.bats to avoid a file-add clash across parallel PRs.
  • shellcheck --severity=error, check-style, check-drift clean; summary.bats + copy-catalog golden green (default output unchanged); manifest.sha256 regenerated (R8).

Note: bash-3.2-safe (never-empty arg arrays; no namerefs).

Closes#430


Note

Medium Risk
Writes LaunchAgents/Daemons and uses sudo for headless boot autostart; failures are best-effort but misconfiguration could affect post-reboot runtime on shared or headless Macs.

Overview
Improves the macOS installer so reboots and non-admin accounts are handled explicitly instead of leaving users to manually restart Docker or hit a vague sudo failure.

Autostart adds _install_macos_autostart (best-effort, || true under set -e): a GUI Mac gets a per-user LaunchAgent that runs open -a Docker at login; headless installs a system LaunchDaemon that runs colima as the install user with retry/colima stop --force, but only when colima is actually present. Honors TRACEBLOC_NO_AUTOSTART; sets TB_MACOS_AUTOSTART=1 only on success.

Admin gate runs _macos_require_admin before preflight_sudo so standard/managed accounts fail fast with IT-facing steps (grant admin or install from an admin account), not a generic sudo error.

UX: first-time Docker Desktop setup now mentions the privileged-helper password prompt. _reboot_note promises automatic restart when TB_MACOS_AUTOSTART=1; otherwise the “open Docker Desktop” line is unchanged.

Adds setup-macos-lifecycle.bats and updates manifest.sha256.

Reviewed by Cursor Bugbot for commit 6e37fc2. Bugbot is set up for automated code reviews on this repo. Configure here.

…-launch prompt
macOS had the weakest lifecycle of the three OSes: no autostart at all (a rebooted
headless Mac stayed down until someone re-ran manually), the up-front admin gate failed
managed/no-admin users with a generic sudo error, and Docker Desktop's privileged-helper
dialog was never mentioned.
- _install_macos_autostart: writes a per-user LaunchAgent (no admin needed) that starts
the runtime at each login — `open -a Docker` on a GUI Mac, `colima start` on a headless
one — with RunAtLoad. Combined with the k3d --restart unless-stopped policy, a rebooted
Mac (GUI or headless) returns with ZERO human action. Best-effort; sets
TB_MACOS_AUTOSTART=1 so the summary can honestly promise it.
- _macos_require_admin (+ _macos_user_is_admin): fail FAST on a no-admin Mac with a named,
IT-facing remedy (the macOS analog of Linux prepare-host) instead of preflight_sudo's
generic "sudo authentication failed" after a wasted prompt. Admins/root pass through.
- First-launch: name the privileged-helper prompt ("macOS asks for your admin password
once") alongside the license note, so the auth dialog isn't a surprise.
- summary _reboot_note: macOS now says "restarts automatically (login item configured)"
when autostart is set; the no-autostart output is byte-identical (golden-safe).
Tests: new scripts/tests/setup-macos-lifecycle.bats (admin detection, no-admin remedy,
LaunchAgent GUI/headless/best-effort-failure, reboot-note both ways). Separate file from
setup-macos.bats / setup-macos-arch.bats to avoid a file-add clash across parallel PRs.
shellcheck/style/drift clean; summary + copy-catalog golden green; manifest regenerated.
Closes#430
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shujaatTraceblocshujaatTracebloc self-assigned this Jul 31, 2026
@shujaatTracebloc
shujaatTracebloc marked this pull request as ready for review July 31, 2026 15:02
…cycle
# Conflicts:
#	scripts/lib/setup-macos.sh
#	scripts/manifest.sha256
Comment threadscripts/lib/setup-macos.sh Outdated
Comment threadscripts/lib/setup-macos.sh Outdated
…gbot)
Two Bugbot findings:
1. (Medium) _install_macos_autostart returns 1 on a mkdir/write failure and install_macos
called it BARE under set -e — aborting the whole install after Docker + tools were
already in, contradicting the best-effort contract. Call it with `|| true`.
New test drives install_macos with a failing autostart and asserts it still exits 0.
2. (High) The no-admin remedy was inaccurate: re-running as the same non-admin account
just hits _macos_require_admin again, and there is NO macOS prepare-host (run_prepare_host
errors on Darwin). Rewrote it to name the remedies that actually unblock the install —
grant THIS account admin rights (then re-run as yourself), or install from an account
that already has admin. Dropped the misleading "install Docker + re-run" loop and the
nonexistent prepare-host reference. Test updated accordingly.
shellcheck/style clean; 10/10 setup-macos-lifecycle.bats; manifest regenerated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment threadscripts/lib/setup-macos.sh Outdated
Comment threadscripts/lib/setup-macos.sh
…UTOSTART (Bugbot)
Two more Bugbot findings:
1. (High) A per-user LaunchAgent only loads inside a GUI/Aqua login session — which a
HEADLESS Mac never has — so the headless branch wrote an agent that never runs at
boot, making the "restarts automatically" promise false. Headless now installs a
system LaunchDaemon (/Library/LaunchDaemons, root) that runs `colima start` at BOOT
as the install user, with HOME + PATH set (a boot daemon has no user env). GUI keeps
the LaunchAgent. Factored the shared plist skeleton into _emit_launch_plist.
2. (Medium) _install_macos_autostart ignored TRACEBLOC_NO_AUTOSTART, the opt-out that
already gates ensure_cluster_autostart (Linux) and the Windows peer. It now short-
circuits on that flag, so macOS no longer configures autostart or promises auto-
restart when the operator opted out.
Tests: headless test now asserts a LaunchDaemon (UserName + EnvironmentVariables +
sudo launchctl, boot not login); new opt-out test; GUI + best-effort tests unchanged.
11/11 setup-macos-lifecycle.bats; shellcheck/style/drift clean; manifest regenerated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment threadscripts/lib/setup-macos.sh Outdated
Comment threadscripts/lib/summary.sh Outdated
Two more Bugbot findings on the LaunchDaemon change:
1. (Medium) Both plists logged to a fixed /tmp/tracebloc-autostart.log. With the
installer's umask 077 the first account creates it 0600, so a second account's job
can't open it (EX_CONFIG → runtime never starts), and /tmp is symlink-plantable on a
shared Mac. _emit_launch_plist now takes a per-user log path: the LaunchAgent logs to
$HOME/Library/Logs and the LaunchDaemon to the install user's ~/Library/Logs.
2. (Low) _reboot_note said "login item configured" for every macOS autostart, but a
headless install uses a system LaunchDaemon (/Library/LaunchDaemons), not a login item
— so IT would look in the wrong place. Dropped the mechanism label: "After a reboot,
tracebloc restarts automatically." (accurate for both agent and daemon).
Tests: assert the plist log path is per-user (Library/Logs), not /tmp; summary +
copy-catalog golden green (no-autostart line unchanged). shellcheck clean; manifest regen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment threadscripts/lib/setup-macos.sh
Comment threadscripts/lib/setup-macos.sh
… (Bugbot)
Two more Bugbot findings on the headless LaunchDaemon:
1. (High) The daemon's StandardOutPath is ~/Library/Logs/... but that dir was never
created (the GUI path mkdir's its own). On a fresh headless account without
~/Library/Logs, launchd fails EX_CONFIG before colima runs, yet TB_MACOS_AUTOSTART=1
still promised recovery. Now mkdir -p "${_home}/Library/Logs" before writing the plist.
2. (High) The daemon ran a bare oneshot `colima start` at boot with no retry — the
VZ+Rosetta stack commonly leaves stale VM state across a reboot, so the first start
fails and the edge never comes back. Replaced with a resilient wrapper:
/bin/bash -c 'until colima start; retry up to 3x, colima stop + sleep 15 between
attempts' — force-stopping clears the stale state. Loop body has no </>/& so it stays
valid inside the plist <string>.
Tests: headless test now asserts the log dir is created, the /bin/bash resilient wrapper,
and colima stop (retry). 11/11 setup-macos-lifecycle.bats; shellcheck/style clean; manifest regen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment threadscripts/lib/setup-macos.sh Outdated
…e (Bugbot)
The headless LaunchDaemon retry ran a bare `colima stop` between failed starts, but the
intent is a FORCE stop: without --force, orphaned VZ driver state isn't cleared (and a
bare stop can hang), so all three attempts fail and a rebooted headless Mac stays down
despite TB_MACOS_AUTOSTART=1. Use `colima stop --force`. Test asserts the flag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 58203d0. Configure here.

Comment threadscripts/lib/setup-macos.sh
…ve its real path (Bugbot)
Headless autostart always wrote a colima LaunchDaemon and set TB_MACOS_AUTOSTART=1, but
install_docker_desktop installs colima only when Docker was DOWN — if Docker was already
up by other means colima may be absent, so the daemon was bogus and the auto-restart
promise false. The `|| echo /usr/local/bin/colima` fallback also baked a path that's wrong
on Apple Silicon (Homebrew there is /opt/homebrew/bin).
Now resolve colima via `command -v` (its REAL path on either chip) and, if it isn't
installed, skip autostart honestly (best-effort return 1; caller's `|| true`) so the
summary won't promise recovery via a runtime that isn't there. New test: headless +
colima absent -> skip, no daemon, flag unset.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shujaatTracebloc
shujaatTracebloc merged commit 07c788e into developAug 3, 2026
61 of 62 checks passed
@shujaatTracebloc
shujaatTracebloc deleted the fix/430-macos-lifecycle branch August 3, 2026 06:55
@LukasWodka

Copy link
Copy Markdown
Contributor

/fr-pass

Sign up for freeto 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.

3 participants

@shujaatTracebloc@LukasWodka@saadqbal