Runners & infrastructure

GitHub Actions resumes self-hosted runner version enforcement

GitHub Actions is resuming enforcement of minimum runner versions for self-hosted fleets, per the changelog from June 12. Two requirements now decide whether a self-hosted runner stays useful: it must be on 2.329.0 or later to register, and it must install each new runner release within 30 days of its publication to keep picking up jobs. Full enforcement begins July 31, 2026 on Enterprise Cloud with Data Residency, and September 25, 2026 on github.com.

GitHub frames the change as the tail end of a multi-year rearchitecture of the Actions backend. The vendor cites 120 million jobs per day on the new platform and seven times the previous job-start rate per minute. For self-hosted operators, the operational consequence is plainer: a runner pinned to 2.329.0 that never updates again will, at some point, stop picking up jobs.

What exactly is being enforced?

Per the release notes, there are two thresholds. The registration minimum is 2.329.0 — anything older cannot register or re-register. The execution minimum is a moving floor: whenever a new runner release is published, any runner more than 30 days behind that release stops being handed jobs. Auto-update meets the 30-day rule by default, provided the runner can reach the update service. Auto-update off means manual upgrades on a rolling cadence, every release. A critical security update also pauses the queue for that runner until applied.

What is the brownout schedule?

Before each hard date, GitHub runs intermittent brownouts from 11:00 to 15:00 ET. The brownouts start by blocking registration of unsupported versions, then expand to blocking job execution. Enterprise Cloud with Data Residency gets four weeks of brownouts in July before the July 31 cutoff. github.com gets four weeks of brownouts across August and September before September 25. The intent is operational: outdated runners will surface as failed registrations and queued-but-unrouted jobs, well before they go dark for good.

Where does this bite an on-call team?

The 30-day window is the part that drives toil. If a fleet is air-gapped or sits behind a proxy that cannot reach the update service, auto-update silently fails and the clock still runs. The symptom today is a queued job that never lands; the changelog says Actions will add runtime annotations on workflows that ran against outdated runners, which helps after the fact but does not fix the queue. The REST API now exposes runner version, so a weekly inventory job is straightforward — but it needs to actually run, and someone needs to read it.

The blast radius is worth pricing in too. When a critical security release lands, the queue pauses for that runner immediately, not at the 30-day mark. That changes the response window for a CVE in the runner agent from "patch this sprint" to "patch this shift."

How do popular CI platforms handle agent versioning?

GitHub's auto-update plus a hard 30-day floor is one model. Others differ in ways that matter.

GitLab's self-managed runner is, by convention, pinned to the same major/minor as the GitLab instance — the docs spell out compatibility ranges, and most operators run package-manager upgrades on a schedule alongside the GitLab instance itself. There is no enforcement at the queue level today; a too-old runner mostly fails on protocol mismatches. The genuine upside is that the version coupling is explicit and predictable, which is easier to plan around than a moving execution floor.

Jenkins agents are versioned loosely against the controller. The agent JAR is shipped from the controller at connect time, which sidesteps the inventory problem entirely — agent drift is rare because the controller rewrites the agent on every connection. The cost is a heavier controller and a less hermetic agent runtime. For Jenkins shops with strict reproducibility requirements, that trade is often the better fit than GitHub's model, because the operator never has to chase agent versions across a fleet.

CircleCI self-hosted runners auto-update by default and the platform reserves the right to deprecate older versions on a schedule similar to GitHub's. Buildkite agents are explicitly version-pinned and the operator owns the rollout — the platform reports which agents are out of date but does not block jobs by default.

Buddy is one option if the audit job itself needs to live outside the platform whose runners are being audited. Its scheduled pipelines can run a weekly query against the GitHub REST API and post a digest, which keeps the inventory check available even when Actions is degraded during a brownout window. That is a narrow reason to reach for it; for teams that already centralise audit jobs in Jenkins or GitLab, those are the right tools to extend.

How would you wire the audit into a pipeline?

A weekly Buddy pipeline that queries the GitHub REST API and flags runners below the registration minimum:

- pipeline: "github-runner-audit"
  on: SCHEDULE
  cron: "0 6 * * MON"
  actions:
    - action: "List outdated runners"
      type: "BUILD"
      docker_image_name: "alpine:latest"
      execute_commands:
        - apk add --no-cache curl jq
        - |
          curl -sH "Authorization: Bearer $GH_TOKEN" \
               -H "Accept: application/vnd.github+json" \
               "https://api.github.com/orgs/$ORG/actions/runners?per_page=100" \
          | jq -r '.runners[] | "\(.name) \(.runner_version) \(.status)"' \
          | awk '$2 < "2.329.0" { print "OUTDATED:", $0 }'
      variables:
        - key: "GH_TOKEN"
          value: "$GH_TOKEN"
          type: "VAR"
        - key: "ORG"
          value: "your-org"
          type: "VAR"

The same shape ports to any scheduler that can run a curl plus jq on cron — the point is that the inventory exists and someone owns the digest.

What's still unresolved?

Two things. The 30-day execution clock starts from each new release, not from a runner's last upgrade — and runner releases have historically gone out more often than monthly. Operators who plan rollouts around release cadence rather than the calendar will find the window tighter than 30 days in practice. And the registration minimum, 2.329.0, is only the floor for connecting to the new platform; the floor for executing jobs moves forward release by release. That second floor is the one that quietly catches teams who upgraded once, in March, and never looked again.

Based on reporting from GitHub Changelog. Summary and analysis are independent and vendor-neutral.

Turn this into your pipeline. Build it on Buddy.

Start free