From 4ced80f03667d8d16401dd650a37eb0f537e3a4e Mon Sep 17 00:00:00 2001 From: Squirrel Date: Mon, 1 Jun 2026 17:24:08 +0100 Subject: [PATCH 1/2] fix: isolate pull request CI from self-hosted runners Route pull_request jobs that execute checked-out code to ephemeral GitHub-hosted runners and clean isolated Docker auth directories after registry use. Assisted-by: OpenAI:gpt-5.3-codex Signed-off-by: Giles Cope --- .../workflows/continuous-integration-test.yml | 15 +++++++++- .github/workflows/continuous-integration.yml | 30 +++++++++++++++---- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/.github/workflows/continuous-integration-test.yml b/.github/workflows/continuous-integration-test.yml index 88482ac6c..0d9636ccf 100644 --- a/.github/workflows/continuous-integration-test.yml +++ b/.github/workflows/continuous-integration-test.yml @@ -16,7 +16,10 @@ concurrency: jobs: run: name: Run tests - runs-on: [self-hosted, "tier:large"] + # Pull requests execute checked-out repository code (.envrc/Earthly), so use + # ephemeral GitHub-hosted runners for PRs and reserve persistent self-hosted + # runners for trusted merge-queue/push events. + runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} permissions: contents: read packages: write @@ -43,6 +46,12 @@ jobs: if: steps.guard.outputs.hit != 'true' && runner.environment != 'self-hosted' run: scripts/free-disk-space.sh + - name: Isolate docker config + if: steps.guard.outputs.hit != 'true' + run: | + mkdir -p "$RUNNER_TEMP/.docker" + echo "DOCKER_CONFIG=$RUNNER_TEMP/.docker" >> "$GITHUB_ENV" + - name: Log in to GHCR (for remote cache) uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && steps.guard.outputs.hit != 'true' @@ -112,6 +121,10 @@ jobs: name: Lcov Coverage Report path: test-artifacts/tests.lcov + - name: Remove isolated docker auth + if: ${{ always() && env.DOCKER_CONFIG != '' }} + run: rm -rf "$DOCKER_CONFIG" + - uses: ./.github/actions/tree-cache-guard/save if: steps.guard.outputs.hit != 'true' with: diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 2c916d801..dbe6eb045 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -31,9 +31,11 @@ jobs: permissions: id-token: write contents: read - # TEST PR — points at the new self-hosted runner pool to validate end-to-end - # build performance. Revert before merge. - runs-on: [self-hosted, "tier:large"] + # Pull requests execute checked-out repository code (for example .envrc and + # Earthly targets), so keep them on ephemeral GitHub-hosted runners. Use the + # persistent self-hosted runner pool only for trusted merge queue and manual + # builds. + runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} env: FORCE_COLOR: 1 outputs: @@ -211,6 +213,10 @@ jobs: name: Test artifacts (amd64) path: test-artifacts-amd64/ + - name: Remove isolated docker auth + if: ${{ always() && env.DOCKER_CONFIG != '' }} + run: rm -rf "$DOCKER_CONFIG" + sbom-scan-node: permissions: contents: read @@ -544,7 +550,7 @@ jobs: actions: write name: Test Toolkit needs: [run] - runs-on: [self-hosted, "tier:large"] + runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} env: FORCE_COLOR: 1 steps: @@ -651,6 +657,10 @@ jobs: with: key: ${{ steps.guard.outputs.key }} + - name: Remove isolated docker auth + if: ${{ always() && env.DOCKER_CONFIG != '' }} + run: rm -rf "$DOCKER_CONFIG" + toolkit-e2e: permissions: contents: read @@ -826,7 +836,7 @@ jobs: packages: read name: Mainnet Sync (1000 blocks) needs: [run] - runs-on: [self-hosted, "tier:medium"] + runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:medium"]') }} steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 @@ -874,6 +884,10 @@ jobs: /tmp/midnight-pg.log if-no-files-found: ignore + - name: Remove isolated docker auth + if: ${{ always() && env.DOCKER_CONFIG != '' }} + run: rm -rf "$DOCKER_CONFIG" + toolkit-contracts-e2e: permissions: contents: read @@ -1097,7 +1111,7 @@ jobs: name: Local Environment Tests if: (github.event_name == 'pull_request' && github.event.pull_request.merged == false) || github.event_name == 'merge_group' needs: [run, build-indexer-images] - runs-on: [self-hosted, "tier:medium"] + runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:medium"]') }} # The local-env stack (kupo, ogmios, db-sync, indexers, postgres, nats, # cardano-node, ...) binds fixed ports on 0.0.0.0 — 1442, 1337, 8088, # 4222, 5432, 30000, 32000 — so concurrent jobs on the same self-hosted @@ -1151,6 +1165,10 @@ jobs: with: key: ${{ steps.guard.outputs.key }} + - name: Remove isolated docker auth + if: ${{ always() && env.DOCKER_CONFIG != '' }} + run: rm -rf "$DOCKER_CONFIG" + # ephemeral-environment-tests: # if: (github.event_name == 'pull_request' && github.event.pull_request.merged == false) || github.event_name == 'merge_group' # # needs: From 47da4245b616cda3be99f832458bb268c8c8c7aa Mon Sep 17 00:00:00 2001 From: Squirrel Date: Mon, 1 Jun 2026 17:24:52 +0100 Subject: [PATCH 2/2] fix: use ephemeral runners for fork PRs Limit the ubuntu-latest fallback to external fork pull requests while preserving self-hosted runners for trusted internal PR, merge queue, push, and manual events. Assisted-by: OpenAI:gpt-5.3-codex Signed-off-by: Giles Cope --- .../workflows/continuous-integration-test.yml | 9 +++++---- .github/workflows/continuous-integration.yml | 16 ++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/continuous-integration-test.yml b/.github/workflows/continuous-integration-test.yml index 0d9636ccf..bbb7362ed 100644 --- a/.github/workflows/continuous-integration-test.yml +++ b/.github/workflows/continuous-integration-test.yml @@ -16,10 +16,11 @@ concurrency: jobs: run: name: Run tests - # Pull requests execute checked-out repository code (.envrc/Earthly), so use - # ephemeral GitHub-hosted runners for PRs and reserve persistent self-hosted - # runners for trusted merge-queue/push events. - runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} + # External fork pull requests execute checked-out repository code + # (.envrc/Earthly), so use ephemeral GitHub-hosted runners for those PRs + # and reserve persistent self-hosted runners for trusted internal PR, + # merge-queue, and push events. + runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} permissions: contents: read packages: write diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index dbe6eb045..42157f6f1 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -31,11 +31,11 @@ jobs: permissions: id-token: write contents: read - # Pull requests execute checked-out repository code (for example .envrc and - # Earthly targets), so keep them on ephemeral GitHub-hosted runners. Use the - # persistent self-hosted runner pool only for trusted merge queue and manual - # builds. - runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} + # External fork pull requests execute checked-out repository code (for + # example .envrc and Earthly targets), so keep them on ephemeral + # GitHub-hosted runners. Use the persistent self-hosted runner pool for + # trusted internal PR, merge queue, and manual builds. + runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} env: FORCE_COLOR: 1 outputs: @@ -550,7 +550,7 @@ jobs: actions: write name: Test Toolkit needs: [run] - runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} + runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'ubuntu-latest' || fromJSON('["self-hosted","tier:large"]') }} env: FORCE_COLOR: 1 steps: @@ -836,7 +836,7 @@ jobs: packages: read name: Mainnet Sync (1000 blocks) needs: [run] - runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:medium"]') }} + runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'ubuntu-latest' || fromJSON('["self-hosted","tier:medium"]') }} steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 @@ -1111,7 +1111,7 @@ jobs: name: Local Environment Tests if: (github.event_name == 'pull_request' && github.event.pull_request.merged == false) || github.event_name == 'merge_group' needs: [run, build-indexer-images] - runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted","tier:medium"]') }} + runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'ubuntu-latest' || fromJSON('["self-hosted","tier:medium"]') }} # The local-env stack (kupo, ogmios, db-sync, indexers, postgres, nats, # cardano-node, ...) binds fixed ports on 0.0.0.0 — 1442, 1337, 8088, # 4222, 5432, 30000, 32000 — so concurrent jobs on the same self-hosted