From 9e6e59b379cd97694b4cdc5f30d48e98e02862e9 Mon Sep 17 00:00:00 2001 From: Fedor Kororkov Date: Thu, 16 Jul 2026 21:32:18 -0400 Subject: [PATCH] [codex] Publish Tart to openai/homebrew-tools (#1277) * Publish Tart to openai/homebrew-tools * Write Tart formula under Formula directory * Use macOS 26 runners * docs: install Tart tools from OpenAI tap * Add required GitHub Actions test check * Fix hosted tests and notarization credentials --- .ci/build-release.sh | 24 ++++++ .ci/create-pkg.sh | 2 +- .ci/set-version.sh | 12 ++- .ci/sign-release.sh | 14 ++++ .cirrus.yml | 85 --------------------- .github/workflows/build.yml | 4 +- .github/workflows/ci.yml | 37 ++++++++++ .github/workflows/release.yml | 106 +++++++++++++++++++++++++++ .goreleaser.yml | 23 +++--- README.md | 2 +- Sources/tart/CI/CI.swift | 2 +- Tests/TartTests/LayerizerTests.swift | 2 +- Tests/TartTests/RegistryTests.swift | 2 +- docs/orchard/deploying-workers.md | 2 +- docs/orchard/quick-start.md | 2 +- docs/orchard/using-orchard-cli.md | 2 +- docs/quick-start.md | 2 +- 17 files changed, 214 insertions(+), 109 deletions(-) create mode 100755 .ci/build-release.sh create mode 100755 .ci/sign-release.sh create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml diff --git a/.ci/build-release.sh b/.ci/build-release.sh new file mode 100755 index 0000000..43d233b --- /dev/null +++ b/.ci/build-release.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -eu + +ARCH="$1" +SCRATCH_PATH=".build/$ARCH" +OUTPUT_PATH=".build/prebuilt/$ARCH" + +swift build \ + --build-system swiftbuild \ + --scratch-path "$SCRATCH_PATH" \ + --arch "$ARCH" \ + --configuration release \ + --product tart + +BIN_PATH=$(swift build \ + --build-system swiftbuild \ + --scratch-path "$SCRATCH_PATH" \ + --arch "$ARCH" \ + --configuration release \ + --show-bin-path) + +mkdir -p "$OUTPUT_PATH" +cp "$BIN_PATH/tart" "$OUTPUT_PATH/tart" diff --git a/.ci/create-pkg.sh b/.ci/create-pkg.sh index 46cd0a4..ec7abad 100755 --- a/.ci/create-pkg.sh +++ b/.ci/create-pkg.sh @@ -2,7 +2,7 @@ set -e -export VERSION="${CIRRUS_TAG:-0}" +export VERSION="${VERSION:-0}" mkdir -p .ci/pkg/ cp .build/arm64-apple-macosx/release/tart .ci/pkg/tart diff --git a/.ci/set-version.sh b/.ci/set-version.sh index d886191..32b4492 100755 --- a/.ci/set-version.sh +++ b/.ci/set-version.sh @@ -1,7 +1,11 @@ #!/bin/sh -TMPFILE=$(mktemp) -envsubst < Sources/tart/CI/CI.swift > $TMPFILE -mv $TMPFILE Sources/tart/CI/CI.swift +set -e -/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string ${CIRRUS_TAG}" Resources/Info.plist +: "${VERSION:?VERSION must be set}" + +TMPFILE=$(mktemp) +perl -pe 's/\$\{VERSION\}/$ENV{VERSION}/g' Sources/tart/CI/CI.swift > "$TMPFILE" +mv "$TMPFILE" Sources/tart/CI/CI.swift + +/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string ${VERSION}" Resources/Info.plist diff --git a/.ci/sign-release.sh b/.ci/sign-release.sh new file mode 100755 index 0000000..b7939b7 --- /dev/null +++ b/.ci/sign-release.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eu + +if [ "${TART_RELEASE_SNAPSHOT:-false}" = "true" ]; then + codesign \ + --force \ + --deep \ + --sign - \ + --entitlements Resources/tart-dev.entitlements \ + dist/tart_darwin_all/tart.app +else + gon gon.hcl +fi diff --git a/.cirrus.yml b/.cirrus.yml index 7cc71ca..2e1f865 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -63,91 +63,6 @@ task: 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' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfd126b..315658f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ permissions: jobs: build_cached: name: Build tart (cached) - runs-on: ghcr.io/cirruslabs/macos-runner:tahoe + runs-on: macos-26 timeout-minutes: 30 steps: - uses: actions/checkout@v5 @@ -29,7 +29,7 @@ jobs: build_no_cache: name: Build tart (no cache) - runs-on: ghcr.io/cirruslabs/macos-runner:tahoe + runs-on: macos-26 timeout-minutes: 30 steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4a0c150 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + merge_group: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +jobs: + test: + name: Test + runs-on: macos-26 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: integration-tests/go.mod + cache-dependency-path: integration-tests/go.sum + - name: Build + run: swift build --build-system swiftbuild + - name: Run unit tests + run: | + export PATH="$PATH:/usr/sbin" + swift test --build-system swiftbuild + # The Python suite boots Tart VMs, but hosted ARM macOS runners do not support nested virtualization. + - name: Run OpenTelemetry integration tests + run: | + bin_path="$(swift build --build-system swiftbuild --show-bin-path)" + codesign --sign - --entitlements Resources/tart-dev.entitlements --force "$bin_path/tart" + cd integration-tests + PATH="$bin_path:$PATH" go test -v ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1a5a572 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,106 @@ +name: Release + +on: + push: + tags: + - "*" + workflow_dispatch: + +permissions: + contents: read + +jobs: + release: + if: github.event_name == 'push' && github.repository == 'openai/tart' + name: Release + runs-on: macos-26 + environment: publish + timeout-minutes: 90 + permissions: + contents: read + env: + VERSION: ${{ github.ref_name }} + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + fetch-depth: 0 + persist-credentials: false + - name: Import signing certificate + env: + KEYCHAIN_PASSWORD: temporary-password + MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} + P12_PASSWORD: password101 + 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 "$P12_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" + - name: Install gon + run: brew install mitchellh/gon/gon + - name: Create release app token for this repo + id: app-token + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 + with: + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + permission-contents: write + - name: Create release app token for homebrew-tools + id: tap-token + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 + with: + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + owner: openai + repositories: homebrew-tools + permission-contents: write + permission-pull-requests: write + - name: Release + uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7 + with: + distribution: goreleaser-pro + version: "~> v2" + args: release --clean + env: + AC_PASSWORD: ${{ secrets.AC_PASSWORD }} + GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + HOMEBREW_TAP_GITHUB_TOKEN: ${{ steps.tap-token.outputs.token }} + + snapshot: + if: github.event_name == 'workflow_dispatch' + name: Release (Dry Run) + runs-on: macos-26 + timeout-minutes: 90 + permissions: + contents: read + env: + TART_RELEASE_SNAPSHOT: "true" + VERSION: snapshot + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + fetch-depth: 0 + persist-credentials: false + - name: Build snapshot + uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7 + with: + distribution: goreleaser-pro + version: "~> v2" + args: release --skip=publish --snapshot --clean + - name: Upload snapshot artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: tart-snapshot + path: dist/* diff --git a/.goreleaser.yml b/.goreleaser.yml index 43b9044..63bb4ad 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -5,8 +5,8 @@ project_name: tart before: hooks: - .ci/set-version.sh - - swift build --arch arm64 --configuration release --product tart - - swift build --arch x86_64 --configuration release --product tart + - sh .ci/build-release.sh arm64 + - sh .ci/build-release.sh x86_64 builds: - id: tart @@ -19,7 +19,7 @@ builds: - amd64 binary: tart.app/Contents/MacOS/tart prebuilt: - path: '.build/{{- if eq .Arch "arm64" }}arm64{{- else }}x86_64{{ end }}-apple-macosx/release/tart' + path: '.build/prebuilt/{{- if eq .Arch "arm64" }}arm64{{- else }}x86_64{{ end }}/tart' universal_binaries: - name_template: tart.app/Contents/MacOS/tart @@ -30,7 +30,7 @@ universal_binaries: - cp Resources/embedded.provisionprofile dist/tart_darwin_all/tart.app/Contents/ - cp Resources/Info.plist dist/tart_darwin_all/tart.app/Contents/ - cp "Resources/actool/UPW Tart.icns" "Resources/actool/Assets.car" dist/tart_darwin_all/tart.app/Contents/Resources/ - - gon gon.hcl + - .ci/sign-release.sh archives: - name_template: "{{ .ProjectName }}" @@ -52,9 +52,14 @@ release: brews: - name: tart + directory: Formula repository: - owner: cirruslabs - name: homebrew-cli + owner: openai + name: homebrew-tools + token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" + branch: "tart-{{ .Version }}" + pull_request: + enabled: true caveats: | Tart has been installed. You might want to reduce the default DHCP lease time from 86,400 to 600 seconds to avoid DHCP shortage when running lots of VMs daily: @@ -62,12 +67,12 @@ 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-ALv2 description: Run macOS and Linux VMs on Apple Hardware skip_upload: auto dependencies: - - "cirruslabs/cli/softnet" + - "openai/tools/softnet" install: | libexec.install Dir["*"] bin.write_exec_script "#{libexec}/tart.app/Contents/MacOS/tart" diff --git a/README.md b/README.md index 67cbbd9..951d8f3 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Many companies are using Tart in their internal setups. Here are just a few of t Try running a Tart VM on your Apple Silicon device running macOS 13.0 (Ventura) or later (will download a 25 GB image): ```bash -brew install cirruslabs/cli/tart +brew install openai/tools/tart tart clone ghcr.io/cirruslabs/macos-tahoe-base:latest tahoe-base tart run tahoe-base ``` 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/Tests/TartTests/LayerizerTests.swift b/Tests/TartTests/LayerizerTests.swift index ca22abd..4ce4b00 100644 --- a/Tests/TartTests/LayerizerTests.swift +++ b/Tests/TartTests/LayerizerTests.swift @@ -14,7 +14,7 @@ final class LayerizerTests: XCTestCase { do { registryRunner = try await RegistryRunner() } catch { - try XCTSkip("Registry is unavailable: \(error)") + throw XCTSkip("Registry is unavailable: \(error)") } } diff --git a/Tests/TartTests/RegistryTests.swift b/Tests/TartTests/RegistryTests.swift index b66bb6b..4cb16e5 100644 --- a/Tests/TartTests/RegistryTests.swift +++ b/Tests/TartTests/RegistryTests.swift @@ -10,7 +10,7 @@ final class RegistryTests: XCTestCase { do { registryRunner = try await RegistryRunner() } catch { - try XCTSkip("Registry is unavailable: \(error)") + throw XCTSkip("Registry is unavailable: \(error)") } } diff --git a/docs/orchard/deploying-workers.md b/docs/orchard/deploying-workers.md index 5d5fa84..74fa9ea 100644 --- a/docs/orchard/deploying-workers.md +++ b/docs/orchard/deploying-workers.md @@ -31,7 +31,7 @@ In this deployment method, we'll create a new job definition file for the launch To begin, first install Orchard: ```shell -brew install cirruslabs/cli/orchard +brew install openai/tools/orchard ``` Ensure that the following command: diff --git a/docs/orchard/quick-start.md b/docs/orchard/quick-start.md index 7d02c47..cc8c232 100644 --- a/docs/orchard/quick-start.md +++ b/docs/orchard/quick-start.md @@ -9,7 +9,7 @@ or [through the API](integration-guide.md). The easiest way to start is to run Orchard in local development mode: ```shell -brew install cirruslabs/cli/orchard +brew install openai/tools/orchard orchard dev ``` diff --git a/docs/orchard/using-orchard-cli.md b/docs/orchard/using-orchard-cli.md index 8f2a8ce..c3a1d63 100644 --- a/docs/orchard/using-orchard-cli.md +++ b/docs/orchard/using-orchard-cli.md @@ -3,7 +3,7 @@ The easiest way to install Orchard CLI is through the [Homebrew](https://brew.sh/): ```shell -brew install cirruslabs/cli/orchard +brew install openai/tools/orchard ``` Binaries and packages for other architectures can be found in [GitHub Releases](https://github.com/openai/orchard/releases). diff --git a/docs/quick-start.md b/docs/quick-start.md index ac33666..eeed28a 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -8,7 +8,7 @@ description: Install Tart and run your first virtual machine on Apple Silicon in Try running a Tart VM on your Apple Silicon device running macOS 13.0 (Ventura) or later (will download a 25 GB image): ```bash -brew install cirruslabs/cli/tart +brew install openai/tools/tart tart clone ghcr.io/cirruslabs/macos-tahoe-base:latest tahoe-base tart run tahoe-base ```