ci: make the pull-request Xcode lane a default-deny structural rule

Merged
TE
23d ago
+70-0

Stacked on #13923. Merge that first; this targets its branch so the diff stays to one file.

The gap

#13923 moves pull-request macOS jobs onto the macos-26 pool and makes their Xcode pin follow the lane. Its guards name the three jobs they cover:

macos-compile-admission, app-host-unit-tests, tests-build-and-lag

A macOS job added next month inherits none of that. It can pin CMUX_CI_XCODE_APP_MACOS_15 while its runs-on reads MACOS_RUNNER_PR, and every existing guard stays green. scripts/select-ci-xcode.sh hard-exits on a pinned developer dir that the image does not have, so that job fails at Xcode selection the first time someone points the lane at macos-26 โ€” which is exactly the failure #13923 exists to prevent, reintroduced by a job nobody thought to add to a list.

The rule

Inverted to default-deny. Every env value under .github/workflows naming the macos-15 Xcode must also read the pull-request variant, unless its exact (file, job, key) appears in EXEMPT with a written reason:

filejobkeywhy
iroh-release-gate.ymltailscale-version-skewCMUX_CI_XCODE_APPstreamed validation lane, routed by MACOS_RUNNER_STREAMED_VALIDATION
ci-macos.ymlswift-package-testsCMUX_CI_XCODE_APPbuilds the SDK 15 Ghostty helper; stays on MACOS_RUNNER_DUAL_XCODE
ci-macos.ymlswift-package-testsCMUX_CI_HELPER_XCODE_APPsame job's SDK 15 release-helper pin

Adding a macOS job requires no guard edit. Opting one out requires writing down why.

Keyed per (file, job, key), not per file. My first version keyed the exemption on the filename, which silently exempted every other job in ci-macos.yml โ€” the injection test below is what caught it.

Verification

Guard suite green on this branch (EXIT=0, 156 checks).

Injected a job that the old guards all accept:

brand-new-pr-job:
  runs-on: ${{ vars.MACOS_RUNNER_PR || 'blacksmith-6vcpu-macos-15' }}
  env:
    CMUX_CI_XCODE_APP: ${{ vars.CMUX_CI_XCODE_APP_MACOS_15 }}
FAIL: a macos-15 Xcode pin does not follow the pull-request lane
      Route it through CMUX_CI_XCODE_APP_PR, or add its (file, job, key) to
      EXEMPT with a reason.
ci-macos.yml::brand-new-pr-job: CMUX_CI_XCODE_APP: ${{ vars.CMUX_CI_XCODE_APP_MACOS_15 }}

PyYAML==6.0.3 is already installed for the guard jobs and tests/test_ci_self_hosted_guard.sh already parses YAML elsewhere, so this adds no dependency.

๐Ÿค– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Turns the pull-request Xcode lane guard into a default-deny structural rule so future macOS jobs can't silently pin the macos-15 Xcode and break when the lane moves.

Previously the guard only covered three named jobs; any macOS job added later would inherit no protection. Now every env value under .github/workflows naming the macos-15 Xcode must also read the pull-request variant unless its exact (file, job, key) is listed in EXEMPT with a reason. Three sites are exempt today; the key is per-job so exempting swift-package-tests doesn't exempt the rest of ci-macos.yml.

Summary by CodeRabbit

  • Tests
    • Expanded automated CI checks to validate macOS Xcode pin settings across workflow files, including whether they track the pull-request lane.
    • The checks now flag invalid or unparseable workflow configurations, with support for explicitly exempted settings.