feat(install): macOS launchd installer + Install/Uninstall routing (VA-89) #138

Merged
longjacksonle merged 1 commit from feat/VA-89-macos-launchd-installer into main 2026-07-14 18:57:42 +02:00

What

Part of VA-89. The agent had no macOS install path - install.rs is systemd-only and main.rs routed Install/Uninstall for Linux and Windows only. This adds the launchd analog.

New install_macos module (mirrors the systemd installer)

  • System mode (root): LaunchDaemon at /Library/LaunchDaemons/run.a8n.vervain-agent.plist, binary at /usr/local/sbin/vervain-agent, databases under /Library/Application Support/vervain-agent/{config,data}.
  • User mode (no root): LaunchAgent under ~/Library/LaunchAgents/, binary at ~/.local/bin/, databases under ~/Library/Application Support/vervain-agent/.

Both consume the one-time bootstrap.json, write the four enrollment PEMs into the data dir (mode 600), generate a fresh VERVAIN_DB_KEY, and render a plist whose EnvironmentVariables dict carries the DB key + VERVAIN_SERVER_DOMAIN + VERVAIN_*_FILE pointers (plist mode 600). RunAtLoad + KeepAlive{SuccessfulExit:false} matches systemd Restart=on-failure. Uninstall reverses each step; uninstall_full/uninstall_full_self wipe identity + state for the VA-87 remote-uninstall path (wired into dispatch's perform_full_uninstall).

main.rs gains macOS Install/Uninstall subcommands (shared InstallType system/user) and a macOS routing block; read_bundle, InstallType, and the ValueEnum import extend to macOS.

Testing

Plist rendering + layout are pure and unit-tested (required keys, XML escaping, home-relative user paths, LaunchDaemon path). The module is compiled under test via cfg(any(target_os = "macos", test)), so those 5 tests run on the Linux CI, and the whole module (bar the geteuid line) compile-checks on Linux. 406 lib tests pass; clippy --all-targets + fmt clean.

The launchctl load/unload calls, the macOS-only main.rs routing block, and the real install/uninstall need a Mac to verify (VA-90 runner or manual). Apple codesign/notarization is a separate follow-up (VA-128); macOS KVM is VA-7.

Scope: x86_64-apple-darwin (AgentId::MacOsx64=16) only; no protocol change.

## What Part of VA-89. The agent had no macOS install path - `install.rs` is systemd-only and `main.rs` routed `Install`/`Uninstall` for Linux and Windows only. This adds the launchd analog. ## New `install_macos` module (mirrors the systemd installer) - **System mode** (root): LaunchDaemon at `/Library/LaunchDaemons/run.a8n.vervain-agent.plist`, binary at `/usr/local/sbin/vervain-agent`, databases under `/Library/Application Support/vervain-agent/{config,data}`. - **User mode** (no root): LaunchAgent under `~/Library/LaunchAgents/`, binary at `~/.local/bin/`, databases under `~/Library/Application Support/vervain-agent/`. Both consume the one-time `bootstrap.json`, write the four enrollment PEMs into the data dir (mode 600), generate a fresh `VERVAIN_DB_KEY`, and render a plist whose `EnvironmentVariables` dict carries the DB key + `VERVAIN_SERVER_DOMAIN` + `VERVAIN_*_FILE` pointers (plist mode 600). `RunAtLoad` + `KeepAlive{SuccessfulExit:false}` matches systemd `Restart=on-failure`. Uninstall reverses each step; `uninstall_full`/`uninstall_full_self` wipe identity + state for the VA-87 remote-uninstall path (wired into dispatch's `perform_full_uninstall`). `main.rs` gains macOS `Install`/`Uninstall` subcommands (shared `InstallType` system/user) and a macOS routing block; `read_bundle`, `InstallType`, and the `ValueEnum` import extend to macOS. ## Testing Plist rendering + layout are pure and unit-tested (required keys, XML escaping, home-relative user paths, LaunchDaemon path). The module is compiled under `test` via `cfg(any(target_os = "macos", test))`, so those 5 tests run on the **Linux CI**, and the whole module (bar the `geteuid` line) compile-checks on Linux. 406 lib tests pass; clippy `--all-targets` + fmt clean. The `launchctl load`/`unload` calls, the macOS-only `main.rs` routing block, and the real install/uninstall need a Mac to verify (VA-90 runner or manual). Apple codesign/notarization is a separate follow-up (VA-128); macOS KVM is VA-7. Scope: x86_64-apple-darwin (`AgentId::MacOsx64=16`) only; no protocol change.
feat(install): macOS launchd installer + Install/Uninstall routing (VA-89)
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 4m57s
Create release / Create release from merged PR (pull_request) Has been skipped
42632bf1cf
The agent had no macOS install path: install.rs was systemd-only and main.rs routed Install/Uninstall for Linux (systemd) and Windows (SCM) only. Add the launchd analog so a Mac agent can be installed as a managed service.

New install_macos module mirrors the systemd installer: a system mode (root LaunchDaemon at /Library/LaunchDaemons/run.a8n.vervain-agent.plist, binary at /usr/local/sbin, databases under /Library/Application Support/vervain-agent) and a per-user mode (LaunchAgent under ~/Library/LaunchAgents, binary at ~/.local/bin, databases under ~/Library/Application Support). Both take the one-time bootstrap.json, write the four enrollment PEMs into the data dir (mode 600), generate a fresh VERVAIN_DB_KEY, and render a plist whose EnvironmentVariables dict carries the DB key + VERVAIN_SERVER_DOMAIN + VERVAIN_*_FILE pointers (plist mode 600). RunAtLoad + KeepAlive{SuccessfulExit:false} matches systemd Restart=on-failure. Uninstall reverses each step; uninstall_full/uninstall_full_self wipe identity + state for the VA-87 remote-uninstall path (wired into dispatch's perform_full_uninstall).

main.rs gains macOS Install/Uninstall subcommands (shared InstallType system/user) and a macOS routing block; read_bundle, InstallType, and the ValueEnum import extend to macOS.

The plist rendering + layout logic is pure and unit-tested; the module is compiled under `test` (via cfg(any(target_os = "macos", test))) so those tests run on the Linux CI, not only the mac runner. The launchctl load/unload calls and the actual install need a Mac to verify (VA-90 runner / manual). Apple codesign/notarization stays a separate follow-up (VA-128); macOS KVM is VA-7.

Part of VA-89. Only x86_64-apple-darwin (AgentId::MacOsx64=16) is targeted; no protocol change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFsMi3Vmf3pCc7mBdhZqoV
longjacksonle deleted branch feat/VA-89-macos-launchd-installer 2026-07-14 18:57:42 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-agent!138
No description provided.