ci(nightly): shorten the release-pool signing chain (about 18 to 15 min to publish)

Merged
TE
4d ago
+387-102

Summary

Leo, 2026-11-03: "the signing/publishing don't require 30 cores". The NEXT nightly's release-pool signing chain is mostly waiting, not work. In run 41570134320 it took 18.2 min from the end of build-nightly-app (03:25:28) to publish-nightly's end (03:43:38). The step times show where the waiting is:

  • signer-build needed pick-nightly-sign-runner, so its hosted pickup and cache restore (43 s) sat between the pick and signer-app. Nothing in it reads the pick's outputs since #30081 put it back on the signer route. It now needs only decide and builds while the app does.
  • signer-app spent 37 s on a full checkout of the build tree, though it reads only scripts/ and the top-level entitlements. It now checks out sparse (sparse-checkout: scripts; cone mode keeps the root files).
  • Apple's clock started only once signer-app had uploaded its artifact and signer-app-notary had been picked up, checked out, and had downloaded and unpacked the app (≈50 s after signing). signer-app now starts the upload to Apple itself (release-signer/submit-app.sh start) right after packing. It runs in the background beside the artifact uploads, and submit-app.sh finish hands the submission id on as an output. signer-app-notary is gone.
  • signer-dmg downloaded the whole 355 MB signed app (50 s) only to read its Info.plist for the appcast. signer-app now hands that Info.plist on as its own small artifact, with its digest as an output, and signer-dmg checks it against the digest.
  • launch-smoke-nightly read the unsigned DMG in one download-artifact stream (205 s). With signer-dmg shorter, that would have put it on publish's path. It now reads in parallel ranges first (fetch_run_artifact.py), as signer-dmg-image and the final-DMG verify already do, with download-artifact as the fallback.

The DMG image step stays on a Mac (hdiutil). Verify DMG and the launch smoke already run side by side (#32378).

What stays

  • Both notarizations, in order. The Mac still staples the app's ticket before it builds the DMG (signer-staple-app.sh polls Apple for the ticket, which exists only for an accepted submission). signer-dmg adds an explicit Accepted check, release-signer/wait-app-notary.sh, before it signs the DMG: notary-wait, then the notary log's status must be Accepted. The DMG's own sign, notarize and staple is unchanged.
  • The Computer Use helper's notarization (sign-app.sh, helper-first) is untouched.
  • The cmux NIGHTLY-identity (legacy) chain. legacy-signer-* jobs are unchanged. They still need signer-build, which now finishes earlier, so the change can only bring them forward.
  • notary_submit (#33028). submit-app.sh submits through it, so a 429 rate limit is still waited out and retried.
  • The overtaken gate (#33109). signer-app still needs pick-nightly-sign-runner with overtaken != 'true'.
  • Keys still live only in a per-job mktemp -d (umask 077) that the script's EXIT trap removes. The background upload owns its own key directory and removes it when the upload ends. No secret, environment or permission changes. Runners are unchanged: GitHub-hosted Ubuntu first, Blacksmith 4 vCPU on a re-run, so tests/test_ci_self_hosted_guard.sh needs no new allowlist line.
  • If Apple rejects the app, the staple still fails at its deadline and signer-dmg never signs, as before. signer-dmg's wait now fails on any answer other than Accepted.

nightly.yml goes from 487,267 to 489,623 bytes (cap 490,000).

Performance

Before: run 41570134320's job and step times. After: projected from those same step times; the first NEXT nightly after merge gives the measured number (follow-up comment).

metricbeforeafter (projected)deltaharness or run link
end of build-nightly-app → publish-nightly done18.2 min≈15.3 min≈−2.9 minrun 41570134320 job/step times
pick done → signer-app start (signer-build hop)79 s≈36 s−43 ssame
signer-app build checkout37 s≈5 s (sparse, as the tools checkout)−32 ssame
app signed → Apple submission starts≈50 s≈2 s−48 ssame
signer-dmg-image end03:34:41≈03:32:40≈−2.0 minsame
signer-dmg signed-app download50 s≈2 s (Info.plist only)−48 ssame
launch-smoke unsigned-DMG download205 sranged read (signer-dmg-image's took 64 s on the same mini for 355 MB)off publish's pathsame
signer jobs per run54−1 hosted job—

Testing

Run locally with system python3, all passing:

  • tests/test_nightly_signer_jobs.py (updated: signer-app-notary gone; submit and wait order; Info.plist digest; signer-build needs only decide; launch smoke's ranged read)
  • tests/test_release_signer_*.py (new AppNotarizationTests: background submit hands on the id; failed upload or missing id fails finish; wait passes only Accepted; key never on argv or in the signer's env; key dirs removed)
  • tests/test_nightly_sign_runner.py, tests/test_nightly_step_coverage.py, tests/test_workflow_file_size.py, tests/test_ci_signing_keychain_is_deleted_before_bundle_code.py, tests/test_ci_nightly_off_blacksmith.py, tests/test_supplychain_security.py, tests/test_ci_self_hosted_guard.sh, plus tests/test_nightly_trusted_routing.py, tests/test_fetch_run_artifact.py and the other tests that read the signer jobs.
  • tests/test_nightly_universal_build.sh fails ("nightly preparation must run on Blacksmith Linux…") identically on base origin/feat-cmux-next; it is not from this change.

Observed / Not run

  • Observed: the step timings above (run 41570134320 via the jobs API), and Apple's ≈35 s upload and 113 s processing in its signer-app-notary log.
  • Not run: a real nightly with these jobs. Only nightly-next with the release environment can sign and notarize. The first nightly after merge is the end-to-end check. If the pool path fails, build-sign-notarize-nightly (the macOS signer) still signs that build, as today.

Changelog

none

risk: high (release signing, CI)

🤖 Generated with Claude Code

Agent session: agent session


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Shortens the release-pool signing chain in the nightly workflow, cutting the time from the end of build-nightly-app to publish from about 18 minutes to about 15 minutes.

  • signer-build now needs only decide; signer-app checks out the build tree sparse and starts Apple's notarization upload in the background, so the signer-app-notary job is gone.
  • signer-dmg waits for Apple's Accepted answer before signing the DMG and reads only the app's Info.plist for the appcast.
  • launch-smoke-nightly downloads the unsigned DMG in parallel ranges first.

Both notarizations stay in order: the Mac still staples the app's ticket before the DMG, and signer-dmg checks the Accepted answer before signing. The legacy NIGHTLY-identity chain, the Computer Use helper notarization, notary_submit retries, and the overtaken gate are unchanged.

Risk: high (release signing, CI).