Nucleic: Gitea Runner macOS VM Support

This commit is contained in:
2026-08-07 01:14:28 -07:00
parent 40697b8329
commit 975cf8c6ea
4 changed files with 163 additions and 28 deletions
+33 -8
View File
@@ -385,18 +385,43 @@ Starting with macOS 15, a process that contacts other hosts on the local network
one-time Local Network permission prompt. A LaunchAgent that is denied (or that never gets a human
to click Allow) cannot reach the guest's NAT address, so VMs boot but SSH never connects.
Grant it interactively the first time — run `gitea-macos-runner vm boot` from a
Terminal in the GUI session and click **Allow** — or pre-authorize the VM subnet:
**On a CI host, use the subnet allowlist.** It is the only deterministic option — no prompt, no GUI
session, and nothing to redo after a rebuild:
```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"
```
Adjust the range to match the subnet Virtualization.framework's NAT hands out on your host (check
`/var/db/dhcpd_leases` after a VM boots). Reboot, or restart the service, for the change to take
effect. Also confirm the runner is enabled under **System Settings → Privacy & Security → Local
Network**.
Then **reboot** — these are read at boot, so restarting the service alone is not enough. Adjust the
range to match the subnet Virtualization.framework's NAT hands out on your host (check
`/var/db/dhcpd_leases` after a VM boots); if you would rather not pin it, the RFC 1918 set
`"10.0.0.0/8" "172.16.0.0/12" "192.168.0.0/16"` also works. `doctor` reports `local network access`
as a **pass** once it can see an allowlist. Both keys are documented by Apple in
[TN3179](https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy)
and are the workaround [Tart's FAQ](https://tart.run/faq/) recommends for the same problem.
**Approving interactively instead.** The app cannot be pre-approved: it appears under **System
Settings → Privacy & Security → Local Network** only *after* it has actually attempted a connection
to a guest. An empty list is expected on a fresh install and does not mean anything is broken. To
create the entry and answer the prompt, run one boot by hand from a Terminal in the GUI session:
```sh
gitea-macos-runner vm boot --image default
```
and click **Allow**. Do not wait for the LaunchAgent to hit it — a background agent has no way to
answer the prompt.
> **Caveat with ad-hoc signing.** An interactive grant is not durable for this project's ad-hoc
> signed bundle. Local Network privacy does not use TCC; per TN3179 it "uses your main executable
> UUID as part of its implementation", and the linker mints a fresh `LC_UUID` on essentially every
> rebuild. So `make install` after a code change is liable to present as a new app that must be
> approved again — and macOS offers no way to reset a Local Network decision back to undetermined,
> so the stale entries accumulate. This is why the allowlist above, which is keyed on the subnet
> rather than on the app, is the recommendation for an unattended machine.
---
@@ -428,7 +453,7 @@ The checks, in order:
| `registration token` | A static token resolves, or one can be fetched when `fetchRegistrationTokenViaAPI` is on |
| `runner download url` | The `gitea-runner` release asset is reachable |
| `token file permissions` | Warns — not fails — when a token file is group- or world-readable |
| `local network access` | An informational note about the macOS 15+ Local Network prompt |
| `local network access` | Passes when a subnet allowlist is set; otherwise an informational note about the macOS 15+ Local Network prompt (§2.6) |
If the config file is missing or invalid, the host checks still run and the rest
are skipped — which is exactly the state a first-time operator is in. Resolve