diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88e6e8f..66f501f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,3 +58,130 @@ jobs: docker compose version - name: Run integration tests run: make test-integration + + # Apple-container backend lives in runtime/applecontainer and is + # darwin/arm64-only (see build tags). This job builds the Swift + # bridge and runs the Go test suite on macOS so we get coverage of + # 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. + test-darwin: + runs-on: macos-26 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version: "1.25" + cache: true + - name: Select Xcode with Swift 6.2 + # apple/container 0.12.3 declares swift-tools-version 6.2; + # the macos-15 image ships an older Xcode by default. Pick + # the newest installed so SwiftPM can resolve the package. + run: sudo xcode-select -s /Applications/Xcode_latest.app || sudo xcode-select -s "$(ls -d /Applications/Xcode_*.app | sort -V | tail -1)" + - name: Cache SwiftPM artifacts + uses: actions/cache@v4 + with: + path: | + applecontainer-bridge/.build + ~/Library/Caches/org.swift.swiftpm + # Key on Package.resolved so the cache busts when dependency + # versions move. Bump the `v1` prefix to force a full miss + # after a toolchain change that breaks artifact compat. + key: swiftpm-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('applecontainer-bridge/Package.resolved') }} + restore-keys: | + swiftpm-v1-${{ runner.os }}-${{ runner.arch }}- + - name: Build Swift bridge + run: make bridge + - run: go vet ./... + - run: go test -race -count=1 ./... + + # Integration tests against a live Apple `container` daemon. + # + # Verified-on-CI status: + # - pkg install : OK on macos-15 and macos-26 + # - system start : OK + # - kernel set : OK + # - builder start : FAILS on both macos-15 and macos-26 with + # "VZErrorDomain Code=2 Virtualization is not available on + # this hardware." + # + # i.e. GitHub-hosted macOS runners do not expose + # Virtualization.framework for Linux guests, regardless of image + # version. Apple's `container` runtime is hardcoded to VZ (no QEMU + # fallback like Colima/Lima), so there is no workaround at the + # workflow level. The only paths to a passing job today are: + # 1. Self-hosted macOS runner with virtualization entitlements + # 2. GH exposing VZ on hosted runners (no announced timeline) + # + # continue-on-error keeps the failure visible without blocking + # merges. Drop it once a real green run is available. + test-integration-darwin: + runs-on: macos-26 + needs: [test-darwin] + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version: "1.25" + cache: true + - name: Install apple/container + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # `gh release download` authenticates with GH_TOKEN, dodging + # the strict anonymous rate limit on api.github.com that + # bit us when curling the unauth'd releases endpoint. + gh release download --repo apple/container \ + --pattern '*installer-signed.pkg' \ + --output /tmp/container.pkg + sudo installer -pkg /tmp/container.pkg -target / + container --version + - name: Select Xcode with Swift 6.2 + # apple/container 0.12.3 declares swift-tools-version 6.2; + # the macos-15 image ships an older Xcode by default. Pick + # the newest installed so SwiftPM can resolve the package. + run: sudo xcode-select -s /Applications/Xcode_latest.app || sudo xcode-select -s "$(ls -d /Applications/Xcode_*.app | sort -V | tail -1)" + - name: Cache SwiftPM artifacts + uses: actions/cache@v4 + with: + path: | + applecontainer-bridge/.build + ~/Library/Caches/org.swift.swiftpm + key: swiftpm-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('applecontainer-bridge/Package.resolved') }} + restore-keys: | + swiftpm-v1-${{ runner.os }}-${{ runner.arch }}- + - name: Build Swift bridge + run: make bridge + - name: Start container apiserver + run: | + # --disable-kernel-install skips the interactive kernel prompt + # that would otherwise hang in CI; we install the recommended + # kernel explicitly in the next step. + container system start --disable-kernel-install + container system status + - name: Install default kernel + # The builder (and any container) needs a configured kernel. + # `--recommended` pulls Apple's recommended binary + # non-interactively, which `--disable-kernel-install` skipped. + run: container system kernel set --recommended + - name: Start builder + id: builder + # On GH-hosted macOS runners VZ is unavailable, so this step + # always fails. Mark it continue-on-error so the JOB stays + # green (continue-on-error at job level wouldn't — that only + # affects workflow status, not the per-job check). The next + # step gates on this step's outcome so we don't run the + # integration tests against a missing daemon. + continue-on-error: true + run: container builder start + - name: Run apple-container integration tests + if: steps.builder.outcome == 'success' + # Filter to TestAppleContainer_* — the docker-backed tests + # share the `integration` build tag and would fail without a + # Docker daemon on this runner. + run: go test -race -count=1 -tags=integration -timeout=15m -run '^TestAppleContainer_' ./test/integration/... + - name: Stop container services + if: always() + run: | + container builder stop || true + container system stop || true diff --git a/applecontainer-bridge/.gitignore b/applecontainer-bridge/.gitignore index bb39a0b..30bcfa4 100644 --- a/applecontainer-bridge/.gitignore +++ b/applecontainer-bridge/.gitignore @@ -1,2 +1 @@ .build/ -Package.resolved diff --git a/applecontainer-bridge/Package.resolved b/applecontainer-bridge/Package.resolved new file mode 100644 index 0000000..e8afb9a --- /dev/null +++ b/applecontainer-bridge/Package.resolved @@ -0,0 +1,293 @@ +{ + "pins" : [ + { + "identity" : "async-http-client", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/async-http-client.git", + "state" : { + "revision" : "3a5b74a58782c3b4c1f0bc75e9b67b10c2494e8f", + "version" : "1.33.1" + } + }, + { + "identity" : "container", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/container.git", + "state" : { + "revision" : "f9899013fd43dd058fdf89709eed0b0861bfd931", + "version" : "0.12.3" + } + }, + { + "identity" : "containerization", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/containerization.git", + "state" : { + "revision" : "f1ee6f8b737ab8dffbd620bfa47283f6f0bc1822", + "version" : "0.31.0" + } + }, + { + "identity" : "grpc-swift-2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-2.git", + "state" : { + "revision" : "21fe69ab7ce0e87ac089534733c52f037e74a3eb", + "version" : "2.4.1" + } + }, + { + "identity" : "grpc-swift-nio-transport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-nio-transport.git", + "state" : { + "revision" : "f62a09000685b5b86ee383b63e042f286b1a5422", + "version" : "2.7.0" + } + }, + { + "identity" : "grpc-swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-protobuf.git", + "state" : { + "revision" : "8723cf856dc23d9c2fad4d874e7b9ed3254acf03", + "version" : "2.3.0" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", + "version" : "1.2.1" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "626b5b7b2f45e1b0b1c6f4a309296d1d21d7311b", + "version" : "1.7.1" + } + }, + { + "identity" : "swift-asn1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-asn1.git", + "state" : { + "revision" : "eb50cbd14606a9161cbc5d452f18797c90ef0bab", + "version" : "1.7.0" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms.git", + "state" : { + "revision" : "9d349bcc328ac3c31ce40e746b5882742a0d1272", + "version" : "1.1.3" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-certificates", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-certificates.git", + "state" : { + "revision" : "bde8ca32a096825dfce37467137c903418c1893d", + "version" : "1.19.1" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "03cc312c2c933ed87abace34044a5dff7a3117c1", + "version" : "1.5.0" + } + }, + { + "identity" : "swift-configuration", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-configuration.git", + "state" : { + "revision" : "be76c4ad929eb6c4bcaf3351799f2adf9e6848a9", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", + "version" : "3.15.1" + } + }, + { + "identity" : "swift-distributed-tracing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-distributed-tracing.git", + "state" : { + "revision" : "dc4030184203ffafbb2ec614352487235d747fe0", + "version" : "1.4.1" + } + }, + { + "identity" : "swift-http-structured-headers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-structured-headers.git", + "state" : { + "revision" : "933538faa42c432d385f02e07df0ace7c5ecfc47", + "version" : "1.7.0" + } + }, + { + "identity" : "swift-http-types", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-types.git", + "state" : { + "revision" : "45eb0224913ea070ec4fba17291b9e7ecf4749ca", + "version" : "1.5.1" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "5073617dac96330a486245e4c0179cb0a6fd2256", + "version" : "1.12.0" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "f71c8d2a5e74a2c6d11a0fbe324774b5d6084237", + "version" : "2.99.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "5a48717e29f62cb8326d6d42e46b562ca93847a6", + "version" : "1.34.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "81cc18264f92cd307ff98430f89372711d4f6fe9", + "version" : "1.43.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "3f337058ccd7243c4cac7911477d8ad4c598d4da", + "version" : "2.37.0" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "67787bb645a5e67d2edcdfbe48a216cc549222d5", + "version" : "1.28.0" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics.git", + "state" : { + "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "81558271e243f8f47dfe8e9fdd55f3c2b5413f68", + "version" : "1.37.0" + } + }, + { + "identity" : "swift-service-context", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-service-context.git", + "state" : { + "revision" : "d0997351b0c7779017f88e7a93bc30a1878d7f29", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-service-lifecycle", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/swift-service-lifecycle.git", + "state" : { + "revision" : "9829955b385e5bb88128b73f1b8389e9b9c3191a", + "version" : "2.11.0" + } + }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "7c6ad0fc39d0763e0b699210e4124afd5041c5df", + "version" : "1.6.4" + } + }, + { + "identity" : "swift-toml", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mattt/swift-toml.git", + "state" : { + "revision" : "827506c90475e82d5a7f191f950fb3025cbdc0d6", + "version" : "2.0.0" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "deaf82e867fa2cbd3cd865978b079bfcf384ac28", + "version" : "6.2.1" + } + }, + { + "identity" : "zstd", + "kind" : "remoteSourceControl", + "location" : "https://github.com/facebook/zstd.git", + "state" : { + "revision" : "f8745da6ff1ad1e7bab384bd1f9d742439278e99", + "version" : "1.5.7" + } + } + ], + "version" : 2 +}