Replace the Tart-based prototype with a runner-oriented macOS VM executor backed by runner-executor-macos and Apple Virtualization. Assisted-by: Codet:MODEL_VERSION
2.7 KiB
macOS VM executor
The runner can execute a job in an ephemeral macOS VM by registering a
macos-vm label:
runner:
labels:
- macos-latest:macos-vm://registry.example.com/macos-15.2-xcode-26.1
The VM is created and managed by runner-executor-macos, a dedicated Swift
binary built on Apple Virtualization.framework. The source VM must include the
runner guest agent.
Configuration
macos_vm:
executor_path: runner-executor-macos
workdir_parent: /Users/admin/runner
cpu: 0
memory: 0
boot_timeout: 5m
workdir_parent is the guest directory under which job workspaces are created.
executor_path is the binary to invoke; an empty value uses PATH lookup.
Executor CLI
The runner uses a narrow, runner-oriented command set:
runner-executor-macos provision <image> <name> [--cpu N] [--memory MB]
runner-executor-macos start <name> [--no-graphics]
runner-executor-macos exec <name> [--stdin] <argv...>
runner-executor-macos stop <name> [--timeout N]
runner-executor-macos destroy <name>
runner-executor-macos list --format json
runner-executor-macos version
list --format json returns:
[
{
"name": "GITEA-MACOS-VM-<runner-uuid>-...",
"state": "stopped",
"running": false,
"accessed_at": "2026-09-05T12:00:00Z"
}
]
Integration test
The end-to-end test is opt-in because it provisions and boots a real VM:
MACOS_VM_TEST_IMAGE=/path/or/reference \
go test -tags macos_vm_integration ./act/container -run '^TestMacOSVMEnvironmentIntegration$' -v
The test skips when MACOS_VM_TEST_IMAGE is unset.
Orphaned VM cleanup
Job VM names start with GITEA-MACOS-VM-<runner-uuid>-. While the runner is
idle, it lists local VMs and destroys the non-running ones whose name has this
runner's UUID and whose access time is older than
runner.workdir_cleanup_age.
Service containers
Service containers are intentionally rejected for macOS VM jobs today. Docker service containers live on a Docker network and are reached by workflow service id, which a macOS VM cannot resolve.
Possible future designs:
- Host-published Docker services + guest host mapping — publish each
service port on the runner host and inject
<service-id> -> <host-ip>into the VM through the guest agent. - macOS VM services — run each service as another VM; this requires service discovery and is much heavier than Docker containers.
- Environment-based discovery — require workflows to read service addresses from env vars instead of hostnames, breaking GitHub Actions compatibility.
Option 1 is the most compatible direction once the guest agent and host network configuration are stable.