From c71a457bcf038eb8e2ddde626bc9ea428db6f4af Mon Sep 17 00:00:00 2001 From: Andrew Moore Date: Fri, 7 Aug 2026 03:30:44 -0700 Subject: [PATCH] Nucleic: Gitea Runner macOS VM Support --- .gitea/workflows/build.yml | 74 ++++++++++++++++++++++++++++++++++++++ README.md | 19 ++++++++++ 2 files changed, 93 insertions(+) create mode 100644 .gitea/workflows/build.yml diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..30e0e38 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,74 @@ +# Builds gitea-macos-runner on the macOS runners gitea-macos-runner itself +# provides. The repo is its own integration test: if this workflow goes green, +# a guest image really can check out a repo, run a Swift toolchain, and produce +# a signed .app. +name: build + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + build: + # The bare label the daemon registers with. There is no container image + # here: jobs run in `:host` mode, directly in an ephemeral macOS 27 guest + # as the admin account, and the guest is destroyed afterwards. + runs-on: macos-arm64 + + # Well under the scheduler's 120-minute job ceiling. A clean release build + # plus the test suite is a few minutes; anything approaching an hour means + # something is wedged and the VM should be reclaimed rather than left + # holding one of the host's two guest slots. + timeout-minutes: 60 + + steps: + # Needs Node.js in the guest, which the base image provisions. + - uses: actions/checkout@v4 + + # First thing in the log, deliberately. Every plausible failure of this + # workflow that is not the code's fault is a toolchain that did not make + # it into the image — Command Line Tools missing, or present but not + # selected. Printing this up front turns "swift: command not found" + # forty lines down into a one-glance diagnosis. + - name: toolchain versions + run: | + sw_vers + swift --version + xcode-select -p + + # RunnerCoreTests only. RunnerHost is compiled (it is a dependency) but + # never exercised: nothing here touches Virtualization.framework at + # runtime, which matters because the guest cannot nest VMs. + - name: unit tests + run: swift test + + # Release build, .app assembly, ad-hoc signature. `codesign --sign -` + # needs no signing identity and no keychain, so it works unattended in a + # throwaway guest — which is the same property that makes it the + # project's shipping signature. + - name: build and sign the app bundle + run: make all + + # Proves the two things a bare `swift build` cannot: that the entitlement + # survived signing, and that the runtime resources were copied in. An + # .app missing either compiles perfectly and then fails at the first + # `image build` — exactly the class of breakage worth catching in CI. + - name: verify the bundle + # `grep … && echo` would be a check that cannot fail: bash exempts + # every command in an `&&` list except the last one from `set -e`, so a + # bundle signed with no entitlements at all would sail through. The + # grep therefore stands alone, as the step's own pass/fail. + run: | + codesign -d --entitlements - --xml .build/GiteaMacosRunner.app | grep -q virtualization + echo "entitlement OK" + ls .build/GiteaMacosRunner.app/Contents/Resources/ + +# Deliberately absent: `doctor`, `vm`, `daemon`, and `image` steps. +# +# All four either start a VM or check the host's ability to start one, and this +# job is already running inside a guest. Virtualization.framework does not +# nest, so those steps would not be a stricter test — they would be a +# guaranteed failure that says nothing about the code. The host-side behaviour +# they cover is verified on a real host, not here. diff --git a/README.md b/README.md index 702b98a..10410e1 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,25 @@ jobs: The daemon picks the job up within one poll interval, boots a VM, and tears it down when the job finishes. +## CI + +This repo builds itself. [`.gitea/workflows/build.yml`](.gitea/workflows/build.yml) runs on +`macos-arm64` — the very runners this project provides — and does a full `swift test`, `make all`, +and a check that the resulting `.app` carries the virtualization entitlement and its runtime +resources. A green run is also an end-to-end test of the runner: it means a guest image really can +check out a repo, run the Swift toolchain, and produce a signed bundle. + +For it to run at all you need: + +- the repo pushed to a Gitea **1.25 or newer** instance with Actions enabled + (`[actions] ENABLED = true`), +- `gitea-macos-runner daemon` running on an Apple silicon host and registered with that instance, +- a base image built and provisioned (`image build`) — `image list` should show `PROVISIONED: yes`. + +The workflow deliberately runs no `doctor`, `vm`, `daemon`, or `image` steps. Those start a VM or +probe the host's ability to start one, and the job is already inside a guest; Virtualization +does not nest, so they would fail for reasons that say nothing about the code. + ## Documentation - [docs/setup.md](docs/setup.md) — full Gitea-side and host-side walkthrough, config reference,