diff --git a/.github/actions/install-node-dependencies/action.yml b/.github/actions/install-node-dependencies/action.yml index 1c5e11129b5..d5f119879b7 100644 --- a/.github/actions/install-node-dependencies/action.yml +++ b/.github/actions/install-node-dependencies/action.yml @@ -67,6 +67,32 @@ outputs: runs: using: composite steps: + # The image resets HOME during login; shell fixtures intentionally use temporary homes. + - name: Preserve explicit login-shell homes on Blacksmith + if: runner.os == 'Linux' && startsWith(runner.name, 'blacksmith-') && job.container.id == '' + shell: bash + run: | + sudo python3 - <<'PYTHON' + from pathlib import Path + profile = Path('/etc/profile.d/blacksmith.sh') + if profile.exists(): + original = profile.read_text() + updated = original.replace('export HOME="$RUNNER_HOME"', 'export HOME="${HOME:-$RUNNER_HOME}"') + if updated != original: + profile.write_text(updated) + PYTHON + fixture_home="$(mktemp -d)" + trap 'rm -rf "$fixture_home"' EXIT + printf 'export ORCA_CI_PROFILE_LOADED=1\n' > "$fixture_home/.bash_profile" + HOME="$fixture_home" ORCA_CI_FIXTURE_HOME="$fixture_home" /bin/bash -lc ' + test "$HOME" = "$ORCA_CI_FIXTURE_HOME" && test "$ORCA_CI_PROFILE_LOADED" = 1 + ' || { + echo '::error::Runner login profile overrides fixture HOME' + grep -nH 'HOME' /etc/profile /etc/profile.d/*.sh || true + HOME="$fixture_home" /bin/bash -lc 'printf "Observed HOME=%s\n" "$HOME"' + exit 1 + } + - name: Resolve pnpm store mode id: pnpm-store-mode if: >- diff --git a/.github/workflows/ci-cache-warmup-platform-jobs.yml b/.github/workflows/ci-cache-warmup-platform-jobs.yml index a2bb09b685b..5a333641e32 100644 --- a/.github/workflows/ci-cache-warmup-platform-jobs.yml +++ b/.github/workflows/ci-cache-warmup-platform-jobs.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - runner: [ubuntu-24.04-arm, blacksmith-8vcpu-ubuntu-2404] + runner: [blacksmith-4vcpu-ubuntu-2404-arm, blacksmith-8vcpu-ubuntu-2404] runs-on: ${{ matrix.runner }} timeout-minutes: 10 env: @@ -95,7 +95,7 @@ jobs: concurrency: group: ci-cache-warmup-linux-package-fixtures-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name != 'schedule' }} - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 10 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/ci-cache-warmup.yml b/.github/workflows/ci-cache-warmup.yml index f1d2f4423af..c0fbda2d823 100644 --- a/.github/workflows/ci-cache-warmup.yml +++ b/.github/workflows/ci-cache-warmup.yml @@ -68,7 +68,7 @@ jobs: concurrency: group: ci-cache-warmup-linux-x64-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name != 'schedule' }} - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 10 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/ci-runner-demand.yml b/.github/workflows/ci-runner-demand.yml index 966813a65e4..b64828369b5 100644 --- a/.github/workflows/ci-runner-demand.yml +++ b/.github/workflows/ci-runner-demand.yml @@ -15,7 +15,7 @@ concurrency: jobs: report: - runs-on: ubuntu-slim + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 15 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/ci-xterm-cache.yml b/.github/workflows/ci-xterm-cache.yml index 4527648a0c5..27a02178c69 100644 --- a/.github/workflows/ci-xterm-cache.yml +++ b/.github/workflows/ci-xterm-cache.yml @@ -23,7 +23,7 @@ env: jobs: seed: if: github.ref == 'refs/heads/main' - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm timeout-minutes: 10 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/cloud-verify.yml b/.github/workflows/cloud-verify.yml index 68318fb3269..5c8ff5e0341 100644 --- a/.github/workflows/cloud-verify.yml +++ b/.github/workflows/cloud-verify.yml @@ -34,7 +34,7 @@ jobs: security: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true name: Secret scan - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 steps: - uses: actions/checkout@v4 with: @@ -84,7 +84,7 @@ jobs: # database, and the service container costs ~13s of startup. build: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 steps: - uses: actions/checkout@v4 @@ -112,7 +112,7 @@ jobs: containers: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true name: Container security (${{ matrix.app }}) - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 strategy: fail-fast: false matrix: @@ -172,7 +172,7 @@ jobs: # `pnpm build` having run. test: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 services: postgres: image: postgres:16-alpine diff --git a/.github/workflows/computer-e2e.yml b/.github/workflows/computer-e2e.yml index fb95dcfc682..54d386e9c54 100644 --- a/.github/workflows/computer-e2e.yml +++ b/.github/workflows/computer-e2e.yml @@ -80,7 +80,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, windows-latest] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-22.04":"blacksmith-4vcpu-ubuntu-2204"}')[matrix.os] || matrix.os }} steps: - uses: actions/checkout@v6 with: @@ -150,7 +150,7 @@ jobs: # grants. Keep the real native build/owner-loss checks on every trigger instead. mac-native-owner-smoke: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true - runs-on: macos-15 + runs-on: blacksmith-6vcpu-macos-15 permissions: contents: read steps: @@ -178,7 +178,7 @@ jobs: linux: if: github.event_name != 'pull_request' - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 env: ORCA_COMPUTER_E2E: '1' ACCESSIBILITY_ENABLED: '1' diff --git a/.github/workflows/daily-mac-build.yml b/.github/workflows/daily-mac-build.yml index 010c610892b..3648edda1a9 100644 --- a/.github/workflows/daily-mac-build.yml +++ b/.github/workflows/daily-mac-build.yml @@ -73,7 +73,7 @@ jobs: # Why: the app and the orcad template it ships must come from one commit, so resolve main once. resolve-main: if: github.repository == 'stablyai/orca' - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 5 outputs: head_sha: ${{ steps.resolve.outputs.head_sha }} @@ -99,6 +99,7 @@ jobs: with: ref: ${{ needs.resolve-main.outputs.head_sha }} build_template: true + fast_runners: true build-daily-mac: needs: @@ -566,7 +567,7 @@ jobs: post-daily-e2e: needs: build-daily-mac if: ${{ needs.build-daily-mac.outputs.published == 'true' && needs.build-daily-mac.outputs.head_sha != '' }} - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404 permissions: actions: write steps: @@ -614,3 +615,4 @@ jobs: ref: ${{ needs.build-daily-mac.outputs.head_sha }} version: ${{ needs.build-daily-mac.outputs.version }} orcad_template: true + fast_release: true diff --git a/.github/workflows/dependency-security.yml b/.github/workflows/dependency-security.yml index a7efa4ef748..263220b9fb7 100644 --- a/.github/workflows/dependency-security.yml +++ b/.github/workflows/dependency-security.yml @@ -27,6 +27,10 @@ on: description: Exact release tag to audit using the workflow commit's tooling required: true type: string + runner: + description: Runner override for GitHub-hosted signing provenance. + type: string + default: blacksmith-4vcpu-ubuntu-2404 workflow_dispatch: permissions: @@ -42,7 +46,7 @@ env: jobs: javascript: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true - runs-on: ubuntu-latest + runs-on: ${{ inputs.runner || 'blacksmith-4vcpu-ubuntu-2404' }} timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -73,7 +77,7 @@ jobs: rust: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true - runs-on: ubuntu-latest + runs-on: ${{ inputs.runner || 'blacksmith-4vcpu-ubuntu-2404' }} timeout-minutes: 20 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/dev-channel-win-build.yml b/.github/workflows/dev-channel-win-build.yml index a94f80b1de1..3872161f7b4 100644 --- a/.github/workflows/dev-channel-win-build.yml +++ b/.github/workflows/dev-channel-win-build.yml @@ -62,7 +62,7 @@ on: fast_release: description: Use the faster unsigned-build runner outside signing provenance type: boolean - default: false + default: true javascript_source_sha: description: Restore this run's shared dev JavaScript instead of rebuilding it type: string @@ -95,6 +95,11 @@ on: required: true type: string + fast_release: + description: Use Blacksmith for unsigned Windows builds + type: boolean + default: true + permissions: contents: read diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 734dda24c09..161f5009e5a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -38,7 +38,7 @@ jobs: check: name: Build and test if: github.event_name == 'pull_request' && github.event.pull_request.draft != true - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 15 steps: - name: Checkout pull request @@ -80,7 +80,7 @@ jobs: if: >- github.repository == 'stablyai/orca' && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 5 outputs: deploy: ${{ steps.validate.outputs.deploy }} @@ -205,7 +205,7 @@ jobs: needs.release_gate.result == 'success' && needs.release_gate.outputs.deploy == 'true' needs: release_gate - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 15 environment: name: docs-production diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 553b8918e78..1ed90002865 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -68,7 +68,7 @@ jobs: build: name: build e2e app if: inputs.test_files == '' || github.event_name != 'pull_request' || inputs.needs_build - runs-on: ubuntu-latest + runs-on: blacksmith-8vcpu-ubuntu-2404 timeout-minutes: 15 env: ORCA_BACKGROUND_LAUNCH: '1' @@ -197,7 +197,7 @@ jobs: name: e2e ${{ matrix.shard_name }} needs: [build] if: inputs.test_files == '' - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 30 strategy: fail-fast: false @@ -324,7 +324,7 @@ jobs: name: changed e2e specs needs: [build] if: inputs.test_files != '' && (github.event_name != 'pull_request' || inputs.run_changed_e2e) - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 45 steps: @@ -424,7 +424,7 @@ jobs: ssh-browser-network-route: name: ssh browser network route if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts') - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -448,7 +448,7 @@ jobs: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/orcad-serve-mode-switch.spec.ts') || contains(inputs.test_files, 'tests/e2e/workspace-layout-oracle-headless.spec.ts') - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 45 env: ORCA_BACKGROUND_LAUNCH: '1' @@ -549,7 +549,7 @@ jobs: name: ssh on managed orcad (Docker ${{ matrix.shard }}) needs: [build] if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/ssh-orcad-') - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 60 strategy: fail-fast: false diff --git a/.github/workflows/hourly-mac-build.yml b/.github/workflows/hourly-mac-build.yml index b7f14d22ea2..0d415b83e13 100644 --- a/.github/workflows/hourly-mac-build.yml +++ b/.github/workflows/hourly-mac-build.yml @@ -63,7 +63,7 @@ jobs: # Avoid occupying the limited Mac pool when main has not moved. preflight: if: github.repository == 'stablyai/orca' - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 5 outputs: should_build: ${{ steps.freshness.outputs.should_build }} @@ -127,6 +127,7 @@ jobs: with: ref: ${{ needs.preflight.outputs.head_sha }} build_template: true + fast_runners: true build-hourly-mac: needs: @@ -529,3 +530,4 @@ jobs: ref: ${{ needs.build-hourly-mac.outputs.head_sha }} version: ${{ needs.build-hourly-mac.outputs.version }} orcad_template: true + fast_release: true diff --git a/.github/workflows/macos-updater-tests.yml b/.github/workflows/macos-updater-tests.yml index fca034a1561..9ef1180300d 100644 --- a/.github/workflows/macos-updater-tests.yml +++ b/.github/workflows/macos-updater-tests.yml @@ -29,7 +29,7 @@ concurrency: jobs: updater: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true - runs-on: macos-15 + runs-on: blacksmith-6vcpu-macos-15 timeout-minutes: 20 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index 226d848ec76..100f1fbcd78 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -107,7 +107,7 @@ jobs: # Why ARM: 209s of this job is Vitest and nothing here needs x86: no Android SDK, emulator, gradle, # Hermes or Watchman, no docker, and no artifacts. The Gemfile.lock lists the generic `ruby` # platform, so frozen bundler installs without an aarch64-linux entry. - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm env: # Why: an unfrozen bundler silently re-resolves when Gemfile.lock drifts @@ -262,7 +262,7 @@ jobs: ORCA_MOBILE_TYPECHECK_COMPILER: 'native' if: github.event_name == 'push' # Why ARM: the same pure-Node Vitest run `verify` makes on a pull request. - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm defaults: run: diff --git a/.github/workflows/node-next-compat.yml b/.github/workflows/node-next-compat.yml index fc9b9cedaf9..c66209614db 100644 --- a/.github/workflows/node-next-compat.yml +++ b/.github/workflows/node-next-compat.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: node: ['24', '26'] - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout diff --git a/.github/workflows/node-server-tests.yml b/.github/workflows/node-server-tests.yml index 8a9db669733..e94f80a50f7 100644 --- a/.github/workflows/node-server-tests.yml +++ b/.github/workflows/node-server-tests.yml @@ -28,9 +28,9 @@ on: type: boolean default: false fast_runners: - description: Use faster runners where the platform and architecture are available + description: Use Blacksmith where the platform and architecture are available type: boolean - default: false + default: true # Release and dev builds qualify every platform for the template they ship. workflow_call: inputs: @@ -43,9 +43,9 @@ on: type: boolean default: false fast_runners: - description: Use faster runners where the platform and architecture are available + description: Use Blacksmith where the platform and architecture are available type: boolean - default: false + default: true # Requalify fresh builds daily; publish missing immutable Windows cache keys. schedule: - cron: '30 11 * * *' @@ -63,7 +63,7 @@ jobs: if: >- github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.draft != true) - runs-on: ${{ (github.event_name == 'pull_request' || inputs.fast_runners) && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }} + runs-on: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 5 outputs: should_run: ${{ steps.scope.outputs.should_run || steps.graph.outputs.should_run }} @@ -155,14 +155,14 @@ jobs: os: ${{ fromJSON(needs.changes.outputs.runners || '["ubuntu-22.04","ubuntu-24.04-arm","macos-15","macos-15-intel","windows-2022","windows-11-arm"]') }} # Keep platform keys stable for slot names and Windows cross-compilation. runs-on: >- - ${{ inputs.fast_runners && fromJSON('{"ubuntu-22.04":"blacksmith-8vcpu-ubuntu-2204","ubuntu-24.04-arm":"blacksmith-8vcpu-ubuntu-2404-arm","macos-15":"blacksmith-6vcpu-macos-15","macos-15-intel":"macos-15-large","windows-2022":"blacksmith-8vcpu-windows-2025","windows-11-arm":"orca-windows-11-arm64-8core"}')[matrix.os] || matrix.os }} + ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && fromJSON('{"ubuntu-22.04":"blacksmith-8vcpu-ubuntu-2204","ubuntu-24.04-arm":"blacksmith-8vcpu-ubuntu-2404-arm","macos-15":"blacksmith-6vcpu-macos-15","macos-15-intel":"macos-15-intel","windows-2022":"blacksmith-8vcpu-windows-2025","windows-11-arm":"windows-11-arm"}')[matrix.os] || matrix.os }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' - JOBS: ${{ inputs.fast_runners && 'max' || '' }} + JOBS: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && 'max' || '' }} steps: - name: Parallelize Windows checkout - if: inputs.fast_runners && runner.os == 'Windows' + if: (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && runner.os == 'Windows' shell: bash run: | git config --global checkout.workers 0 @@ -336,7 +336,7 @@ jobs: ${{ !cancelled() && needs.changes.outputs.should_run != 'false' && needs.changes.outputs.qualification != 'false' && (github.event_name != 'pull_request' || github.event.pull_request.draft != true) }} - runs-on: ${{ inputs.fast_runners && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }} + runs-on: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -379,7 +379,7 @@ jobs: image: quay.io/pypa/manylinux_2_28_x86_64@sha256:407f771c51a2c3e83ebe5a7970b4289ead3a6db21d9b9c089168775cad11d328 - os: ubuntu-24.04-arm image: quay.io/pypa/manylinux_2_28_aarch64@sha256:c22ffd129ac99a8a42d1f2c2f4e88a9089288dd9ee987a7092da1c7dc48f27a9 - runs-on: ${{ inputs.fast_runners && (matrix.os == 'ubuntu-22.04' && 'blacksmith-8vcpu-ubuntu-2204' || 'blacksmith-8vcpu-ubuntu-2404-arm') || matrix.os }} + runs-on: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && (matrix.os == 'ubuntu-22.04' && 'blacksmith-8vcpu-ubuntu-2204' || 'blacksmith-8vcpu-ubuntu-2404-arm') || matrix.os }} container: ${{ matrix.image }} timeout-minutes: 25 env: @@ -441,7 +441,7 @@ jobs: (github.event_name != 'pull_request' || github.event.pull_request.draft != true) && (github.event_name != 'pull_request' || inputs.build_template || inputs.ref != '' || needs.changes.outputs.native_compatibility != 'false') }} - runs-on: ${{ inputs.fast_runners && 'blacksmith-8vcpu-ubuntu-2204' || 'ubuntu-22.04' }} + runs-on: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && 'blacksmith-8vcpu-ubuntu-2204' || 'ubuntu-22.04' }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' @@ -503,7 +503,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, ubuntu-24.04-arm] - runs-on: ${{ inputs.fast_runners && (matrix.os == 'ubuntu-22.04' && 'blacksmith-8vcpu-ubuntu-2204' || 'blacksmith-8vcpu-ubuntu-2404-arm') || matrix.os }} + runs-on: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && (matrix.os == 'ubuntu-22.04' && 'blacksmith-8vcpu-ubuntu-2204' || 'blacksmith-8vcpu-ubuntu-2404-arm') || matrix.os }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' @@ -569,7 +569,7 @@ jobs: permissions: contents: read actions: read - runs-on: ${{ inputs.fast_runners && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} + runs-on: ${{ (inputs.fast_runners || github.event_name == 'pull_request' || github.event_name == 'schedule') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }} timeout-minutes: 30 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/packaged-browser-e2e.yml b/.github/workflows/packaged-browser-e2e.yml index de37e67ec23..0265de5d5a3 100644 --- a/.github/workflows/packaged-browser-e2e.yml +++ b/.github/workflows/packaged-browser-e2e.yml @@ -23,7 +23,7 @@ permissions: cache-mode: read jobs: compatibility: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 25 steps: - uses: actions/checkout@v6 @@ -67,7 +67,7 @@ jobs: path: test-results/ retention-days: 3 layout-compat: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 30 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/performance-contracts.yml b/.github/workflows/performance-contracts.yml index e76ba2981c7..aaac40c6488 100644 --- a/.github/workflows/performance-contracts.yml +++ b/.github/workflows/performance-contracts.yml @@ -46,7 +46,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-latest":"blacksmith-4vcpu-ubuntu-2404","macos-latest":"blacksmith-6vcpu-macos-latest","windows-latest":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 20 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/pi-owner-runtime.yml b/.github/workflows/pi-owner-runtime.yml index da85f5b6637..c245df8f643 100644 --- a/.github/workflows/pi-owner-runtime.yml +++ b/.github/workflows/pi-owner-runtime.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-latest":"blacksmith-4vcpu-ubuntu-2404","macos-latest":"blacksmith-6vcpu-macos-latest","windows-latest":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/pi-provider-runtime.yml b/.github/workflows/pi-provider-runtime.yml index ac652d64e63..778448fc8eb 100644 --- a/.github/workflows/pi-provider-runtime.yml +++ b/.github/workflows/pi-provider-runtime.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-latest":"blacksmith-4vcpu-ubuntu-2404","macos-latest":"blacksmith-6vcpu-macos-latest","windows-latest":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/pr-test-loc.yml b/.github/workflows/pr-test-loc.yml index 340c6c7b70d..6c284cb4102 100644 --- a/.github/workflows/pr-test-loc.yml +++ b/.github/workflows/pr-test-loc.yml @@ -19,7 +19,7 @@ jobs: loc: name: test vs non-test LoC # API calls and a small Node script fit the free single-CPU container runner. - runs-on: ubuntu-slim + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 2 steps: # Why no checkout: the Files API already has per-file additions/deletions. diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 01f3fde8c72..13a2b90ec12 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -573,7 +573,7 @@ jobs: needs.code_paths.result == 'success' && needs.code_paths.outputs.git_compatibility == 'true' && needs.preflight.result == 'success' - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout @@ -645,7 +645,7 @@ jobs: needs.code_paths.outputs.codex_index_heal_contract == 'true' && needs.preflight.result == 'success' # Why ARM: @openai/codex ships @openai/codex-linux-arm64. - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm env: CODEX_CLI_VERSION: '0.150.1' # Why a second pin: --no-daemon only exists from 0.156, and Orca's codex wrapper relies on it. @@ -746,7 +746,7 @@ jobs: # Why ARM: the patch check rebuilds 4 packages x 2 builds and byte-compares against the # checked-in bundles. Those were generated on Linux x64 and reproduce byte-for-byte on # darwin-arm64, so the output is neither host-arch nor host-OS dependent. - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm steps: - name: Checkout @@ -778,7 +778,7 @@ jobs: needs.code_paths.outputs.shell_contracts == 'true' && needs.preflight.result == 'success' # Exercise Linux ARM with the standalone aarch64 release and Ubuntu's zsh. - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm # Bound stalled prerequisite downloads instead of waiting for GitHub's 6-hour default. timeout-minutes: 15 env: @@ -916,7 +916,7 @@ jobs: name: mobile web app bundle needs: [code_paths] if: needs.code_paths.outputs.mobile_web_app == 'true' - runs-on: ubuntu-latest + runs-on: blacksmith-8vcpu-ubuntu-2404 steps: - name: Checkout @@ -998,7 +998,7 @@ jobs: needs.code_paths.outputs.cross-version-wire == 'true' && needs.preflight.result == 'success' # Why ARM: source-only: tagged checkout plus in-process vitest, no docker or browser. - runs-on: ubuntu-24.04-arm + runs-on: blacksmith-4vcpu-ubuntu-2404-arm steps: # Why fetch-depth 0: the harness extracts the newest release tag to skew @@ -1046,7 +1046,7 @@ jobs: needs.code_paths.outputs.managed_hook_node18 == 'true' && needs.preflight.result == 'success' # Retain the required check while sharing preflight's checkout and built packages. - runs-on: ubuntu-slim + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 5 steps: diff --git a/.github/workflows/preflight-cli-platforms.yml b/.github/workflows/preflight-cli-platforms.yml index 2f77f269092..eed13e44624 100644 --- a/.github/workflows/preflight-cli-platforms.yml +++ b/.github/workflows/preflight-cli-platforms.yml @@ -25,7 +25,7 @@ jobs: preflight: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true name: Preflight CLI (${{ matrix.os }}) - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-22.04":"blacksmith-4vcpu-ubuntu-2204","macos-15":"blacksmith-6vcpu-macos-15","windows-2022":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 20 strategy: fail-fast: false diff --git a/.github/workflows/qualified-orcad-template.yml b/.github/workflows/qualified-orcad-template.yml index d0ef6545b98..9e1ab339a14 100644 --- a/.github/workflows/qualified-orcad-template.yml +++ b/.github/workflows/qualified-orcad-template.yml @@ -7,9 +7,9 @@ on: required: true type: string fast_runners: - description: Opt into faster adhoc runners; production stays on free GitHub runners + description: Use Blacksmith; disable inside the SignPath signing workflow. type: boolean - default: false + default: true permissions: contents: read diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml index 03d1b8479f3..00bf2decda9 100644 --- a/.github/workflows/release-cut.yml +++ b/.github/workflows/release-cut.yml @@ -858,6 +858,7 @@ jobs: uses: ./.github/workflows/dependency-security.yml with: ref: refs/tags/${{ needs.cut.outputs.tag }} + runner: ubuntu-latest terminal-rendering-golden: needs: cut @@ -1195,6 +1196,7 @@ jobs: uses: ./.github/workflows/qualified-orcad-template.yml with: ref: refs/tags/${{ needs.cut.outputs.tag }} + fast_runners: false # Why: artifact jobs submit Windows binaries to SignPath. Keep every # quota-consuming build behind all blocking release gates so a late test @@ -1227,6 +1229,7 @@ jobs: uses: ./.github/workflows/release-javascript.yml with: ref: refs/tags/${{ needs.cut.outputs.tag }} + runner: ubuntu-latest secrets: ORCA_POSTHOG_WRITE_KEY: ${{ secrets.ORCA_POSTHOG_WRITE_KEY }} diff --git a/.github/workflows/release-javascript.yml b/.github/workflows/release-javascript.yml index 7ff8be03267..200bec42481 100644 --- a/.github/workflows/release-javascript.yml +++ b/.github/workflows/release-javascript.yml @@ -12,7 +12,7 @@ on: default: false runner: type: string - default: ubuntu-latest + default: blacksmith-8vcpu-ubuntu-2404 outputs: supported: value: ${{ jobs.bundle.outputs.supported }} diff --git a/.github/workflows/release-policy.yml b/.github/workflows/release-policy.yml index 512a5fb8ea8..180334b9571 100644 --- a/.github/workflows/release-policy.yml +++ b/.github/workflows/release-policy.yml @@ -16,7 +16,7 @@ concurrency: jobs: enforce: if: github.repository == 'stablyai/orca' - runs-on: ubuntu-slim + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 5 steps: # Why: release events run this file from the tagged commit, so load the module from the same commit. diff --git a/.github/workflows/release-ref-validation.yml b/.github/workflows/release-ref-validation.yml index 42a55772e53..e7c837207a2 100644 --- a/.github/workflows/release-ref-validation.yml +++ b/.github/workflows/release-ref-validation.yml @@ -25,7 +25,7 @@ jobs: fail-fast: false matrix: os: [macos-15, windows-2022] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"macos-15":"blacksmith-6vcpu-macos-15","windows-2022":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 10 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/ssh-hostile-hosts.yml b/.github/workflows/ssh-hostile-hosts.yml index 10905dd86ab..48fab51e8d2 100644 --- a/.github/workflows/ssh-hostile-hosts.yml +++ b/.github/workflows/ssh-hostile-hosts.yml @@ -53,7 +53,7 @@ jobs: glibc_slot: # A draft carries no verdict; readiness re-triggers this workflow. if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft != true }} - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 # Same glibc 2.28 builder as the headless-server floor lane, so the slot loads on Debian 10. container: quay.io/pypa/manylinux_2_28_x86_64@sha256:407f771c51a2c3e83ebe5a7970b4289ead3a6db21d9b9c089168775cad11d328 timeout-minutes: 25 @@ -96,7 +96,7 @@ jobs: musl_slot: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft != true }} - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 timeout-minutes: 25 steps: - uses: actions/checkout@v6 @@ -138,7 +138,7 @@ jobs: # headless-server compat lane builds it (see linux_glibc217_compat in node-server-tests.yml). glibc217_slot: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft != true }} - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 timeout-minutes: 25 env: ORCA_BACKGROUND_LAUNCH: '1' @@ -178,7 +178,7 @@ jobs: hosts: needs: [glibc_slot, musl_slot, glibc217_slot] - runs-on: ubuntu-24.04 + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 60 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/terminal-ime-e2e.yml b/.github/workflows/terminal-ime-e2e.yml index 2dc4e9cf8c5..eb10051181e 100644 --- a/.github/workflows/terminal-ime-e2e.yml +++ b/.github/workflows/terminal-ime-e2e.yml @@ -23,7 +23,7 @@ env: jobs: linux-x11: name: Linux X11 terminal IME - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 timeout-minutes: 25 steps: @@ -82,7 +82,7 @@ jobs: linux-wayland: name: Linux Wayland Hangul terminating digit - runs-on: ubuntu-22.04 + runs-on: blacksmith-4vcpu-ubuntu-2204 timeout-minutes: 25 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/terminal-perf.yml b/.github/workflows/terminal-perf.yml index bc727e34a10..dd6cffe0911 100644 --- a/.github/workflows/terminal-perf.yml +++ b/.github/workflows/terminal-perf.yml @@ -57,7 +57,7 @@ cache-mode: read jobs: terminal-perf: name: terminal scale perf - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 45 env: NODE_OPTIONS: --max-old-space-size=4096 @@ -91,7 +91,9 @@ jobs: 'node config/scripts/rebuild-native-deps.mjs', 'pnpm run build:packages && node config/scripts/rebuild-native-deps.mjs' ] - const shared = process.env.RUNNER_KIND === 'github-hosted' && !process.env.JOB_CONTAINER && + const supportedRunner = process.env.RUNNER_KIND === 'github-hosted' || + process.env.RUNNER_NAME?.startsWith('blacksmith-') + const shared = supportedRunner && !process.env.JOB_CONTAINER && process.env.RUNNER_OS === 'Linux' && process.env.RUNNER_ARCH === 'X64' && manifest.engines?.node === '24' && typeof manifest.packageManager === 'string' && manifest.packageManager.split('+')[0] === 'pnpm@12.14.0' && diff --git a/.github/workflows/unit-plan.yml b/.github/workflows/unit-plan.yml index acc6a8fc500..1bd32f72ecc 100644 --- a/.github/workflows/unit-plan.yml +++ b/.github/workflows/unit-plan.yml @@ -25,7 +25,7 @@ permissions: jobs: plan: - runs-on: ubuntu-latest + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 5 outputs: shards: ${{ steps.plan.outputs.shards }} diff --git a/.github/workflows/unit-selection-evidence.yml b/.github/workflows/unit-selection-evidence.yml index 0385da6c02e..f49da2f58ec 100644 --- a/.github/workflows/unit-selection-evidence.yml +++ b/.github/workflows/unit-selection-evidence.yml @@ -15,7 +15,7 @@ jobs: selection_evidence: if: ${{ !cancelled() }} continue-on-error: true - runs-on: ubuntu-slim + runs-on: blacksmith-2vcpu-ubuntu-2404 steps: - uses: actions/checkout@v6 with: diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 5db6fda346e..acab67dae59 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -11,7 +11,7 @@ on: runner: description: Hosted runner for the unit shards. required: false - default: ubuntu-latest + default: blacksmith-4vcpu-ubuntu-2404 type: string browser_contract: @@ -91,35 +91,10 @@ jobs: - name: Install Electron package binary for tests run: node config/scripts/install-electron-package-binary.mjs - # The image resets HOME during login; shell fixtures intentionally use temporary homes. - - name: Preserve explicit login-shell homes on Blacksmith - if: runner.os == 'Linux' && startsWith(inputs.runner, 'blacksmith-') - run: | - sudo python3 - <<'PYTHON' - from pathlib import Path - profile = Path('/etc/profile.d/blacksmith.sh') - if profile.exists(): - original = profile.read_text() - updated = original.replace('export HOME="$RUNNER_HOME"', 'export HOME="${HOME:-$RUNNER_HOME}"') - if updated != original: - profile.write_text(updated) - PYTHON - - name: Verify Blacksmith unit runner environment if: runner.os == 'Linux' && startsWith(inputs.runner, 'blacksmith-') run: | ELECTRON_RUN_AS_NODE=1 "$(node -p "require('electron')")" --version - fixture_home="$(mktemp -d)" - trap 'rm -rf "$fixture_home"' EXIT - printf 'export ORCA_CI_PROFILE_LOADED=1\n' > "$fixture_home/.bash_profile" - HOME="$fixture_home" ORCA_CI_FIXTURE_HOME="$fixture_home" /bin/bash -lc ' - test "$HOME" = "$ORCA_CI_FIXTURE_HOME" && test "$ORCA_CI_PROFILE_LOADED" = 1 - ' || { - echo '::error::Runner login profile overrides fixture HOME' - grep -nH 'HOME' /etc/profile /etc/profile.d/*.sh || true - HOME="$fixture_home" /bin/bash -lc 'printf "Observed HOME=%s\n" "$HOME"' - exit 1 - } - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: diff --git a/.github/workflows/windows-typecheck-parity.yml b/.github/workflows/windows-typecheck-parity.yml index 7b15f958ec3..b80b993eca8 100644 --- a/.github/workflows/windows-typecheck-parity.yml +++ b/.github/workflows/windows-typecheck-parity.yml @@ -28,7 +28,7 @@ jobs: parity: if: github.event_name != 'pull_request' || github.event.pull_request.draft != true name: Windows compiler diagnostics and file selection - runs-on: windows-2022 + runs-on: blacksmith-4vcpu-windows-2025 timeout-minutes: 40 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/zcode-credential-contract.yml b/.github/workflows/zcode-credential-contract.yml index b9688b1bf9e..22196e3cd7f 100644 --- a/.github/workflows/zcode-credential-contract.yml +++ b/.github/workflows/zcode-credential-contract.yml @@ -32,7 +32,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, macos-15, windows-2022] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-22.04":"blacksmith-4vcpu-ubuntu-2204","macos-15":"blacksmith-6vcpu-macos-15","windows-2022":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/.github/workflows/zcode-transcript-contract.yml b/.github/workflows/zcode-transcript-contract.yml index 4c27c29ab73..dc98006b01e 100644 --- a/.github/workflows/zcode-transcript-contract.yml +++ b/.github/workflows/zcode-transcript-contract.yml @@ -24,7 +24,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, macos-15, windows-2022] - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJSON('{"ubuntu-22.04":"blacksmith-4vcpu-ubuntu-2204","macos-15":"blacksmith-6vcpu-macos-15","windows-2022":"blacksmith-4vcpu-windows-2025"}')[matrix.os] || matrix.os }} timeout-minutes: 20 env: ORCA_BACKGROUND_LAUNCH: '1' diff --git a/config/scripts/ci-dependency-download-cache.test.mjs b/config/scripts/ci-dependency-download-cache.test.mjs index 14cafead9fa..82eb3f82ef0 100644 --- a/config/scripts/ci-dependency-download-cache.test.mjs +++ b/config/scripts/ci-dependency-download-cache.test.mjs @@ -395,7 +395,10 @@ describe('CI dependency download caches', () => { const warmInstall = warm.steps.find((step) => step.uses === installer) const unitInstall = units.steps.find((step) => step.uses === installer) expect(warm['runs-on']).toBe('${{ matrix.runner }}') - expect(warm.strategy.matrix.runner).toEqual(['ubuntu-24.04-arm', pr.jobs.test.with.runner]) + expect(warm.strategy.matrix.runner).toEqual([ + 'blacksmith-4vcpu-ubuntu-2404-arm', + pr.jobs.test.with.runner + ]) expect(pr.jobs.preflight['runs-on']).toBe('blacksmith-8vcpu-ubuntu-2404') expect(pr.jobs.test.with.runner).toBe('blacksmith-8vcpu-ubuntu-2404') expect(units['runs-on']).toBe('${{ inputs.runner }}') diff --git a/config/scripts/dev-channel-orcad-template-workflow.test.mjs b/config/scripts/dev-channel-orcad-template-workflow.test.mjs index 61e1e10a317..b5723460fb6 100644 --- a/config/scripts/dev-channel-orcad-template-workflow.test.mjs +++ b/config/scripts/dev-channel-orcad-template-workflow.test.mjs @@ -33,7 +33,11 @@ describe.each(channels)('$name build ships the orcad template', (channel) => { it('builds the template from the commit the app is built from', () => { const template = jobs['orcad-template'] expect(template.uses).toBe('./.github/workflows/node-server-tests.yml') - expect(template.with).toEqual({ ref: channel.pinnedSha, build_template: true }) + expect(template.with).toEqual({ + ref: channel.pinnedSha, + build_template: true, + fast_runners: true + }) expect(template.permissions).toEqual({ contents: 'read', actions: 'read' }) expect(template.secrets).toBeUndefined() expect(mac.steps.find((step) => step.name === 'Checkout').with.ref).toBe(channel.pinnedSha) diff --git a/config/scripts/hourly-preflight-workflow.test.mjs b/config/scripts/hourly-preflight-workflow.test.mjs index d23681c026c..cb7eb0823c8 100644 --- a/config/scripts/hourly-preflight-workflow.test.mjs +++ b/config/scripts/hourly-preflight-workflow.test.mjs @@ -57,7 +57,7 @@ async function checkFreshness(overrides = {}) { describe('hourly build preflight', () => { it('gates Mac allocation and pins the checkout and downstream identity', () => { const build = workflow.jobs['build-hourly-mac'] - expect(preflight['runs-on']).toBe('ubuntu-latest') + expect(preflight['runs-on']).toBe('blacksmith-2vcpu-ubuntu-2404') expect(preflight.steps.some((step) => step.uses?.startsWith('actions/checkout'))).toBe(false) expect( preflight.steps.find((step) => step.id === 'app_token').with['permission-contents'] diff --git a/config/scripts/linux-package-fixture-cache.test.mjs b/config/scripts/linux-package-fixture-cache.test.mjs index 04caf501c30..ba8af2e1d17 100644 --- a/config/scripts/linux-package-fixture-cache.test.mjs +++ b/config/scripts/linux-package-fixture-cache.test.mjs @@ -159,7 +159,7 @@ it.each([ const source = workflow('ci-cache-warmup-platforms').jobs['warm-platforms'].uses const warm = parse(readFileSync(source, 'utf8')).jobs['warm-linux-package-fixtures'] const context = { github: { event_name: event } } - expect(warm['runs-on']).toBe('ubuntu-latest') + expect(warm['runs-on']).toBe('blacksmith-4vcpu-ubuntu-2404') expect(warm.steps.map((step) => step.uses)).toEqual([ 'actions/checkout@v6', './.github/actions/prepare-linux-package-fixture', diff --git a/config/scripts/node-server-fast-runners.test.mjs b/config/scripts/node-server-fast-runners.test.mjs index 3a596d6fef4..e327824bac4 100644 --- a/config/scripts/node-server-fast-runners.test.mjs +++ b/config/scripts/node-server-fast-runners.test.mjs @@ -2,23 +2,23 @@ import { readFileSync } from 'node:fs' import { runInNewContext } from 'node:vm' import { expect, it } from 'vitest' import { parse } from 'yaml' +import { compileAggregateExpression } from './pr-aggregate-gate-context.mjs' const workflow = parse(readFileSync('.github/workflows/node-server-tests.yml', 'utf8')) -function runnerFor(job, os, fast, eventName = 'workflow_dispatch') { - return runInNewContext(job['runs-on'].slice(3, -2), { - github: { event_name: eventName }, +function runnerFor(job, os, fast, event = 'workflow_dispatch') { + return compileAggregateExpression(job['runs-on'], ['inputs', 'matrix', 'github'])({ inputs: { fast_runners: fast }, matrix: { os }, - fromJSON: JSON.parse - }) + github: { event_name: event } + }).coerceString() } -it('keeps faster runners opt-in for both reusable and manual qualification', () => { +it('defaults reusable and manual qualification to Blacksmith', () => { for (const trigger of ['workflow_call', 'workflow_dispatch']) { expect(workflow.on[trigger].inputs.fast_runners).toMatchObject({ type: 'boolean', - default: false + default: true }) } }) @@ -27,13 +27,16 @@ it.each([ ['ubuntu-22.04', 'blacksmith-8vcpu-ubuntu-2204'], ['ubuntu-24.04-arm', 'blacksmith-8vcpu-ubuntu-2404-arm'], ['macos-15', 'blacksmith-6vcpu-macos-15'], - ['macos-15-intel', 'macos-15-large'], + ['macos-15-intel', 'macos-15-intel'], ['windows-2022', 'blacksmith-8vcpu-windows-2025'], - ['windows-11-arm', 'orca-windows-11-arm64-8core'] + ['windows-11-arm', 'windows-11-arm'] ])('preserves the qualification architecture for %s', (os, fastRunner) => { expect(runnerFor(workflow.jobs.persistence, os, false)).toBe(os) expect(runnerFor(workflow.jobs.persistence, os, true)).toBe(fastRunner) expect(runnerFor(workflow.jobs.persistence, os, undefined)).toBe(os) + for (const event of ['pull_request', 'schedule']) { + expect(runnerFor(workflow.jobs.persistence, os, undefined, event)).toBe(fastRunner) + } }) it('retains both Linux architectures and the pinned libc qualification containers', () => { @@ -62,12 +65,11 @@ it.each([ ['mobile_web_bundle', 'ubuntu-latest', 'blacksmith-8vcpu-ubuntu-2404'], ['desktop_template', 'ubuntu-latest', 'blacksmith-4vcpu-ubuntu-2404'], ['linux_glibc217_compat', 'ubuntu-22.04', 'blacksmith-8vcpu-ubuntu-2204'] -])('sizes %s for its work without changing default callers', (name, hostedRunner, fastRunner) => { +])('sizes %s while preserving the signing workflow override', (name, hostedRunner, fastRunner) => { expect(runnerFor(workflow.jobs[name], undefined, false)).toBe(hostedRunner) expect(runnerFor(workflow.jobs[name], undefined, true)).toBe(fastRunner) - expect(runnerFor(workflow.jobs[name], undefined, undefined, 'pull_request')).toBe( - name === 'changes' ? fastRunner : hostedRunner - ) + expect(runnerFor(workflow.jobs[name], undefined, undefined, 'pull_request')).toBe(fastRunner) + expect(runnerFor(workflow.jobs[name], undefined, undefined, 'schedule')).toBe(fastRunner) }) it('still builds and uploads cross-compiled Windows template addons on the x64 lane', () => { diff --git a/config/scripts/node-server-native-compat-scope.test.mjs b/config/scripts/node-server-native-compat-scope.test.mjs index ff93b416215..dc4d69d8b52 100644 --- a/config/scripts/node-server-native-compat-scope.test.mjs +++ b/config/scripts/node-server-native-compat-scope.test.mjs @@ -1,5 +1,4 @@ import { readFileSync } from 'node:fs' -import { runInNewContext } from 'node:vm' import { expect, it, vi } from 'vitest' import { parse } from 'yaml' import { compileAggregateExpression } from './pr-aggregate-gate-context.mjs' @@ -355,9 +354,13 @@ it('configures server glibc 2.28 slots and the glibc 2.17 compatibility lane', ( const compat = workflow.jobs.linux_glibc217_compat expect(compat.needs).toBe('changes') - expect(runInNewContext(compat['runs-on'].slice(3, -2), { inputs: { fast_runners: false } })).toBe( - 'ubuntu-22.04' - ) + const runner = compileAggregateExpression(compat['runs-on'], ['inputs', 'github']) + expect( + runner({ + inputs: { fast_runners: false }, + github: { event_name: 'workflow_dispatch' } + }).coerceString() + ).toBe('ubuntu-22.04') const run = compat.steps.map((step) => step.run ?? '').join('\n') expect(run).toMatch(/quay\.io\/pypa\/manylinux2014_x86_64@sha256:[0-9a-f]{64} /) expect(run).toContain('--slot=linux-x64-glibc217 --print-runtime') diff --git a/config/scripts/package-electron-runtime-contract.test.mjs b/config/scripts/package-electron-runtime-contract.test.mjs index 9c6139bf881..3ee3adca57a 100644 --- a/config/scripts/package-electron-runtime-contract.test.mjs +++ b/config/scripts/package-electron-runtime-contract.test.mjs @@ -4,6 +4,7 @@ import { join, resolve } from 'node:path' import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' import { parse } from 'yaml' +import { compileAggregateExpression } from './pr-aggregate-gate-context.mjs' const projectDir = resolve(import.meta.dirname, '../..') const require = createRequire(import.meta.url) @@ -110,6 +111,30 @@ describe('Electron runtime package contract', () => { ) expect(releaseWorkflowText).not.toContain('blacksmith-') + for (const caller of Object.values(releaseWorkflow.jobs)) { + if (!caller.uses?.startsWith('./.github/workflows/')) { + continue + } + const child = parse(readProject(caller.uses)) + const inputs = { + ...Object.fromEntries( + Object.entries(child.on.workflow_call.inputs).map(([name, input]) => [ + name, + input.default ?? '' + ]) + ), + ...caller.with + } + for (const job of Object.values(child.jobs)) { + if (!job['runs-on']) { + continue + } + const runner = job['runs-on'].startsWith('${{') + ? compileAggregateExpression(job['runs-on'], ['inputs'])({ inputs }).coerceString() + : job['runs-on'] + expect(runner).not.toMatch(/^(blacksmith-|orca-)/) + } + } expect(releaseWorkflow.jobs['build-mac']['runs-on']).toBe('ubuntu-latest') expect(releaseWorkflow.jobs['build-mac'].permissions.actions).toBe('write') expect(macDispatchStep.run).toBe( diff --git a/config/scripts/pr-e2e-route-contracts.test.mjs b/config/scripts/pr-e2e-route-contracts.test.mjs index bc7f647502b..2d03f20b0a9 100644 --- a/config/scripts/pr-e2e-route-contracts.test.mjs +++ b/config/scripts/pr-e2e-route-contracts.test.mjs @@ -275,7 +275,7 @@ describe('ssh-browser-e2e-routing', () => { const run = job.steps.find( (step) => step.name === 'Run Docker SSH browser network route journeys' ) - expect(job['runs-on']).toBe('ubuntu-latest') + expect(job['runs-on']).toBe('blacksmith-4vcpu-ubuntu-2404') expect(job.if).toContain("inputs.test_files == ''") expect(job.if).toContain(spec) expect(install.with['native-runtime']).toBe('node') diff --git a/config/scripts/pr-preflight-gates.test.mjs b/config/scripts/pr-preflight-gates.test.mjs index 2ead06d1056..d32b3807eba 100644 --- a/config/scripts/pr-preflight-gates.test.mjs +++ b/config/scripts/pr-preflight-gates.test.mjs @@ -400,7 +400,7 @@ it('runs the unchanged Node 18 smoke after every Node 24 step and preserves its expect(joined, background.id).toBeLessThan(steps.indexOf(smoke)) } expect(receipt.name).toBe('managed hooks on Node 18') - expect(receipt['runs-on']).toBe('ubuntu-slim') + expect(receipt['runs-on']).toBe('blacksmith-2vcpu-ubuntu-2404') expect(receipt.steps).toHaveLength(1) expect(receipt.steps[0].uses).toBeUndefined() expect(receipt.steps[0].env.MANAGED_HOOK_NODE18).toBe( diff --git a/config/scripts/pr-test-loc-summary.test.mjs b/config/scripts/pr-test-loc-summary.test.mjs index d206c3c09a0..15e6fc74c83 100644 --- a/config/scripts/pr-test-loc-summary.test.mjs +++ b/config/scripts/pr-test-loc-summary.test.mjs @@ -232,8 +232,8 @@ describe('PR test LoC summary', () => { expect(result.stderr).toContain('--from-pr') }) - it('is a no-checkout GitHub-hosted PR workflow', () => { - expect(locJob['runs-on']).toBe('ubuntu-slim') + it('is a no-checkout PR workflow on an ephemeral Blacksmith runner', () => { + expect(locJob['runs-on']).toBe('blacksmith-2vcpu-ubuntu-2404') expect(locJob.steps).toHaveLength(1) expect(locStep.run).toContain('gh api') expect(locStep.run).toContain('pr-test-loc-table.mjs') diff --git a/config/scripts/qualified-orcad-template.test.mjs b/config/scripts/qualified-orcad-template.test.mjs index 536386c0b60..53caafbb417 100644 --- a/config/scripts/qualified-orcad-template.test.mjs +++ b/config/scripts/qualified-orcad-template.test.mjs @@ -94,15 +94,16 @@ it('qualifies cache misses and permits cache publication only after the full mat expect(validate.run).toContain('assertNotDarkBuild') }) -it('keeps production on free GitHub runners and isolates adhoc qualification caches', () => { +it('keeps SignPath on GitHub runners and isolates Blacksmith qualification caches', () => { const release = parse(readFileSync('.github/workflows/release-cut.yml', 'utf8')) const adhoc = parse(readFileSync('.github/workflows/adhoc-mac-build.yml', 'utf8')) - expect(workflow.on.workflow_call.inputs.fast_runners.default).toBe(false) + expect(workflow.on.workflow_call.inputs.fast_runners.default).toBe(true) expect(release.jobs['orcad-template'].uses).toBe( './.github/workflows/qualified-orcad-template.yml' ) expect(release.jobs['orcad-template'].with).toEqual({ - ref: 'refs/tags/${{ needs.cut.outputs.tag }}' + ref: 'refs/tags/${{ needs.cut.outputs.tag }}', + fast_runners: false }) expect(adhoc.jobs['orcad-template'].with.fast_runners).toBe(true) expect(identity.env.RUNNER_PROFILE).toBe( diff --git a/config/scripts/terminal-perf-dependency-preparation.test.mjs b/config/scripts/terminal-perf-dependency-preparation.test.mjs index 82e2d31e97f..7cdab5a195b 100644 --- a/config/scripts/terminal-perf-dependency-preparation.test.mjs +++ b/config/scripts/terminal-perf-dependency-preparation.test.mjs @@ -47,6 +47,7 @@ function select(options = {}) { ...process.env, GITHUB_OUTPUT: output, RUNNER_KIND: options.kind ?? 'github-hosted', + RUNNER_NAME: options.name ?? 'GitHub Actions 1', JOB_CONTAINER: options.container ?? '', RUNNER_OS: options.os ?? 'Linux', RUNNER_ARCH: options.arch ?? 'X64' @@ -77,6 +78,12 @@ it('keeps the shared preparation route for the qualified older lifecycle', () => ).toBe('shared=true') }) +it('uses shared preparation on Blacksmith while preserving historical-ref fallback', () => { + const runner = { kind: 'self-hosted', name: 'blacksmith-4vcpu-ubuntu-2404-test' } + expect(select(runner)).toBe('shared=true') + expect(select({ ...runner, manifest: {} })).toBe('shared=false') +}) + it.each([ ['historical Node', { manifest: { ...supportedManifest, engines: { node: '22' } } }], ['historical pnpm', { manifest: { ...supportedManifest, packageManager: 'pnpm@10.0.0' } }], diff --git a/docs/readme/ci-runners.md b/docs/readme/ci-runners.md new file mode 100644 index 00000000000..cdd87ac9d82 --- /dev/null +++ b/docs/readme/ci-runners.md @@ -0,0 +1,41 @@ +# CI runners + +Use Blacksmith for ordinary PR checks, Linux E2E, cache preparation, mobile checks, +and unsigned desktop builds. Small routing and reporting jobs use 2 vCPUs; most +test jobs use 4; compilation and shared JavaScript builds use 8. Mac checks use +the 6-vCPU Apple Silicon runners. Adhoc Mac packaging uses 12 vCPUs. + +Keep matrix platform keys separate from runner labels: platform keys select +native slots, architectures, cache identities, and upload conditions. + +## Production signing + +SignPath requires every job in the signing workflow to use GitHub-hosted runners, +including jobs inside reusable workflows. `release-cut.yml` therefore explicitly +passes `fast_runners: false` to template qualification and `runner: ubuntu-latest` +to dependency security and shared JavaScript compilation. Preserve these overrides +when changing shared defaults. + +The production Mac build already runs on Blacksmith in the separately dispatched +`release-mac-build.yml`. Keep its exact-run identity checks and publication gates. +Moving more production work to Blacksmith requires another isolated workflow; +changing a runner label inside `release-cut.yml` breaks signing provenance. + +## Platform exceptions + +- Windows WSL and WSL2 tests retain GitHub runners: Blacksmith Windows runners do + not support the required nested virtualization. +- Windows signing and its rehearsal retain GitHub runners for SignPath provenance. +- Intel Mac and Windows ARM qualification retain their native GitHub runners; + Blacksmith does not offer these architectures. +- Windows desktop lifecycle tests retain their existing GitHub desktop images. +- Mac SSH hostile-host tests retain GitHub images because Blacksmith's shell + initialization restores the toolchain PATH that these fixtures must hide. +- Linux libc qualification keeps its pinned manylinux and Alpine containers, + regardless of the host runner pool. + +The shared dependency installer preserves temporary login-shell homes on +Blacksmith Linux hosts. Container jobs skip this host-image adjustment. + +Runner availability: . +Signing requirements: . diff --git a/mobile/src/transport/mobile-web-bundle-host-slow-link.test.ts b/mobile/src/transport/mobile-web-bundle-host-slow-link.test.ts index 9be2fec619e..e07e3cf2d96 100644 --- a/mobile/src/transport/mobile-web-bundle-host-slow-link.test.ts +++ b/mobile/src/transport/mobile-web-bundle-host-slow-link.test.ts @@ -154,4 +154,4 @@ it('verifies a host-served bundle over a 20 KiB/s link including incompressible expect(value?.assets.get(path)).toEqual(new Uint8Array(bytes)) } expect(tracker.size()).toBe(0) -}) +}, 15_000)