ci(signing): owned Macs first for the release, repair and DEV signing jobs, with a stall-aware fallback

Merged
TE
8d ago
+298-13

Leo, 2026-10-28, on letting the release signing jobs run on our own Macs while Blacksmith is starved: "ok. idk what the "risk" was before but like.. we can just read the code and stuff." The routing order is Linux first, then owned Macs, then Blacksmith macOS last.

What changed

  • release.yml build-sign-notarize, repair-v0-64-25-helper-rpaths.yml repair and cmux-next-dev-daily.yml sign each get a pick-sign-runner job, like the nightly signing picker:
    • Linux Blacksmith, the routing environment, actions: read and contents: read, continue-on-error.
    • It runs scripts/ci/signing_runner.py: a drained owned Mac on attempt 1 while vars.CI_SIGN_OWNED is 1, else the Blacksmith macOS 26 label whose queue moves, and the other size for a re-run (stall-aware fallback).
    • The routing token is minted only on the refs the release environment allows (main, rc/**, v* tags).
  • Each signing job takes the pick: github.run_attempt == 1 && <owned> && fromJSON(<owned>), then the Blacksmith pick, then a literal Blacksmith label. No raw repository variable names the signing runner.
  • Each signing job starts with the claim gate (before the checkout's token) and runs the claim script before any secret; its existing if: always() keychain delete stays.
  • tests/test_ci_signing_owned_mac.py reads which picker output is the owned one, and fails a picker of an owned-routed job that could hold a secret on any ref.
  • tests/test_ci_release_sdk_lane.sh expects the release job's new runs-on.

Before / after

  • Before: the three keyed signing jobs sat on the literal blacksmith-12vcpu-macos-26 label, whatever its queue.
  • After: an idle owned Mac first (once CI_SIGN_OWNED=1), else whichever Blacksmith macOS 26 size is moving; a re-run takes the other size.

Tests

Local: test_ci_signing_owned_mac.py, test_ci_blacksmith_linux_failover.py, test_ci_runs_on_fallback.py, test_ci_runs_on_values.py, test_runs_on_labels.py, test_supplychain_security.py, test_ci_check_repo_variables.py, test_cmux_next_dev_daily_dispatch.py, test_ci_release_sdk_lane.sh, test_repair_v06425_workflow.sh, actionlint.

Risk: medium. It changes where release signing runs. Owned Macs stay off until the variable is set; without it the jobs only move between Blacksmith sizes.

Agent session: agent session

šŸ¤– Generated with Claude Code