Skip to content

applecontainer: add Swift bridge skeleton and runtime stub#58

Merged
bilby91 merged 2 commits into
mainfrom
m6/pr-a-applecontainer-bridge-skeleton
May 15, 2026
Merged

applecontainer: add Swift bridge skeleton and runtime stub#58
bilby91 merged 2 commits into
mainfrom
m6/pr-a-applecontainer-bridge-skeleton

Conversation

@bilby91
Copy link
Copy Markdown
Member

@bilby91 bilby91 commented May 14, 2026

Summary

First PR of M6 — a second Runtime backend that drives Apple's container
stack on macOS (Sequoia+, arm64). This PR lands the scaffolding only:
New + Ping. Every other Runtime method returns ErrNotImplemented
until PR-B onward.

Architecture: Go package cgo-links a Swift dynamic library
(libACBridge.dylib) that imports apple/container's
ContainerAPIClient and speaks XPC to the system container-apiserver
daemon. Same daemon model as Docker — brew install container +
container system start is the user's responsibility, analogous to
dockerd for runtime/docker.

  • applecontainer-bridge/ — SwiftPM dynamic-library package, exact-pinned
    to apple/container 0.12.3. Exports ac_version, ac_ping(timeout)
    (returns JSON-encoded SystemHealth), ac_free.
  • runtime/applecontainer/ — Go package, build-tagged darwin && arm64.
    New probes ClientHealthCheck.ping; returns
    *runtime.DaemonUnavailableError on failure. Ping is also exposed as
    a method so consumers can re-probe a live runtime. Compile-time
    _ runtime.Runtime = (*Runtime)(nil) assertion catches upstream
    interface drift.
  • Non-darwin/arm64 stub returns "platform unsupported" from New so the
    package imports cleanly cross-platform.
  • Makefile bridge + bridge-clean targets.

Deferred

PR-A links the dylib at build time via cgo LDFLAGS rpath into
applecontainer-bridge/.build/.../release. Single-binary packaging via
go:embed + dlopen lands in PR-A2.

Test plan

Local verification (darwin/arm64 with daemon running):

  • brew install container && container system start
  • make bridge
  • go test ./runtime/applecontainer/... — 2 tests pass:
    TestPing_DaemonRunning round-trips a real SystemHealth through
    the bridge; TestNew_TypedErrorOnFailure asserts typed-error
    contract.
  • go test ./... — all existing tests still green; no regression.
  • GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build ./runtime/applecontainer/... — stub compiles.
  • go vet ./runtime/applecontainer/... clean.

CI: this PR does not yet add a macOS arm64 runner. The Linux runner
exercises the stub path; make bridge + the daemon-dependent tests
run on a developer machine until the M6 CI job lands (PR-H).

Summary by CodeRabbit

  • New Features
    • Apple Container runtime added for macOS arm64 with bridge-based health checks and runtime version reporting
  • Documentation
    • Package-level docs describing macOS arm64 runtime behavior and platform fallbacks
  • Tests
    • Integration tests for daemon connectivity and typed error handling
  • Chores
    • Build helpers and ignore rules added for the bridge component

Review Change Stack

First PR of M6 (apple-container runtime backend). Lands the
applecontainer-bridge/ SwiftPM dynamic library and the
runtime/applecontainer/ Go package as a skeleton — New + Ping only,
every other Runtime method returns ErrNotImplemented for PR-B onward
to fill in.

Bridge (Swift):
- Pinned exact to apple/container 0.12.3.
- @_cdecl exports: ac_version, ac_ping(timeout) returning JSON-encoded
  SystemHealth, ac_free.

Runtime (Go, darwin && arm64):
- New probes ClientHealthCheck.ping; returns
  *runtime.DaemonUnavailableError if unreachable.
- Ping exposed as a method so consumers can re-probe a live runtime.
- Compile-time runtime.Runtime interface assertion catches upstream
  signature changes.
- Non-darwin/arm64 build tag links a stub so the package imports
  cleanly cross-platform.

Distribution: PR-A links the dylib at build time via cgo LDFLAGS rpath
into applecontainer-bridge/.build/.../release. Run `make bridge`
before any Go build that links runtime/applecontainer on darwin/arm64.
go:embed + dlopen single-binary packaging lands in PR-A2.

Test plan (run on darwin/arm64 with `container system start` first):
- `make bridge && go test ./runtime/applecontainer/...`

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

coderabbitai Bot commented May 14, 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: 98de9375-8a76-4e97-a957-28df248ee4a6

📥 Commits

Reviewing files that changed from the base of the PR and between 8d01be7 and f9e8406.

📒 Files selected for processing (3)
  • Makefile
  • applecontainer-bridge/Sources/ACBridge/bridge.swift
  • runtime/applecontainer/runtime_darwin_arm64.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • applecontainer-bridge/Sources/ACBridge/bridge.swift

📝 Walkthrough

Walkthrough

Adds a darwin/arm64 Apple Container runtime that links to a new Swift C-bridge (ACBridge) for daemon health checks and version info, includes cgo wiring, runtime types and Ping/BridgeVersion implementations, runtime method stubs, Makefile build targets, ignore rules, and darwin/arm64 integration tests.

Changes

Apple Container Runtime for macOS arm64

Layer / File(s) Summary
Build targets and .gitignore
Makefile, .gitignore, applecontainer-bridge/.gitignore
Makefile adds bridge and bridge-clean (uname-guarded swift build/clean). Root .gitignore ignores examples/applecontainer-spike/. Bridge .gitignore ignores SwiftPM .build/ and Package.resolved.
cgo directives and linkage
runtime/applecontainer/runtime_darwin_arm64.go (cgo headers)
Adds darwin/arm64 build tag and cgo directives to link libACBridge.dylib and include ac_bridge.h.
Runtime types and JSON-mapped PingResult
runtime/applecontainer/runtime_darwin_arm64.go
Defines Runtime, Options, and PingResult with JSON tags and a compile-time interface assertion that *Runtime implements runtime.Runtime.
New constructor and initial health check
runtime/applecontainer/runtime_darwin_arm64.go
New(ctx, opts) validates ctx, fetches bridge version, runs Ping() with configured timeout, and returns an error if the daemon health probe fails.
Ping implementation and JSON handling
runtime/applecontainer/runtime_darwin_arm64.go
Ping() clamps timeout to ctx deadline, calls ac_ping, converts and frees C string, unmarshals JSON payload, returns *runtime.DaemonUnavailableError when bridge returns nil or ok:false, and returns formatted error on JSON unmarshal failures.
BridgeVersion and bridge helpers
runtime/applecontainer/runtime_darwin_arm64.go
BridgeVersion() returns cached bridge version; helper calls ac_version() and converts/frees the C string (returns empty string on nil).
Runtime interface stubs
runtime/applecontainer/runtime_darwin_arm64.go, runtime/applecontainer/runtime_unsupported.go, runtime/applecontainer/doc.go
Adds package doc, unsupported-platform stub (non-darwin/arm64) that errors on New, and exported method stubs (build/pull/run/inspect/logs/etc.) that return runtime.ErrNotImplemented.
Integration tests for darwin/arm64 runtime
runtime/applecontainer/runtime_darwin_arm64_test.go
TestPing_DaemonRunning pings daemon with 3s timeout, skips if daemon unavailable, asserts bridge version prefix and non-empty fields. TestNew_TypedErrorOnFailure verifies error typing when ping timeout is zero.
Swift package manifest and bridge sources
applecontainer-bridge/Package.swift, applecontainer-bridge/Sources/ACBridge/bridge.swift, applecontainer-bridge/include/ac_bridge.h
Adds Swift Package manifest for ACBridge (macOS 15+, dynamic lib), pinned apple/container 0.12.3, C header ac_bridge.h declaring ac_version, ac_ping, ac_free, and Swift bridge implementation that returns JSON health payloads and version strings to C callers.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A rabbit hops across the bridge of code, 🐇
Swift strings meet C and carry the load,
A ping returns a tidy JSON song,
Stubs await the work that won't be long,
darwin/arm64 — connected, proud.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding a Swift bridge skeleton and a runtime stub for Apple container support.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch m6/pr-a-applecontainer-bridge-skeleton

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: 3

🤖 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 `@applecontainer-bridge/Sources/ACBridge/bridge.swift`:
- Around line 14-29: ac_ping blocks indefinitely because sem.wait() is
unbounded; replace the plain sem.wait() with a timed wait using
DispatchSemaphore.wait(timeout:) based on the same timeoutSeconds (use the same
default 5s logic), check for .timedOut, and if timed out set a deterministic
error payload (e.g. call encodePingErr with a small PingTimeout Error type or
set json to a timeout JSON) before returning; refer to ac_ping,
DispatchSemaphore, Task, ClientHealthCheck.ping, encodePingOK and encodePingErr
to locate and update the logic.

In `@Makefile`:
- Around line 36-44: The Makefile targets bridge and bridge-clean currently
invoke swift unconditionally; update both targets (bridge and bridge-clean) to
first check the platform and architecture (e.g., uname -s and uname -m or
GOOS/GOARCH env) and only run the swift commands when on darwin and arm64,
otherwise treat the target as a no-op (print a short message or exit 0). Ensure
you change the bridge recipe (cd applecontainer-bridge && swift build -c
release) and bridge-clean recipe (cd applecontainer-bridge && swift package
clean && rm -rf .build) to be guarded by that platform check so they don't run
swift on unsupported systems.

In `@runtime/applecontainer/runtime_darwin_arm64.go`:
- Around line 81-86: The Ping method currently ignores ctx's deadline; change
Runtime.Ping to compute an effective timeout by checking ctx.Deadline() and
using the minimum of timeoutSeconds and the remaining time until the deadline
(rounding up to whole seconds), returning ctx.Err() immediately if the deadline
has already passed, then call C.ac_ping with that effective timeout (the
C.ac_ping invocation and cstr handling remain the same). Locate the Ping
function, replace the direct use of timeoutSeconds for C.ac_ping with the
computed effectiveTimeout (int32), and ensure you still respect ctx.Err() at the
top and before invoking C.ac_ping.
🪄 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: fb277a14-cb5d-424d-93e7-9703471b6e71

📥 Commits

Reviewing files that changed from the base of the PR and between 2178286 and 8d01be7.

📒 Files selected for processing (10)
  • .gitignore
  • Makefile
  • applecontainer-bridge/.gitignore
  • applecontainer-bridge/Package.swift
  • applecontainer-bridge/Sources/ACBridge/bridge.swift
  • applecontainer-bridge/include/ac_bridge.h
  • runtime/applecontainer/doc.go
  • runtime/applecontainer/runtime_darwin_arm64.go
  • runtime/applecontainer/runtime_darwin_arm64_test.go
  • runtime/applecontainer/runtime_unsupported.go

Comment thread applecontainer-bridge/Sources/ACBridge/bridge.swift
Comment thread Makefile Outdated
Comment thread runtime/applecontainer/runtime_darwin_arm64.go
Three fixes from CodeRabbit review on #58, all valid:

bridge.swift: ac_ping's `sem.wait()` was unbounded — if the Swift
Task never signals (cancellation race, runtime hang) the cgo caller
would block forever. ClientHealthCheck.ping already enforces its own
Duration timeout, but we guard the semaphore as belt-and-suspenders
with a deterministic "bridge-timeout" error payload.

Makefile: bridge / bridge-clean recipes were unconditional but the
comment claimed "no-op on other platforms." Guard with uname so
invoking on linux/amd64 prints a clear skip message rather than
failing with "swift: command not found." Comment rewritten to match.

runtime_darwin_arm64.go: Ping ignored ctx.Deadline(). Clamp the
effective bridge timeout to min(timeoutSeconds, ceil(time.Until(
deadline).Seconds())) and return ctx.Err() if the deadline has
already passed. The bridge call is synchronous from Go's view so we
can't cancel mid-flight; bounding the argument is the closest we get
to context semantics.

Test plan:
- `make bridge` still builds the dylib on darwin/arm64
- `make bridge` on non-darwin/arm64 prints "skipped" and exits 0
- `go test ./runtime/applecontainer/...` — 2 tests pass
- `GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build` of stub — ok
- `go vet ./runtime/applecontainer/...` — clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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