From 6f30fcff611111953aa21dbaecf3b6ed9729165d Mon Sep 17 00:00:00 2001 From: sprooty Date: Wed, 19 Aug 2026 04:12:28 +0000 Subject: [PATCH] policy: select runners by capability, and stop advising a location label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gate itself ran on `[self-hosted, node-b, linux, x64]` and, on failure, told every repository in the organization to do the same. That advice is what spread a location label into 59 job definitions across 12 repositories, and it is why proxmox-gha-public-rust and wsl2-gha-public-rust sat idle — both `busy: false` — while all three Node B workers were busy and jobs queued behind them at a p90 of 207s and a p99 of 1153s (2026-08-19 review). What the gate *enforces* is deliberately unchanged: a job must name the literal `self-hosted`, and dynamic `runs-on` is still rejected. Only the selector it uses and the examples it prints have changed, to the capability labels the fleet actually advertises — `publish` for a Docker daemon, `tailnet` for Tailnet reachability, and nothing at all for work that can run anywhere. --- .github/workflows/audit.yml | 2 +- .github/workflows/runner-policy-reusable.yml | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index d80cc37..45c2778 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -25,7 +25,7 @@ permissions: jobs: audit: - runs-on: [self-hosted, node-b, linux, x64] + runs-on: [self-hosted] steps: - uses: actions/checkout@v4 - name: Audit this repository's workflows and exception expiry diff --git a/.github/workflows/runner-policy-reusable.yml b/.github/workflows/runner-policy-reusable.yml index ea06d1c..e23a9db 100644 --- a/.github/workflows/runner-policy-reusable.yml +++ b/.github/workflows/runner-policy-reusable.yml @@ -26,6 +26,13 @@ # that repository, and recording the reason and expiry in # runner-exceptions.json so the daily expiry check still surfaces it. # +# Labels name capabilities, not locations (2026-08-19). `node-b` was being used +# as a fleet selector, which left two of the five runners permanently idle +# while the other three were busy and jobs queued behind them at a p90 of +# 207s; `linux`/`x64` are advertised by every runner and selected nothing. +# What this gate enforces is unchanged: the literal `self-hosted`, and no +# dynamic `runs-on`. +# # Fail-closed note: this job requests self-hosted labels. A repository not # added to the `public-node-b` runner group has no runner able to accept it, so # the check stays queued and the pull request cannot merge. That is intended -- @@ -42,7 +49,7 @@ permissions: jobs: runner-policy: - runs-on: [self-hosted, node-b, linux, x64] + runs-on: [self-hosted] steps: - uses: actions/checkout@v5 @@ -110,9 +117,9 @@ jobs: print('', file=sys.stderr) print('Organization policy: every job must select a self-hosted runner ' 'explicitly, e.g.', file=sys.stderr) - print(' runs-on: [self-hosted, node-b, linux, x64]', file=sys.stderr) - print(' runs-on: [self-hosted, node-b, linux, x64, docker, publish] ' - '# needs Docker', file=sys.stderr) + print(' runs-on: [self-hosted] # any runner', file=sys.stderr) + print(' runs-on: [self-hosted, publish] # needs Docker', file=sys.stderr) + print(' runs-on: [self-hosted, tailnet] # needs Tailnet', file=sys.stderr) sys.exit(1) print(f'ok: {len(workflows)} workflow file(s) audited, all self-hosted')