CI/CD Pipeline for apple/container: GitHub Actions Workflow Explained

The apple/container project uses a GitHub Actions-based CI/CD pipeline where three workflow files orchestrate builds, tests, and releases by delegating to a shared common.yml configuration executed on self-hosted macOS runners.

The apple/container repository automates its software delivery through a comprehensive CI/CD pipeline defined in the .github/workflows/ directory. This pipeline validates every contribution through automated checks and produces signed release artifacts for Apple's containerization framework. All workflow jobs execute on self-hosted macOS runners with Apple Silicon architecture to ensure native ARM64 compatibility.

Workflow Architecture Overview

The CI/CD pipeline employs a modular design pattern that separates event triggers from implementation logic. Three entry-point workflows—pr-build.yml, merge-build.yml, and release.yml—handle specific Git events while delegating execution to .github/workflows/common.yml. This architecture eliminates duplication and ensures consistent build behavior across different trigger types.

The Three Entry-Point Workflows

PR Build (pr-build.yml)

Located at .github/workflows/pr-build.yml, this workflow triggers on pull_request events (opened, reopened, synchronize). It executes two sequential jobs: first, a signature verification step that validates all commits are cryptographically signed, followed by the shared build and test workflow. The workflow passes release: false and coverage: true to the common configuration.

name: container project - PR build
on:
  pull_request:
    types: [opened, reopened, synchronize]

jobs:
  verify-signatures:
    runs-on: ubuntu-latest
    steps:
      - name: Check all commits are signed
        env:
          GH_TOKEN: ${{ github.token }}
          REPO: ${{ github.repository }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          commits=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/commits" --paginate)
          # ... loop that fails on unsigned commits ...

  build:
    uses: ./.github/workflows/common.yml
    with:
      release: false
      coverage: true
      pr_number: ${{ github.event.pull_request.number }}

Merge Build (merge-build.yml)

The .github/workflows/merge-build.yml workflow activates on push events to the main branch or any release/* branch. It invokes common.yml with release: true to ensure merged code produces releasable artifacts and passes all integration tests.

Release Build (release.yml)

Triggered exclusively by version tags matching the vX.Y.Z pattern, .github/workflows/release.yml coordinates production releases. After executing the shared build logic with release configuration, it uses the softprops/action-gh-release action to create a draft GitHub release marked as prerelease, attaching the built .pkg and .zip artifacts.

Shared Build Logic in common.yml

The pipeline's core implementation resides in .github/workflows/common.yml, which executes on runs-on: [self-hosted, macos, tahoe, ARM64]. This workflow accepts boolean inputs including release, coverage, and pr_number to customize behavior.

The shared workflow executes the following stages:

  1. Checkout - Retrieves full repository history using actions/checkout@v7 with fetch-depth: 0
  2. Formatting Verification - Executes make fmt after installing the Hawkeye formatter via scripts/install-hawkeye.sh, failing if uncommitted changes exist
  3. Protobuf Validation - Runs make protos to ensure generated code is synchronized with source definitions
  4. Configuration - Sets the BUILD_CONFIGURATION environment variable to debug or release based on the inputs.release value
  5. Compilation - Executes make container dsym docs to build the binary, debug symbols, and documentation, then archives the site as _site.tgz
  6. Testing - Runs make test install-kernel integration integration-new for standard validation, or make coverage-new when coverage analysis is requested
  7. Coverage Processing - Extracts line-coverage percentages and archives HTML reports when enabled
  8. Artifact Packaging - Bundles container-installer-unsigned.pkg and dSYM archives for distribution
  9. Log Collection - Gathers container logs from temporary test directories and uploads them for debugging
jobs:
  buildAndTest:
    runs-on: [self-hosted, macos, tahoe, ARM64]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7
        with:
          fetch-depth: 0

      - name: Check formatting
        run: |
          ./scripts/install-hawkeye.sh
          make fmt
          if ! git diff --quiet -- . ; then
            echo "❌ Formatting required"
            false
          fi

      - name: Set build configuration
        env:
          RELEASE: ${{ inputs.release }}
        run: |
          echo "BUILD_CONFIGURATION=debug" >> $GITHUB_ENV
          if [[ "${RELEASE}" == "true" ]]; then
            echo "BUILD_CONFIGURATION=release" >> $GITHUB_ENV
          fi

      - name: Make the container project and docs
        run: |
          make container dsym docs
          tar cfz _site.tgz _site

Signature Verification and Security

Before compilation begins, the PR workflow enforces cryptographic signing requirements through a dedicated verification job. A Bash script queries the GitHub API using the gh CLI to enumerate commits in the pull request, inspecting the verification.verified field for each entry. If any commit lacks a valid signature, the script exits with an error, preventing unsigned code from entering the build pipeline.

Release Publishing Process

When a maintainer pushes a semantic version tag, the release workflow automatically prepares distribution assets. The process generates a draft release containing the container-installer-unsigned.pkg installer and compressed archives, allowing maintainers to review release notes and assets before publication. The draft status ensures automated tooling does not immediately publicize potentially incomplete releases.

Summary

  • The pipeline uses three entry-point workflows (pr-build.yml, merge-build.yml, release.yml) that delegate to a shared .github/workflows/common.yml
  • All builds execute on self-hosted macOS ARM64 runners ([self-hosted, macos, tahoe, ARM64]) for native Apple Silicon compatibility
  • Mandatory commit signature verification prevents unsigned code from merging via the GitHub API verification check
  • The Makefile drives build tasks including make fmt, make protos, make container, and make test
  • Automated drafting of GitHub releases occurs when version tags are pushed, producing .pkg and .zip artifacts

Frequently Asked Questions

What triggers the CI/CD pipeline in apple/container?

The pipeline triggers on three distinct events: pull request activity (opened, reopened, or synchronized), pushes to main or release/* branches, and pushes of version tags matching semantic versioning patterns. Each event type routes to a specific workflow file optimized for that validation scenario.

Why does apple/container use self-hosted runners instead of GitHub-hosted runners?

The workflow specifies runs-on: [self-hosted, macos, tahoe, ARM64] to ensure builds execute on dedicated Apple Silicon hardware with specific kernel extension capabilities and environment configurations required for testing container functionality on macOS.

How does the pipeline enforce commit signing requirements?

The PR build workflow executes a Bash script that queries the GitHub API for all commits in the pull request, inspecting the verification.verified field. If any commit lacks a valid cryptographic signature, the workflow fails immediately before reaching build or test stages.

What build configurations are supported?

The pipeline supports debug and release configurations controlled by the release input parameter passed to common.yml. Debug builds execute during standard PR validation, while release builds produce optimized binaries, installer packages, and draft GitHub releases.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →