A workflow still points to a retired runner label, but a default-branch search shows no match.
Fastest fix: build a GitHub Actions macOS 14 Runner inventory across repositories, reusable workflows, generated configuration, and actual run records, then validate each workload before approving migration. GitHub has announced retirement of the macOS 14 runner image on November 2, 2026; the affected labels are macos-14, macos-14-large, and macos-14-xlarge (GitHub’s retirement announcement).
This guide is for GitHub organization administrators auditing runner labels across repositories.
It is also for CI platform owners tracing reusable workflows, dynamic configuration, and run history.
Release owners can use the acceptance criteria to distinguish routine test failures from blocked delivery.
Last updated October 8, 2026; retirement details, affected labels, brownout plans, and suggested alternatives checked against the GitHub announcement. Recheck it before rollout if GitHub updates the announcement.
Retirement scope and inventory boundaries
A complete GitHub Actions workflow inventory needs a defined boundary. Include every organization repository in scope, not just active application repositories or those with a recent default-branch commit. Also record repositories you could not inspect, archived repositories excluded by policy, and approved exceptions. An unvisited repository is unknown, not cleared.
The retirement announcement identifies the affected hosted-runner labels and its planned brownout periods. Check the announcement for the current schedule and record the relevant dates in your change evidence; don’t rely on a copied schedule if the official notice has changed. The retirement applies to the announced hosted runner images. Do not infer that it changes the status of a self-hosted Mac, which is a different runner arrangement.
Use a scope record such as this before scanning:
| Scope item | Evidence to retain | What an incomplete result means |
|---|---|---|
| Organization repository list | Repository name, visibility or status, scan date, and scan result | Missing repositories prevent an organization-wide coverage claim |
| Workflow branches | Branches inspected and method used | Default-branch-only inspection may miss branch-specific files |
| Workflow sources | Paths, reusable-workflow references, and generated configuration locations | A caller-only review may miss the source of a runner label |
| Exceptions | Repository, reason, approver, owner, and review condition | An undocumented exception remains an untracked dependency |
Record the source and consumer separately. If a central reusable workflow receives a runner label as an input, the caller may supply the value while the reusable workflow consumes it. Both sides belong in the inventory.
Label and configuration coverage
Search for the literal macos-14 label family, but don’t treat a text search as the whole audit. Include macos-14-large and macos-14-xlarge, as named in the official retirement notice. Search workflow files and templates, then trace every value that can determine a job’s runs-on setting.
GitHub’s workflow syntax reference describes job runner selection and workflow structure. Its runner selection guidance explains how a job selects a runner. Use those documents to interpret findings; your organization’s own repository and run evidence establishes whether the configuration is in use.
Check the following sources, including indirect ones:
- Workflow files in every repository and relevant branch.
- Reusable workflows, both local and centrally maintained. A caller may pass a label into a reusable workflow rather than contain the runner selection itself. Review GitHub’s reusable workflow documentation when tracing the call and input chain.
- Matrix values, expressions, and variables used to set
runs-on. A label may be assembled or selected at runtime rather than appear as a complete literal. The contexts reference and expressions reference help identify where those values can come from. - Generated workflow files, internal templates, and configuration created before a workflow runs.
- Manual dispatches, branch-only workflows, scheduled jobs, and release workflows that may not have run during the audit window.
For each finding, capture the repository path, workflow name, the label or expression, its source, and where it is consumed. This makes the result reviewable by someone who did not perform the scan.
How do you find every workflow still using macos-14?
Combine repository-wide searches with configuration tracing and run-history checks. Search for all affected labels, inspect dynamic inputs and reusable workflows, then reconcile each result against actual workflow runs. A clean search is evidence about the text you searched, not proof that every relevant repository and execution path was included.
How should you inspect labels passed into reusable workflows?
Start at the caller, identify the input or expression passed to the reusable workflow, and follow it to the job’s runner selection. Search shared workflow repositories as well as application repositories. If a value comes from an organization variable or generated file, retain evidence of that source and the consumer; changing only the caller or only the shared template may leave other paths untouched.
Runtime evidence and business impact
Static configuration shows what a workflow could request. Run history helps show what has actually executed. Neither view replaces the other. Compare the inventory with workflow runs, and investigate jobs that have not run recently, run only from a specific branch, or require a manual trigger.
The workflow runs REST API provides a way to retrieve workflow run records. Use it, or an equivalent export, to preserve the workflow, triggering event, branch or ref, conclusion, and run time. Where available, also retain the runner label resolved for the run. If the record does not expose the resolved label, mark that limitation and connect the run to the workflow configuration that selected it.
A run that has not failed recently is not evidence that the workflow is unaffected. It may not have run, may be triggered only by a release event, or may use a path absent from the scanned default branch. Flag these cases for an owner to validate rather than closing them as clean.
Classify the workload by consequence, not simply by whether it is a build:
- Pull-request checks can delay merges or allow changes through without the expected validation if a required check is misconfigured.
- Scheduled regression jobs can miss problems if they stop running unnoticed.
- Signing and release workflows can block a delivery even when routine tests have passed.
- Manual and recovery workflows may be rarely used but still matter during an incident.
Assign each finding a named owner and a business impact. Separate a non-blocking validation failure from a release-path blocker. Record any fixed toolchain dependency, compatibility issue, or unverified build step as a risk. Don’t infer replacement-label performance or queue behavior from the label name or from GitHub’s recommendation; validate your workload directly.
Migration acceptance and coverage proof
A suggested replacement in an official announcement is a candidate, not proof that your project has migrated successfully. Validate the actual build, test, signing, and publishing steps that the workflow needs. Compare the old and new configuration, retain results, and keep unresolved work visible.
Use this checklist as the audit record. Mark an item complete only when you can attach or link to evidence.
- [ ] Define the organization and repository scope, including exclusions, inaccessible repositories, and approved exceptions.
- [ ] Search for
macos-14,macos-14-large, andmacos-14-xlargeacross workflow files, templates, and generated configuration. - [ ] Trace expressions, matrices, variables, and reusable-workflow inputs from their source to the job that consumes the runner label.
- [ ] Reconcile static findings with actual workflow runs, including manual, scheduled, branch-specific, and release-triggered paths.
- [ ] Record each workflow’s owner, business impact, trigger, runner-label source, and most recent available run evidence.
- [ ] Select a replacement label from current GitHub guidance and retain the source used for that choice.
- [ ] Run the real project pipeline with the replacement configuration; verify the steps required for build, tests, signing, and publication.
- [ ] Keep the configuration diff, run result, failed or skipped steps, and unresolved compatibility items with the change record.
- [ ] Obtain sign-off from the workload owner for release-critical tasks and document any temporary exception with an approver and review condition.
- [ ] Recheck repository coverage after migration so newly discovered or previously inaccessible repositories do not remain silently outside the audit.
The acceptance table makes the release decision explicit:
| Evidence state | Decision | Required follow-up |
|---|---|---|
| Repository scope is reconciled, the label path is traced, and the real workload passes on the selected replacement | Accept the migration for that workflow | Keep the change diff and run evidence with the record |
| A workflow is found but its trigger, owner, or runtime behavior is unclear | Do not mark the workflow covered | Assign an owner and validate the missing path |
| A release-critical task fails or a required step remains untested | Block that task’s migration approval | Resolve compatibility or approve a documented temporary exception |
| A repository could not be scanned or a configuration source is unavailable | Treat coverage as incomplete | Restore access or record an accountable exception before claiming organization-wide completion |
How can you confirm migration covers every repository?
Reconcile the organization’s repository list against the scan results, then account for every excluded or inaccessible repository. For each in-scope repository, retain workflow paths, label-source tracing, and relevant run evidence. Coverage is complete only when every repository has a recorded status; “no search result” is not sufficient if the repository, branch, template, or runtime path was never inspected.
What belongs in Mac CI migration acceptance evidence?
Keep the pre-migration and post-migration configuration, the replacement-label source, and results from the project’s real pipeline. Include required build, test, signing, and publishing outcomes, plus failures and unresolved compatibility concerns. If a step was not exercised, mark it unverified rather than treating the whole workflow as accepted.
Exceptions, ownership, and Mac workload decisions
Close the inventory with an owner and disposition for every unresolved dependency. A practical disposition is one of three choices: migrate and validate, retain a time-limited approved exception, or move the workload to a separately managed Mac environment. Make the choice based on evidence about the specific task, not on an assumption that a different runner label will behave identically.
A temporary exception should identify the affected workflow, the reason migration is incomplete, the accountable approver, and the condition for review or removal. Prioritize release blockers and required checks, but don’t ignore low-frequency scheduled or manual workflows: their quiet history can make them harder to detect, not less relevant.
A separate Mac environment may fit workloads that need a controlled Mac host or require a migration path outside the affected hosted labels. It also creates operational responsibilities. Your team must account for access control, toolchain upkeep, runner registration, security boundaries, and recovery. Review KVMFLUX use cases when assessing whether a remote Mac fits a specific CI task; do not treat the service as a substitute for validating the workflow itself.
For eligible work, KVMFLUX offers access to hosted real Macs through VNC, SSH, or a web console, with root access. That can be a better fit than repeatedly adapting a workload to a hosted runner when your requirement is a managed Mac host, but it does not remove the need to operate and secure your CI configuration. If you need a temporary or evaluation environment, compare the operating model and current rental terms against self-hosting or continued use of hosted runners. If your workload requires hardware you must physically control, or it runs as stable heavy capacity that makes ownership more suitable, rental may not be the right choice.
Start by completing the repository and workflow coverage record, then approve only the migrations with workload-specific evidence. Where a validated task needs a separate Mac host, compare that option against your current runner arrangement and internal maintenance capacity before assigning it.
Further Reading
- Build a complete macOS runner inventory before planning capacity changes.
- Review self-hosted runner setup, labels, and operational checks for remote Macs.
- Compare self-hosted Mac CI with Xcode Cloud when deciding where migrated workflows should run.
Move Your macOS CI to a Dedicated Runner
Set up a dedicated Mac mini M4 as a self-hosted runner for your macOS builds. Connect over SSH and keep your build environment under your control. Choose when to update macOS and Xcode to fit your migration and release schedule. Rent by the day, week, month, or quarter and select from six regions.