Repository navigation
ci(release): notarize the shipped macOS binaries - #2003
Merged
norrietaylor merged 4 commits intoOct 6, 2026
Merged
Conversation
After signing, build-release-macos-arm64 now submits min, minvmd and min-answerer to the Apple notary service with `xcrun notarytool submit --wait`, each in a ditto zip used only for the submission. The release fails unless every result is Accepted, and the step prints the notary log of a rejected submission. The release ships bare Mach-O files, which stapler cannot staple, so Gatekeeper looks the ticket up online. Credentials come from a notarytool keychain profile in the signing keychain, named by the MACOS_NOTARY_PROFILE repository variable. The job timeout rises from 45 to 60 minutes to cover the notary waits. Document the step and its runner prerequisites in release-pipeline.md.
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
# Conflicts: # docs/internal/release-pipeline.md
Contributor
|
Approved: no findings at Nothing to do. Clobber: none: |
jtnkminimal
approved these changes
Oct 6, 2026
yermakoffivan
pushed a commit
to yermakoffivan/minimal
that referenced
this pull request
Oct 7, 2026
…very platform (gominimal#2002) * ci(release): ship min-answerer signed for every platform The build, staging, packaging and install scripts already handle min-answerer (gominimal#1971), but the release workflow never built, signed or uploaded it, so stage-release.sh and package-nfpm.sh skipped it with a warning. Linux: rename the min-answerer artifacts dist-build.sh already builds, re-run scripts/check-answerer-links.sh on the renamed files and upload them as min-answerer-linux-{amd64,arm64}. macOS: build min-answerer in its own -p min-answerer invocation, link-gate it, rename it, Developer-ID sign it (hardened runtime, timestamp, no entitlements, identifier dev.minimal.min-answerer), verify it against the designated requirement min checks, re-run the link gate on the signed bytes and upload it as min-answerer-macos-arm64. Pass MINIMAL_ANSWERER_TEAMID and MINIMAL_ANSWERER_IDENTIFIER as job env to the macOS build so the min it builds carries that identity. * docs(release): describe min-answerer as built, signed and uploaded by the workflow The release workflow now builds, link-gates, signs and uploads min-answerer, so the pipeline doc no longer calls it a pending code-owner patch or a gap. * refactor: rename min-answerer to minzoned The host box-zone service binary becomes minzoned, matching minimald and minvmd. It holds the box zone: the box names and the addresses behind them, so a dns name would be too narrow once address arbitration lands. The name stays narrow on purpose: a privileged, config-less service should not invite more functions. - crate, package and binary: crates/minzoned, minzoned - launchd label dev.gominimal.zone, systemd units minzoned.socket and minzoned.service - root-owned copies /Library/PrivilegedHelperTools/minzoned and /usr/local/lib/minimal/minzoned - codesign identifier dev.minimal.minzoned; compile-time env MINIMAL_ZONED_TEAMID and MINIMAL_ZONED_IDENTIFIER - release artifacts minzoned-{linux-amd64,linux-arm64,macos-arm64} - scripts/check-zoned-links.sh (and its test), just zoned-build and zoned-link-check - advisory lead-in: install the Minimal box-name service (DNS and addresses for boxes) * ci(release): build, sign and ship the box-name service as minzoned Follows the rename of min-answerer to minzoned: the artifact names, the link check script, the cargo package and binary, the signing identifier dev.minimal.minzoned and the MINIMAL_ZONED_* build env that min compiles in. * test(e2e): match the renamed box-name service in the session e2e The advisory command now installs minzoned, so the e2e's answerer-step matches look for minzoned instead of the old zone-answerer label. The install test's root-owned-path guard names the new program and plist paths. Daemon log greps keep the zone-answerer component name. * ci(release): notarize the shipped macOS binaries (gominimal#2003) After signing, build-release-macos-arm64 now submits min, minvmd and min-answerer to the Apple notary service with `xcrun notarytool submit --wait`, each in a ditto zip used only for the submission. The release fails unless every result is Accepted, and the step prints the notary log of a rejected submission. The release ships bare Mach-O files, which stapler cannot staple, so Gatekeeper looks the ticket up online. Credentials come from a notarytool keychain profile in the signing keychain, named by the MACOS_NOTARY_PROFILE repository variable. The job timeout rises from 45 to 60 minutes to cover the notary waits. Document the step and its runner prerequisites in release-pipeline.md. * test(minzoned): prove the macOS service install on a hosted runner (gominimal#2011) * test(minzoned): prove the macOS service install on a hosted runner The self-hosted Mac fleet runs PR code without sudo, so the minzoned LaunchDaemon path had no CI proof. A new zoned job on macos-latest runs the privileged install command min prints, then checks custody, the system resolver, the channel (a script stands in for the node), the uid gate, a restart, a re-run and a clean teardown. A hidden debug-only verb, min debug-answerer-command, prints the command without a session. * test(minzoned): wait for the range job to apply every alias * fix(scripts): spell the zoned restart check as an if so shellcheck passes * docs(scripts): say release.yml now ships minzoned in the optional-artifact notes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #2002, which ships
minzoned; the base is that PR's branch. Merge #2002 first.The release workflow signs every shipped macOS binary with the Developer ID but notarizes none of them. A binary that a user runs from a downloaded file can therefore fail Gatekeeper's notarization check. This PR closes that gap for
min,minvmdandminzoned..github/workflows/release.yml(jobbuild-release-macos-arm64)minzonedlink gate, before the uploads. For each of the three binaries, the step:ditto -c -k --keepParent, becausenotarytooltakes a zip,.pkgor.dmgand not a bare Mach-O; the zip is used only for the submission;xcrun notarytool submit --wait --timeout 15m --output-format json;statusfrom the JSON and fails the release unless it isAccepted; on any other result, or if the submission itself failed, it printsxcrun notarytool log <id>.kind filerows inscripts/stage-release.sh, installed tobin/).staplercan attach a ticket only to an app bundle, a.pkgor a.dmg, so the workflow cannot staple these; Gatekeeper looks the ticket up online.notarytoolkeychain profile in the existing signing keychainminimal-signing.keychain-db. The step unlocks that keychain with the existingKC_PWsecret and passes it with--keychain. The repository variableMACOS_NOTARY_PROFILEnames the profile; the workflow had no notary convention before this. If the variable is empty, the step fails before submitting anything.timeout-minutesrises from 45 to 60. The build takes about 15 minutes, and the notary waits come on top of that.docs/internal/release-pipeline.md: documents the step, why it does not staple, and its prerequisites. The doc also no longer points to a private tracker.Not in scope:
libkrun.1.dyliband the macOSgvproxy, whichsign-macos-artifactssigns, are still not notarized. The doc says so.Runner setup a human must do before merge
xcrun notarytool history --keychain-profile <profile> --keychain ~/Library/Keychains/minimal-signing.keychain-db.gh variable set MACOS_NOTARY_PROFILE --body <profile> --repo gominimal/minimal.Until steps 1 and 3 are done, every release run with
RUN_MACOS_CInotfalsefails at this step.Validation
actionlint .github/workflows/release.yml: clean.zizmor --offline .github/workflows/release.yml: no findings.python3(yaml.safe_load).run:script and checked it withbash -nandshellcheck: clean.xcrunandsecurity, using realdittoandplutil:Accepted: exit 0;Invalid: exit 1, error annotation, notary log printed;notarytool submitandnotarytool logaccept--keychain, and thatplutil -extract … rawreads the JSON output.just lint-prose docs/internal/release-pipeline.md: 0 alerts.Review
This PR edits a frozen, CODEOWNER-gated workflow. A code owner reviews and merges it, after #2002.