From 4df49fc0fcc8c317aa4719242fe1bd7c186f0c6b Mon Sep 17 00:00:00 2001 From: Fedor Korotkov Date: Fri, 5 Jun 2026 10:12:53 -0700 Subject: [PATCH] Migrate CI to GitHub Actions --- .ci/set-version.sh | 2 +- .cirrus.yml | 163 --------------------------- .github/workflows/build.yml | 37 ------ .github/workflows/ci.yml | 92 +++++++++++++++ .github/workflows/docs.yml | 40 +++++++ .github/workflows/release.yml | 70 ++++++++++++ .goreleaser.yml | 4 +- Sources/tart/CI/CI.swift | 2 +- docs/orchard/deploying-controller.md | 66 +---------- 9 files changed, 209 insertions(+), 267 deletions(-) delete mode 100644 .cirrus.yml delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/release.yml diff --git a/.ci/set-version.sh b/.ci/set-version.sh index d886191..efc6b0d 100755 --- a/.ci/set-version.sh +++ b/.ci/set-version.sh @@ -4,4 +4,4 @@ TMPFILE=$(mktemp) envsubst < Sources/tart/CI/CI.swift > $TMPFILE mv $TMPFILE Sources/tart/CI/CI.swift -/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string ${CIRRUS_TAG}" Resources/Info.plist +/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string ${VERSION}" Resources/Info.plist diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 7cc71ca..0000000 --- a/.cirrus.yml +++ /dev/null @@ -1,163 +0,0 @@ -use_compute_credits: true - -task: - name: Test - alias: test - persistent_worker: - labels: - name: dev-mini - resources: - tart-vms: 1 - build_script: - - swift build - test_script: - # Add /usr/sbin to PATH, otherwise testDiskutilInfo() fails to locate "diskutil" - - export PATH=$PATH:/usr/sbin - - swift test - integration_test_script: - - codesign --sign - --entitlements Resources/tart-dev.entitlements --force .build/debug/tart - - export PATH=$(pwd)/.build/arm64-apple-macosx/debug:$PATH - # Run integration tests - - cd integration-tests - - python3 -m venv --symlinks venv - - source venv/bin/activate - - pip install -r requirements.txt - - pytest --verbose --junit-xml=pytest-junit.xml - - go test -v ./... - pytest_junit_result_artifacts: - path: "integration-tests/pytest-junit.xml" - format: junit - -task: - name: Markdown Lint - only_if: $CIRRUS_BRANCH != 'gh-pages' && changesInclude('**.md') - container: - image: node:latest - install_script: npm install -g markdownlint-cli - lint_script: markdownlint --config=docs/.markdownlint.yml docs/ - -task: - name: Lint - alias: lint - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:tahoe - lint_script: - - swift package plugin --allow-writing-to-package-directory swiftformat --cache ignore --lint --report swiftformat.json . - always: - swiftformat_report_artifacts: - path: swiftformat.json - format: swiftformat - -task: - only_if: $CIRRUS_TAG == '' - env: - matrix: - BUILD_ARCH: arm64 - BUILD_ARCH: x86_64 - name: Build ($BUILD_ARCH) - alias: build - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:tahoe - build_script: swift build --arch $BUILD_ARCH --product tart - sign_script: codesign --sign - --entitlements Resources/tart-dev.entitlements --force .build/$BUILD_ARCH-apple-macosx/debug/tart - binary_artifacts: - path: .build/$BUILD_ARCH-apple-macosx/debug/tart - -task: - only_if: $CIRRUS_TAG == '' && ($CIRRUS_USER_PERMISSION == 'write' || $CIRRUS_USER_PERMISSION == 'admin') - name: Release (Dry Run) - depends_on: - - lint - - build - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:tahoe - env: - MACOS_CERTIFICATE: ENCRYPTED[552b9d275d1c2bdbc1bff778b104a8f9a53cbd0d59344d4b7f6d0ca3c811a5cefb97bef9ba0ef31c219cb07bdacdd2c2] - AC_PASSWORD: ENCRYPTED[4a761023e7e06fe2eb350c8b6e8e7ca961af193cb9ba47605f25f1d353abc3142606f412e405be48fd897a78787ea8c2] - GITHUB_TOKEN: ENCRYPTED[!98ace8259c6024da912c14d5a3c5c6aac186890a8d4819fad78f3e0c41a4e0cd3a2537dd6e91493952fb056fa434be7c!] - GORELEASER_KEY: ENCRYPTED[!9b80b6ef684ceaf40edd4c7af93014ee156c8aba7e6e5795f41c482729887b5c31f36b651491d790f1f668670888d9fd!] - setup_script: - - cd $HOME - - echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12 - - security create-keychain -p password101 build.keychain - - security default-keychain -s build.keychain - - security unlock-keychain -p password101 build.keychain - - security import certificate.p12 -k build.keychain -P password101 -T /usr/bin/codesign -T /usr/bin/pkgbuild - - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k password101 build.keychain - - xcrun notarytool store-credentials "notarytool" --apple-id "hello@cirruslabs.org" --team-id "9M2P8L4D89" --password $AC_PASSWORD - install_script: - - brew install go - - brew install mitchellh/gon/gon - - brew install --cask goreleaser/tap/goreleaser-pro - info_script: - - security find-identity -v - - xcodebuild -version - - swift -version - goreleaser_script: goreleaser release --skip=publish --snapshot --clean - always: - dist_artifacts: - path: "dist/*" - -task: - name: Release - only_if: $CIRRUS_TAG != '' - depends_on: - - lint - - build - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:tahoe - env: - MACOS_CERTIFICATE: ENCRYPTED[552b9d275d1c2bdbc1bff778b104a8f9a53cbd0d59344d4b7f6d0ca3c811a5cefb97bef9ba0ef31c219cb07bdacdd2c2] - AC_PASSWORD: ENCRYPTED[4a761023e7e06fe2eb350c8b6e8e7ca961af193cb9ba47605f25f1d353abc3142606f412e405be48fd897a78787ea8c2] - GITHUB_TOKEN: ENCRYPTED[!98ace8259c6024da912c14d5a3c5c6aac186890a8d4819fad78f3e0c41a4e0cd3a2537dd6e91493952fb056fa434be7c!] - GORELEASER_KEY: ENCRYPTED[!9b80b6ef684ceaf40edd4c7af93014ee156c8aba7e6e5795f41c482729887b5c31f36b651491d790f1f668670888d9fd!] - SENTRY_ORG: cirrus-labs - SENTRY_PROJECT: persistent-workers - SENTRY_AUTH_TOKEN: ENCRYPTED[!9eaf2875d51b113e2f68598441ff8e6b2e53242e48fcb93633bd75a373fbe2e7caa900d837cc92f0b142b65579731644!] - setup_script: - - cd $HOME - - echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12 - - security create-keychain -p password101 build.keychain - - security default-keychain -s build.keychain - - security unlock-keychain -p password101 build.keychain - - security import certificate.p12 -k build.keychain -P password101 -T /usr/bin/codesign -T /usr/bin/pkgbuild - - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k password101 build.keychain - - xcrun notarytool store-credentials "notarytool" --apple-id "hello@cirruslabs.org" --team-id "9M2P8L4D89" --password $AC_PASSWORD - install_script: - - brew install go getsentry/tools/sentry-cli - - brew install mitchellh/gon/gon - - brew install --cask goreleaser/tap/goreleaser-pro - info_script: - - security find-identity -v - - xcodebuild -version - - swift -version - release_script: goreleaser - upload_sentry_debug_files_script: - - cd .build/arm64-apple-macosx/release/ - # Generate and upload symbols - - dsymutil tart - - sentry-cli debug-files upload tart.dSYM/ - - SENTRY_PROJECT=tart sentry-cli debug-files upload tart.dSYM/ - # Bundle and upload sources - - sentry-cli debug-files bundle-sources tart.dSYM - - sentry-cli debug-files upload tart.src.zip - - SENTRY_PROJECT=tart sentry-cli debug-files upload tart.src.zip - create_sentry_release_script: - - export SENTRY_RELEASE="tart@$CIRRUS_TAG" - - sentry-cli releases new $SENTRY_RELEASE - - sentry-cli releases set-commits $SENTRY_RELEASE --auto - - sentry-cli releases finalize $SENTRY_RELEASE - -task: - name: Deploy Documentation - only_if: $CIRRUS_BRANCH == 'main' - container: - image: ghcr.io/squidfunk/mkdocs-material:latest - registry_config: ENCRYPTED[!cf1a0f25325aa75bad3ce6ebc890bc53eb0044c02efa70d8cefb83ba9766275a994b4831706c52630a0692b2fa9cfb9e!] - env: - DEPLOY_TOKEN: ENCRYPTED[!45ed45666558902ed1c2400add734ec063103bec31841847e8c8764802fca229bfa6d85c690e16ad159e047574b48793!] - deploy_script: - - git config --global user.name "Cirrus CI" - - git config --global user.name "hello@cirruslabs.org" - - git remote set-url origin https://$DEPLOY_TOKEN@github.com/cirruslabs/tart/ - - mkdocs --verbose gh-deploy --force --remote-branch gh-pages diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index cfd126b..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Build - -on: - workflow_dispatch: - -permissions: - contents: read - -jobs: - build_cached: - name: Build tart (cached) - runs-on: ghcr.io/cirruslabs/macos-runner:tahoe - timeout-minutes: 30 - steps: - - uses: actions/checkout@v5 - - name: Build - run: | - export COMPILATION_CACHE_ENABLE_CACHING=YES - export COMPILATION_CACHE_REMOTE_SERVICE_PATH="$HOME/.cirruslabs/omni-cache.sock" - export COMPILATION_CACHE_ENABLE_PLUGIN=YES - export COMPILATION_CACHE_ENABLE_INTEGRATED_QUERIES=YES - export COMPILATION_CACHE_ENABLE_DETACHED_KEY_QUERIES=YES - export SWIFT_ENABLE_COMPILE_CACHE=YES - export SWIFT_ENABLE_EXPLICIT_MODULES=YES - export SWIFT_USE_INTEGRATED_DRIVER=YES - export CLANG_ENABLE_COMPILE_CACHE=YES - export CLANG_ENABLE_MODULES=YES - swift build --build-system swiftbuild --product tart - - build_no_cache: - name: Build tart (no cache) - runs-on: ghcr.io/cirruslabs/macos-runner:tahoe - timeout-minutes: 30 - steps: - - uses: actions/checkout@v5 - - name: Build - run: swift build --build-system swiftbuild --product tart diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..63849a5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI + +on: + merge_group: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +jobs: + test: + name: Test + runs-on: ghcr.io/cirruslabs/macos-runner:tahoe + timeout-minutes: 60 + steps: + - uses: actions/checkout@v6 + - name: Build + run: swift build + - name: Run unit tests + run: | + export PATH="$PATH:/usr/sbin" + swift test + - name: Run integration tests + run: | + codesign --sign - --entitlements Resources/tart-dev.entitlements --force .build/debug/tart + export PATH="$PWD/.build/arm64-apple-macosx/debug:$PATH" + cd integration-tests + python3 -m venv --symlinks venv + source venv/bin/activate + pip install -r requirements.txt + pytest --verbose --junit-xml=pytest-junit.xml + go test -v ./... + - name: Upload integration test results + if: always() + uses: actions/upload-artifact@v6 + with: + name: pytest-junit + path: integration-tests/pytest-junit.xml + if-no-files-found: ignore + + lint: + name: Lint + runs-on: ghcr.io/cirruslabs/macos-runner:tahoe + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + - name: Run SwiftFormat + run: swift package plugin --allow-writing-to-package-directory swiftformat --cache ignore --lint --report swiftformat.json . + - name: Upload SwiftFormat report + if: always() + uses: actions/upload-artifact@v6 + with: + name: swiftformat + path: swiftformat.json + if-no-files-found: ignore + + markdown-lint: + name: Markdown Lint + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + - name: Install markdownlint + run: npm install --global markdownlint-cli + - name: Lint documentation + run: markdownlint --config docs/.markdownlint.yml docs/ + + build: + name: Build (${{ matrix.arch }}) + runs-on: ghcr.io/cirruslabs/macos-runner:tahoe + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + arch: + - arm64 + - x86_64 + steps: + - uses: actions/checkout@v6 + - name: Build + run: swift build --arch "${{ matrix.arch }}" --product tart + - name: Sign + run: codesign --sign - --entitlements Resources/tart-dev.entitlements --force ".build/${{ matrix.arch }}-apple-macosx/debug/tart" + - name: Upload binary + uses: actions/upload-artifact@v6 + with: + name: tart-${{ matrix.arch }} + path: .build/${{ matrix.arch }}-apple-macosx/debug/tart diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..3f8df42 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,40 @@ +name: Documentation + +on: + push: + branches: + - main + paths: + - docs/** + - mkdocs.yml + - .github/workflows/docs.yml + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: documentation + cancel-in-progress: true + +jobs: + deploy: + name: Deploy Documentation + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Deploy + run: | + docker run --rm \ + --volume "$PWD:/docs" \ + --entrypoint sh \ + ghcr.io/squidfunk/mkdocs-material:latest \ + -c ' + git config --global --add safe.directory /docs + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + mkdocs gh-deploy --force --remote-branch gh-pages + ' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..eb5d5b9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,70 @@ +name: Release + +on: + push: + tags: + - "*" + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + name: ${{ github.ref_type == 'tag' && 'Release' || 'Release (Dry Run)' }} + runs-on: ghcr.io/cirruslabs/macos-runner:tahoe + timeout-minutes: 90 + env: + AC_PASSWORD: ${{ secrets.AC_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} + MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} + VERSION: ${{ github.ref_type == 'tag' && github.ref_name || 'snapshot' }} + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Import signing certificate + env: + KEYCHAIN_PASSWORD: temporary-password + run: | + echo "$MACOS_CERTIFICATE" | base64 --decode > "$RUNNER_TEMP/certificate.p12" + security create-keychain -p "$KEYCHAIN_PASSWORD" "$RUNNER_TEMP/build.keychain" + security default-keychain -s "$RUNNER_TEMP/build.keychain" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$RUNNER_TEMP/build.keychain" + security import "$RUNNER_TEMP/certificate.p12" \ + -k "$RUNNER_TEMP/build.keychain" \ + -P "$KEYCHAIN_PASSWORD" \ + -T /usr/bin/codesign \ + -T /usr/bin/pkgbuild + security set-key-partition-list \ + -S apple-tool:,apple:,codesign: \ + -s \ + -k "$KEYCHAIN_PASSWORD" \ + "$RUNNER_TEMP/build.keychain" + xcrun notarytool store-credentials notarytool \ + --apple-id hello@cirruslabs.org \ + --team-id 9M2P8L4D89 \ + --password "$AC_PASSWORD" + - name: Install gon + run: brew install mitchellh/gon/gon + - name: Release + if: github.ref_type == 'tag' + uses: goreleaser/goreleaser-action@v7 + with: + distribution: goreleaser-pro + version: "~> v2" + args: release --clean + - name: Release dry run + if: github.ref_type != 'tag' + uses: goreleaser/goreleaser-action@v7 + with: + distribution: goreleaser-pro + version: "~> v2" + args: release --skip=publish --snapshot --clean + - name: Upload dry-run artifacts + if: github.ref_type != 'tag' + uses: actions/upload-artifact@v6 + with: + name: tart-snapshot + path: dist/* diff --git a/.goreleaser.yml b/.goreleaser.yml index 18f4232..feb4323 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -62,8 +62,8 @@ brews: sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.InternetSharing.default.plist bootpd -dict DHCPLeaseTimeSecs -int 600 See https://tart.run/faq/#changing-the-default-dhcp-lease-time for more details. - homepage: https://github.com/cirruslabs/tart - license: "Fair Source" + homepage: https://github.com/openai/tart + license: FSL-1.1-Apache-2.0 description: Run macOS and Linux VMs on Apple Hardware skip_upload: auto dependencies: diff --git a/Sources/tart/CI/CI.swift b/Sources/tart/CI/CI.swift index f0cf9f5..0e3bb28 100644 --- a/Sources/tart/CI/CI.swift +++ b/Sources/tart/CI/CI.swift @@ -1,5 +1,5 @@ struct CI { - private static let rawVersion = "${CIRRUS_TAG}" + private static let rawVersion = "${VERSION}" static var version: String { rawVersion.expanded() ? rawVersion : "SNAPSHOT" diff --git a/docs/orchard/deploying-controller.md b/docs/orchard/deploying-controller.md index e1f0b6b..c8f2a7f 100644 --- a/docs/orchard/deploying-controller.md +++ b/docs/orchard/deploying-controller.md @@ -2,7 +2,7 @@ Compared to Worker, which can only be deployed on a macOS machine, Controller can be also deployed on Linux. -In fact, we've made a [container image](https://github.com/orgs/cirruslabs/packages/container/package/orchard) to ease deploying the Controller in container-native environments such as Kubernetes. +In fact, we've made a [container image](https://github.com/openai/orchard/pkgs/container/orchard) to ease deploying the Controller in container-native environments such as Kubernetes. Another thing to keep in mind that Orchard API is secured by default: all requests must be authenticated with the credentials of a service account. When you first run Orchard Controller, a `bootstrap-admin` service account will be created automatically and credentials will be printed to the standard output. @@ -88,7 +88,7 @@ gcloud compute instances create-with-container orchard-controller \ --image-project cos-cloud \ --tags=https-server \ --address=$ORCHARD_IP \ - --container-image=ghcr.io/cirruslabs/orchard:latest \ + --container-image=ghcr.io/openai/orchard:latest \ --container-env=PORT=443 \ --container-env=ORCHARD_BOOTSTRAP_ADMIN_TOKEN=$ORCHARD_BOOTSTRAP_ADMIN_TOKEN \ --container-mount-host-path=host-path=/home/orchard-data,mode=rw,mount-path=/data @@ -149,7 +149,7 @@ spec: spec: containers: - name: orchard-controller - image: ghcr.io/cirruslabs/orchard:latest + image: ghcr.io/openai/orchard:latest volumeMounts: - mountPath: /data name: orchard-controller @@ -180,63 +180,3 @@ You can further allocate a static IP address and use it by adding annotations to * on Google's GKE: * on Amazon's EKS: - -### systemd service on Debian-based distributions - -This should work for most Debian-based distributions like Debian, Ubuntu, etc. - -Firstly, make sure that the APT transport for downloading packages via HTTPS and common X.509 certificates are installed: - -```shell -sudo apt-get update && sudo apt-get -y install apt-transport-https ca-certificates -``` - -Then, add the Cirrus Labs repository: - -```shell -echo "deb [trusted=yes] https://apt.fury.io/cirruslabs/ /" | sudo tee /etc/apt/sources.list.d/cirruslabs.list -``` - -Update the package index files and install the Orchard Controller: - -```shell -sudo apt-get update && sudo apt-get -y install orchard-controller -``` - -Finally, enable and start the Orchard Controller systemd service: - -```shell -sudo systemctl enable orchard-controller -sudo systemctl start orchard-controller -``` - -The bootstrap credentials will be printed to the standard output. You can inspect them by running `sudo systemctl status orhcard-controller` or `journalctl -u orchard-controller`. - -### systemd service on RPM-based distributions - -This should work for most RPM-based distributions like Fedora, CentOS, etc. - -First, create a `/etc/yum.repos.d/cirruslabs.repo` file with the following contents: - -```ini -[cirruslabs] -name=Cirrus Labs Repo -baseurl=https://yum.fury.io/cirruslabs/ -enabled=1 -gpgcheck=0 -``` - -Then, install the Orchard Controller: - -```shell -sudo yum -y install orchard-controller -``` - -Finally, enable and start the Orchard Controller systemd service: - -```shell -systemctl enable orchard-controller -systemctl start orchard-controller -``` - -The bootstrap credentials will be printed to the standard output. You can inspect them by running `sudo systemctl status orhcard-controller` or `journalctl -u orchard-controller`.