Nucleic: Gitea Runner macOS VM Support
This commit is contained in:
+61
-12
@@ -24,6 +24,7 @@ gitea-macos-runner service status
|
||||
| VM won't start; entitlement / `com.apple.security.virtualization` error | Running an unsigned binary, or one outside the signed `.app` bundle | `make sign` (or re-run `make install`); invoke the installed bundle, never `.build/release/…` |
|
||||
| `virtualMachineLimitExceeded` at boot | macOS allows at most **2** concurrent macOS VMs | Set `scheduler.maxConcurrentVMs` ≤ 2; kill stray VMs from earlier runs |
|
||||
| VM boots but never gets an IP | DHCP lease not yet written, or Local Network privacy denial (macOS 15+) | Check `/var/db/dhcpd_leases`; grant Local Network permission or pre-authorize the subnet |
|
||||
| Runner not listed under Privacy & Security → Local Network | Expected — the list is populated only after the app first attempts a local connection; it cannot be pre-approved | Boot one VM by hand from a GUI Terminal to create the entry, or (better on CI) allowlist the subnet with `defaults write com.apple.network.local-network` |
|
||||
| SSH times out on a freshly built image | Guest macOS < 27, so provisioning options were ignored and Setup Assistant is waiting | Rebuild the image from a macOS **27+** IPSW |
|
||||
| `SecKeyCreateRandomKey` / "Interaction is not allowed" | `login.keychain` is locked — no GUI session | Run as a LaunchAgent in an unlocked GUI session; enable auto-login |
|
||||
| Job stays queued forever | Label mismatch, or the daemon isn't running/reaching Gitea | Use bare label names in `runs-on`; match `runner.labels`; check daemon logs |
|
||||
@@ -96,23 +97,71 @@ prompt**: a LaunchAgent that was never granted permission (or was denied) cannot
|
||||
An entry with a recent `lease` timestamp and the guest's MAC means networking is fine and the
|
||||
problem is timing — raise `scheduler.bootTimeoutSeconds`.
|
||||
|
||||
2. No entry at all: check **System Settings → Privacy & Security → Local Network** and enable the
|
||||
runner. If it isn't listed, trigger the prompt interactively from a Terminal in the GUI session:
|
||||
|
||||
```sh
|
||||
gitea-macos-runner vm boot
|
||||
```
|
||||
|
||||
and click **Allow**.
|
||||
|
||||
3. Or pre-authorize the VM subnet, then reboot:
|
||||
2. No entry at all: pre-authorize the VM subnet, then **reboot** (these are read at boot):
|
||||
|
||||
```sh
|
||||
sudo defaults write com.apple.network.local-network \
|
||||
AllowedEthernetLocalNetworkAddresses -array "192.168.0.0/16"
|
||||
AllowedEthernetLocalNetworkAddresses -array "192.168.64.0/24"
|
||||
sudo defaults write com.apple.network.local-network \
|
||||
AllowedWiFiLocalNetworkAddresses -array "192.168.64.0/24"
|
||||
```
|
||||
|
||||
Match the range to what your host's NAT actually hands out.
|
||||
Match the range to what your host's NAT actually hands out. `doctor` reports `local network
|
||||
access` as a pass once it can see this. This is the deterministic fix for an unattended host —
|
||||
see [Local Network: the app is not listed in System Settings](#local-network-the-app-is-not-listed-in-system-settings)
|
||||
for why the interactive grant is not.
|
||||
|
||||
3. Or grant it interactively: run `gitea-macos-runner vm boot --image default` from a Terminal in
|
||||
the GUI session and click **Allow**. The app is not listed under **System Settings → Privacy &
|
||||
Security → Local Network** until it has made that first attempt.
|
||||
|
||||
---
|
||||
|
||||
## Local Network: the app is not listed in System Settings
|
||||
|
||||
**Symptom.** `doctor` prints the `local network access` note telling you to approve the app under
|
||||
**System Settings → Privacy & Security → Local Network**, but the runner is nowhere in that list —
|
||||
so there is nothing to switch on.
|
||||
|
||||
**Cause.** This is expected, not a bug. The Local Network list is populated lazily: an app appears
|
||||
there only *after* it has actually attempted a local-network connection and been evaluated. It
|
||||
cannot be pre-approved. A freshly installed runner that has not yet reached a guest has no entry.
|
||||
|
||||
There is also nothing to query, so `doctor` cannot tell you the grant's state. Unlike most macOS
|
||||
privacy controls, Local Network privacy is not stored in TCC — per
|
||||
[TN3179](https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy)
|
||||
the checks live "deep in the networking stack" as a Network Extension packet filter, so the
|
||||
permission is absent from `TCC.db` and `tccutil reset` does not apply to it.
|
||||
|
||||
**Fix — interactive.** Make the app connect once, from a GUI session where a human can answer:
|
||||
|
||||
```sh
|
||||
gitea-macos-runner vm boot --image default
|
||||
```
|
||||
|
||||
Click **Allow**. The entry now exists and can be toggled later. Do not wait for the LaunchAgent to
|
||||
trigger it; a background agent cannot answer the prompt, so it simply fails to reach the guest.
|
||||
|
||||
**Fix — deterministic, and what to use on a CI box.** Allowlist the VM subnet instead. It is keyed
|
||||
on the network rather than on the app, so no prompt is involved and nothing needs redoing:
|
||||
|
||||
```sh
|
||||
sudo defaults write com.apple.network.local-network \
|
||||
AllowedEthernetLocalNetworkAddresses -array "192.168.64.0/24"
|
||||
sudo defaults write com.apple.network.local-network \
|
||||
AllowedWiFiLocalNetworkAddresses -array "192.168.64.0/24"
|
||||
```
|
||||
|
||||
Reboot afterwards. `doctor` then reports `local network access` as a **pass**. Both keys are
|
||||
Apple's, documented in TN3179; the same pair is what [Tart's FAQ](https://tart.run/faq/) recommends
|
||||
for this exact problem on CI hosts.
|
||||
|
||||
> **Why the interactive grant does not stick here.** This project ships an **ad-hoc signed** bundle
|
||||
> (`codesign --sign -`), and TN3179 notes that "local network privacy uses your main executable UUID
|
||||
> as part of its implementation". The linker writes a new `LC_UUID` on essentially every rebuild, so
|
||||
> a rebuilt-and-reinstalled runner can read as a *different* program and prompt again — while the
|
||||
> old row lingers, since macOS provides no way to reset a Local Network decision to undetermined.
|
||||
> Expect duplicate entries after a few upgrades. The subnet allowlist avoids all of this.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user