ci(dev tip): sign, notarize and staple the tip DMG on Linux; the Mac only builds it
Leo: "I THOUGHT THESE COULD JUST GO ON LINUX" and "JUST FUCKING USE MORE LINUX FIX THE FUCKING BUILDS".
The DEV tip DMG job (tip-dmg, blacksmith-6vcpu-macos-26, 50 min timeout) held a Mac through DMG signing, the notary submit/wait (up to 30 min) and stapling. Only two parts need macOS: Apple's codesign --verify --deep --strict of the Linux-signed app and hdiutil create -format ULMO. This PR splits the job:
tip-dmg-build(Mac, blacksmith-6vcpu-macos-26, 20 min timeout, no environment, no secrets): reads the live feed (rollback guard), runs Apple codesign on the app, builds the unsigned DMG and uploads it under a per-attempt artifact name (cmux-next-dev-tip-unsigned-$GITHUB_RUN_ATTEMPT) with its sha256.tip-dmg(Linux, blacksmith-4vcpu-ubuntu-2404, environment release): checks that the DMG was built from the archive sign made (sha256 checks on both), thenscripts/ci/rcodesign-notarize-dmg-dev.shsigns it with stock rcodesign 0.29.0 (the same pinned install and PKCS#12-to-PEM handling asrcodesign-sign-bundle-dev.sh), notarizes it, and staples it (rcodesign notary-submit --staple).scripts/ci/tip_appcast_linux.pythen writes the full-DMG appcast. Its outputs (ready,run_tag,handoff) are unchanged, sotipandtip-deltasread it as before.tip-deltas(Mac, unchanged runner) gains a first step: Apple'scodesign --verify,xcrun stapler validateandspctl --assess --type open --context context:primary-signatureon the published DMG. That gives an Apple-tool check of the Linux-signed DMG on every run.
The guarantees from #25673 and #25706 still hold. tip is still the only R2 writer, and it still needs verify (verified == 'true') plus the tested digest. Every attempt uses its own object and artifact names. No concurrency groups. Every tip job is advisory (continue-on-error).
The appcast: Ed25519 is deterministic, so tip_appcast_linux.py produces the same signature Sparkle's generate_appcast makes for the same key and bytes. That matters because tip_feed.py add-deltas refuses deltas unless the regenerated item's url/length/signature match the published one. The script accepts a 32-byte seed or the old 96-byte key. It refuses an app whose CFBundleVersion isn't the build or whose SUPublicEDKey isn't the key's public half (both read from the signed archive the DMG was built from), and it checks the signature with openssl pkeyutl -verify. The test checks the signature byte for byte against openssl's for the same seed. Item layout follows the live feed.
Secrets: same names, same release environment. Blacksmith Linux is trusted like hosted runners. No new permissions or secrets. The Mac job now holds none.
Tests: tests/test_cmux_next_dev_tip_feed.py (updated for the split, plus appcast/signature/refusal cases), tests/test_ci_signing_keychain_is_deleted_before_bundle_code.py (tip-dmg registered as a Linux PEM signer), tests/test_nightly_delivery_concurrency.py (tip-dmg-build has no group). All three pass locally.
Mac minutes before/after: before, DMG + sign + notarize + staple + appcast took 8.8 to 9.8 min of blacksmith macOS per DEV run (tip job in runs 40390973550 and 40394072646). After, the Mac part is checkout + download + codesign verify + hdiutil. The real-run numbers go in a comment after the first DEV publish through this.
Risk: medium-low. Every tip job is advisory, so a failure leaves the feed on its last build and never blocks the rolling DEV prerelease. If rcodesign's DMG signature or staple were wrong, tip-deltas' Apple check would turn red on the first run, and reverting this PR restores the Mac path.
Agent session: agent session
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by CodeRabbit
- Improvements
- Nightly tip builds now publish signed, notarized, and stapled disk images, with a matching full-download update feed.
- Published disk images are checked before update deltas are generated, helping ensure downloads and updates meet Apple’s verification requirements.