Skip to content

ci: add darwin/arm64 unit and integration test jobs#63

Merged
bilby91 merged 10 commits into
mainfrom
ci/darwin-runners
May 15, 2026
Merged

ci: add darwin/arm64 unit and integration test jobs#63
bilby91 merged 10 commits into
mainfrom
ci/darwin-runners

Conversation

@bilby91
Copy link
Copy Markdown
Member

@bilby91 bilby91 commented May 15, 2026

Summary

Extends the CI pipeline with two macOS jobs so the apple-container backend gets coverage equivalent to the Linux side:

  • test-darwin (macos-15) — builds the Swift bridge and runs the Go test suite on darwin/arm64. Exercises cgo, go:embed of libACBridge.dylib, and daemon-free unit tests. Daemon-dependent tests skip cleanly. Deterministic, blocks merges.

  • test-integration-darwin (macos-15, continue-on-error: true) — installs the signed apple/container .pkg from GitHub releases, brings up the apiserver + builder, runs TestAppleContainer_* integration tests. Marked continue-on-error because Apple's runtime officially requires macOS 26 (vmnet networking doesn't work pre-26) and macos-15 is the newest hosted image available. The job exists to get empirical signal on what works on the current runner — drop continue-on-error once a green run on main confirms the contract.

Test plan

  • test-darwin goes green
  • test-integration-darwin produces useful output (either green or a clear failure mode pointing at macOS 15 vs 26)
  • Existing Linux jobs unaffected

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added macOS CI jobs to run Swift tooling on macOS 26: select a Swift 6.2–compatible Xcode, cache SwiftPM artifacts, build the Swift bridge, and run Go unit tests.
    • Added a non-blocking macOS integration job that installs Apple container software from release artifacts, starts container services and builder, runs targeted integration tests (15‑minute timeout), and always attempts clean shutdown.
    • Stop ignoring the Swift package lockfile and include the resolved dependency lockfile in source control.

Review Change Stack

Adds two macOS jobs to complement the existing Linux pipeline so the
applecontainer backend (runtime/applecontainer, darwin/arm64-only)
gets CI coverage:

- test-darwin (macos-15): builds the Swift bridge via `make bridge`,
  runs `go vet` and `go test -race ./...`. Exercises cgo compilation,
  go:embed of libACBridge.dylib, and the daemon-free unit tests.
  Daemon-dependent tests skip cleanly via runtimeOrSkip when Apple's
  `container` apiserver isn't running. Deterministic, blocks merges.

- test-integration-darwin (macos-15, continue-on-error): installs the
  signed `apple/container` pkg from GitHub releases, brings up the
  apiserver + builder, and runs `TestAppleContainer_*` integration
  tests. Filtered with -run to skip the docker-backed tests that
  share the `integration` tag. Marked continue-on-error because
  Apple's runtime officially requires macOS 26 (vmnet networking
  doesn't work pre-26), and macos-15 is the newest hosted image GH
  Actions exposes today — this job exists to get empirical signal on
  what works, not to block merges. Drop continue-on-error once a
  green run on main establishes the contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 838d9d3b-7c37-48ed-a6fa-fe19de5251ab

📥 Commits

Reviewing files that changed from the base of the PR and between c4cd55b and d2cbd19.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

📝 Walkthrough

Walkthrough

Adds two macOS CI jobs on macos-26: test-darwin builds the Swift bridge, caches SwiftPM artifacts (tracks Package.resolved), and runs unit tests; test-integration-darwin (depends on test-darwin, continue-on-error) installs Apple container services, starts apiserver/builder, and runs TestAppleContainer_* integration tests.

Changes

macOS CI Testing

Layer / File(s) Summary
macOS unit tests with Swift bridge
.github/workflows/ci.yml, applecontainer-bridge/.gitignore, applecontainer-bridge/Package.resolved
test-darwin job on macos-26 selects Xcode for Swift 6.2, caches/restores SwiftPM artifacts for applecontainer-bridge, runs make bridge, then go vet ./... and go test -race -count=1 ./.... Also removes Package.resolved from .gitignore and adds Package.resolved lockfile.
macOS integration tests with container services
.github/workflows/ci.yml
test-integration-darwin job on macos-26, depends on test-darwin, continue-on-error: true; downloads and installs installer-signed.pkg via authenticated gh release download, selects Xcode, restores SwiftPM cache, rebuilds bridge, starts apiserver (--disable-kernel-install), sets recommended kernel non-interactively, starts builder, runs integration tests filtered to TestAppleContainer_ with -tags=integration and -timeout=15m, and stops services in an always() step using `

Sequence Diagram — macOS integration test startup flow:

sequenceDiagram
  participant GitHubRunner
  participant GHRelease as "GitHub Release"
  participant XcodeSelector
  participant Apiserver
  participant Builder
  participant GoTests
  GitHubRunner->>GHRelease: gh release download installer-signed.pkg (auth via GITHUB_TOKEN)
  GitHubRunner->>XcodeSelector: select Xcode compatible with Swift 6.2
  GitHubRunner->>Apiserver: container system start --disable-kernel-install
  Apiserver-->>GitHubRunner: apiserver ready
  GitHubRunner->>Apiserver: container system kernel set --recommended
  GitHubRunner->>Builder: start container builder
  GitHubRunner->>GoTests: run TestAppleContainer_* (-tags=integration, -timeout=15m)
Loading

Estimated code review effort:
🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 I built a tiny bridge at dawn,
macOS hills waking with a yawn,
Tests that sprint and services hum,
Containers dance till checks are done,
A carrot cheer — CI's now drawn! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding darwin/arm64 CI test jobs (both unit and integration).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/darwin-runners

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

87-124: ⚡ Quick win

Add a job-level timeout for integration runs.

Only the go test command is bounded; install/startup steps can still hang and occupy a macOS runner for hours. Add timeout-minutes on the job.

⏱️ Proposed change
   test-integration-darwin:
     runs-on: macos-15
     needs: [test-darwin]
     continue-on-error: true
+    timeout-minutes: 30
     steps:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 87 - 124, The test-integration-darwin
job can hang during setup; add a job-level timeout by adding a timeout-minutes
field to the test-integration-darwin job definition (e.g., timeout-minutes: 60)
so the entire job (including Install apple/container, Start container apiserver,
Start builder, and Run apple-container integration tests steps) will be
terminated after the configured minutes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 97-104: The workflow currently installs a downloaded .pkg as root
without verifying its installer identity; modify the step that downloads and
runs /tmp/container.pkg to verify its signer using pkgutil --check-signature and
compare the extracted "Developer ID Installer: <Name> (<Team ID>)" string to the
exact signer identity for apple/container (determine this by running pkgutil
--check-signature on a known release and copying the full signer line), and if
the signer does not match, abort before running sudo installer -pkg; use the
PKG_URL and /tmp/container.pkg variables already present to locate the file and
fail the job with a non-zero exit when the signature check does not match.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 87-124: The test-integration-darwin job can hang during setup; add
a job-level timeout by adding a timeout-minutes field to the
test-integration-darwin job definition (e.g., timeout-minutes: 60) so the entire
job (including Install apple/container, Start container apiserver, Start
builder, and Run apple-container integration tests steps) will be terminated
after the configured minutes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 18160ad6-57aa-4569-a3d5-087af77b81b3

📥 Commits

Reviewing files that changed from the base of the PR and between 9aebace and 950d217.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

Comment thread .github/workflows/ci.yml
bilby91 and others added 6 commits May 15, 2026 14:45
apple/container 0.12.3 declares swift-tools-version 6.2, which is
only in Xcode 26.x. macos-15 runners ship multiple Xcode versions
but default to an older one — pick the newest installed before
running `make bridge`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The anonymous curl to api.github.com was rate-limited (HTTP 403)
on shared CI egress IPs. Use `gh release download` with GH_TOKEN so
the request goes against the authenticated 5k/hr limit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`container system start --disable-kernel-install` skips the
interactive kernel prompt but leaves no kernel configured, so
`container builder start` fails with "default kernel not configured
for architecture arm64". Install Apple's recommended kernel
non-interactively via `container system kernel set --from-recommended`
between start and builder.

Also confirms that `container system start` itself works on a
macos-15 hosted runner — the apiserver came up cleanly in the
previous run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Fix the kernel install flag: it's `--recommended`, not
  `--from-recommended`. The CLI surfaced "Unknown option" with the
  correct usage line; this aligns with `container system kernel
  set --help`.

- Cache applecontainer-bridge/.build and SwiftPM's per-user
  checkout directory between runs, keyed on Package.resolved. The
  from-scratch bridge build was ~5-6 minutes (resolving
  apple/container + NIO/gRPC, then compiling); a warm cache should
  drop that to roughly the link step (~30s). Cache prefix is `v1`
  so we can force a full miss after a toolchain change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`container builder start` fails with VZErrorDomain Code=2
("Virtualization is not available on this hardware") on
GitHub-hosted macos-15 runners. The earlier steps (pkg install,
system start, kernel set) all succeed; the wall is reached only
when the runtime tries to actually boot a Linux guest VM.

Record the finding in the workflow comment so the constraint is
discoverable next time someone wonders why integration-darwin is
allowed to fail. The job stays in place (continue-on-error) so the
failure is visible and easy to retry once GH exposes VZ or we add
a self-hosted runner with virtualization entitlements.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
macos-26 (Tahoe) is now GA as a GitHub-hosted runner label.
macos-15 doesn't expose Virtualization.framework for Linux guests,
which blocks `container builder start` (Apple's runtime has no
QEMU fallback like Colima/Lima). Bump both darwin jobs to
macos-26 to see if VZ is exposed on the newer image.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
.github/workflows/ci.yml (1)

119-130: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Verify package signature before sudo installer execution.

Line 129 installs a downloaded .pkg as root without a signature gate. This is a supply-chain risk in CI.

🔐 Minimal hardening patch
       - name: Install apple/container
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         run: |
@@
           gh release download --repo apple/container \
             --pattern '*installer-signed.pkg' \
             --output /tmp/container.pkg
+          # Fail closed if signer does not match expected Developer ID Installer identity.
+          EXPECTED_SIGNER="Developer ID Installer: Apple Inc. (TEAMID)"
+          pkgutil --check-signature /tmp/container.pkg | grep -Fq "$EXPECTED_SIGNER" \
+            || { echo "::error::Unexpected package signer"; exit 1; }
           sudo installer -pkg /tmp/container.pkg -target /
           container --version
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 119 - 130, After downloading
/tmp/container.pkg, add a signature verification step and fail the job if
verification fails: run a package signature check (e.g., pkgutil
--check-signature /tmp/container.pkg or spctl --assess --type install -v
/tmp/container.pkg) and abort before running sudo installer -pkg
/tmp/container.pkg -target /; ensure the CI step that currently runs gh release
download and then sudo installer now checks the signature of /tmp/container.pkg
and logs/fails explicitly if the signature check does not report a valid
developer/macos installer signature.
🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

109-113: ⚡ Quick win

Add an explicit timeout to prevent long-running macOS integration hangs.

This job exercises virtualization/runtime setup and can stall for a long time on hosted runners; adding timeout-minutes improves CI reliability/cost control.

⏱️ Suggested change
   test-integration-darwin:
     runs-on: macos-26
     needs: [test-darwin]
     continue-on-error: true
+    timeout-minutes: 30
     steps:

Also applies to: 147-165

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 109 - 113, The test-integration-darwin
GitHub Actions job (job id test-integration-darwin) can hang indefinitely on
macOS runners; add a timeout-minutes property to the job definition to cap its
runtime (e.g., timeout-minutes: 60) to prevent long-running stalls and control
CI costs; also apply the same change to the other integration job referenced in
the comment (the job block around lines 147-165) so both jobs have explicit
timeouts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.github/workflows/ci.yml:
- Around line 119-130: After downloading /tmp/container.pkg, add a signature
verification step and fail the job if verification fails: run a package
signature check (e.g., pkgutil --check-signature /tmp/container.pkg or spctl
--assess --type install -v /tmp/container.pkg) and abort before running sudo
installer -pkg /tmp/container.pkg -target /; ensure the CI step that currently
runs gh release download and then sudo installer now checks the signature of
/tmp/container.pkg and logs/fails explicitly if the signature check does not
report a valid developer/macos installer signature.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 109-113: The test-integration-darwin GitHub Actions job (job id
test-integration-darwin) can hang indefinitely on macOS runners; add a
timeout-minutes property to the job definition to cap its runtime (e.g.,
timeout-minutes: 60) to prevent long-running stalls and control CI costs; also
apply the same change to the other integration job referenced in the comment
(the job block around lines 147-165) so both jobs have explicit timeouts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 894a8a10-52de-4926-8b7d-f2b4c63e3385

📥 Commits

Reviewing files that changed from the base of the PR and between b81152f and 4566bfe.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

Bumping the runner to macos-26 (the newest hosted image GH offers)
produced the same VZErrorDomain Code=2 failure as macos-15. This
confirms the limitation is at the runner-platform layer, not a
per-image setting — GH hosted macOS runners simply do not expose
Virtualization.framework for Linux guests.

Update the workflow comment so the next engineer doesn't re-derive
this. Apple's `container` runtime has no QEMU fallback, so there's
no workflow-level workaround; we need a self-hosted runner or for
GH to expose VZ. continue-on-error stays.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

118-122: ⚡ Quick win

Add an explicit timeout to the non-blocking integration job.

This job can still hang on runtime startup paths; without timeout-minutes, it can run for the default ~6h and delay CI feedback.

💡 Suggested change
   test-integration-darwin:
     runs-on: macos-26
     needs: [test-darwin]
     continue-on-error: true
+    timeout-minutes: 30
     steps:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 118 - 122, The non-blocking GitHub
Actions job "test-integration-darwin" lacks an explicit timeout and can hang for
hours; add a timeout-minutes field to the job definition (e.g., timeout-minutes:
30) under the "test-integration-darwin" job to bound its execution and prevent
long CI stalls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 118-122: The non-blocking GitHub Actions job
"test-integration-darwin" lacks an explicit timeout and can hang for hours; add
a timeout-minutes field to the job definition (e.g., timeout-minutes: 30) under
the "test-integration-darwin" job to bound its execution and prevent long CI
stalls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 99348e37-e936-4676-bcf2-70d3473ec28c

📥 Commits

Reviewing files that changed from the base of the PR and between 4566bfe and 6af9bcf.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

bilby91 and others added 2 commits May 15, 2026 16:30
The previous workflow keyed the SwiftPM cache on
hashFiles('applecontainer-bridge/Package.resolved'), but that file
was in .gitignore — it didn't exist on the freshly-checked-out
runner, so hashFiles returned an empty string and every key
collapsed to the prefix `swiftpm-v1-macOS-ARM64-`. With prefix-only
keys, the cache was technically restored but reflected whichever
toolchain happened to populate it last, so SwiftPM rebuilt from
scratch whenever the OS image moved.

Track Package.resolved in the repo — standard SwiftPM convention
for top-level applications (the bridge ships a dylib, it's not
consumed as a SwiftPM library) — so the cache key resolves to a
real hash and warm builds actually hit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Job-level `continue-on-error: true` only stops the workflow run
from failing — the individual job still shows red on the PR check
list, which is the noise that was bugging me. Move the lenience
to the step level: mark `Start builder` continue-on-error and gate
the test step on its outcome.

Net effect:
  - Hosted runner (VZ unavailable): builder step fails inline,
    tests are skipped, job ends green.
  - Self-hosted runner (or future hosted with VZ): builder
    succeeds, tests run, job is green or red on real signal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bilby91 bilby91 merged commit 128b584 into main May 15, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant