ci(nightly-next): run verify-signed's checks on the DMG Mac, beside the DMG

Merged
TE
14d ago
+268-157

Summary

A pool-signed cmux NEXT nightly sent its stapled app to two office Macs: signer-dmg-image (to build the DMG) and verify-signed-nightly (a gzip that signer-dmg made on Linux, downloaded again over the office link). That second download took 2-5 min in recent runs and set the length of the verify stage whenever it outran verify-final-dmg-nightly.

  • signer-dmg-image now runs verify-signed-nightly's checks itself (scripts/ci/nightly-steps/signer-verify-signed.sh: version surfaces, the signed diff sidecar contract, check-signed-app.sh with the Computer Use helper ticket required, the bundled Ghostty theme picker regression, the SSH daemon contract), on a copy of the app it already holds.
  • Those checks and the existing signed-app checks start in the background after Apple's checks of the stapled app, run while the DMG is built and uploaded, and the job fails after the upload when any of them failed. signer-dmg needs signer-dmg-image, so it never signs a DMG whose app failed a check.
  • verify-signed-nightly runs for the macOS signer's app only. publish-nightly takes signer-dmg's success in its place for a pool-signed app (its if and its OWN_VERIFIED).
  • signer-dmg no longer packages or uploads the verify handoff; signer-handoff.sh is removed.

No check is dropped: verify-signed-nightly's codesign --verify --deep --strict is the first of signer-apple-checks.sh's checks, which the job runs before it starts the others. No secret reaches the Mac job. Nothing changes in build-nightly-app, prepare, or the macOS fallback signer path.

Performance

Chain = build-nightly-app end to publish-nightly end. The before rows are the last five arm64 pool-signed runs with a publish, from the jobs API. The after column is filled from real nightly-next runs once this lands.

metricbeforeafterdeltaharness or run link
verify stage, max(verify-signed, verify-final)3.2, 5.8, 2.8, 2.6, 2.5 minpendingexpected -0.0 to -3.9 min (verify-final alone: 3.0, 1.9, 2.8, 2.6, 1.9)runs 40893555177, 40905688542, 40909458084, 40913618519, 40918131595
verify-signed download of the signed app120-321 s0 (no second download)-120 to -321 s of office-link traffic per runsame runs
signer-dmg-image, checks then DMG3.0-5.5 min (checks 38-73 s run before the DMG)pendingexpected about -0.6 min (checks overlap the DMG build and upload)same runs
chain (build end to publish end)16.5, 17.9, 17.7, 15.4, 15.9 minpendingexpected about -1 to -4 minsame runs
Mac jobs per pool-signed run3 (dmg-image, verify-signed, verify-final)2-1nightly.yml job graph

Testing

  • python3 tests/test_nightly_signer_jobs.py: 20 tests pass, including new SignerVerifySigned tests that run the script with stub checks (every check runs on a copy; a failure fails finish after the rest ran; bundled-assets and CLI flags match verify-signed-nightly; nothing a check writes reaches the app the DMG is built from) and the wiring test for the new step order.
  • python3 tests/test_nightly_step_coverage.py and python3 tests/test_nightly_next_recovery.py pass.
  • Every other tests/test_*nightly* / workflow test that reads nightly.yml passes here, except tests/test_nightly_next_arm64_only.py and tests/test_check_ghostty_zig_workflows.py, which fail the same way on base in this Linux environment (a git rev-parse outside a repo; no bashlex).

Observed / Not run

Observed: the tests above on Linux. Not run: a real nightly-next run with this change; the first runs after it lands fill the Performance table.

Changelog

none

šŸ¤– Generated with Claude Code

Agent session: agent session