Repository navigation
Build, sign, and notarize binaries on Buildkite - #56
Conversation
fastlane will fetch the Developer ID certificate and sign and notarize the macOS binaries on Buildkite. `.xcode-version` selects the Buildkite agent image. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same lanes as the Day One CLI, so Automattic's CLIs sign the same way. `sign_macos_binaries` keeps the `binaries.json` contract of `sign-macos-binaries.ts`: it updates the macOS checksums after signing, so the npm and Homebrew publish steps read the manifest unchanged. No explicit signing identifier: the CLI never touches the Keychain, and the file-name default matches what 0.6.2 shipped with. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Releases had to come from Batuhan's Mac, the only machine with the signing secrets. The step builds all four binaries on one Mac agent, since Bun cross-compiles the Linux ones, so a release's artifacts come from one place. It publishes nothing: the npm and Homebrew steps read the archived `binaries.json` and binaries. The binaries go into a tarball because Buildkite artifacts drop the executable bit. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`build-homebrew-archive.ts` reads each binary from the absolute `path` in `binaries.json`, which only exists on the agent that built it. Archiving downstream from the uploaded binaries would fail, so the job now builds the same archives, `homebrew.json`, and `binaries.json` a GitHub Release carries. Flagged by Codex review. --- Generated with the help of Claude Code, https://code.claude.com Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
AliSoftware
left a comment
There was a problem hiding this comment.
Downloaded the mac arm64 zip, unzipped it, and checked:
$ codesign -dvv "/Users/olivierhalligon/Downloads/bin/beeper"
Executable=/Users/olivierhalligon/Downloads/bin/beeper
Identifier=beeper-darwin-arm64
Format=Mach-O thin (arm64)
CodeDirectory v=20500 size=231615 flags=0x10000(runtime) hashes=7232+2 location=embedded
Signature size=9052
Authority=Developer ID Application: Automattic, Inc. (PZYM8XX95Q)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=30 Oct 2026 at 03:59:08
Info.plist=not bound
TeamIdentifier=PZYM8XX95Q
Runtime Version=15.2.0
Sealed Resources=none
Internal requirements count=1 size=180
$ "/Users/olivierhalligon/Downloads/bin/beeper" --version
@beeper/cli/0.6.2 darwin-arm64 node-v24.3.0
I left a note about how our way to install bun on CI is not idea in terms of security, but since this is the official way documented by Bun themselves, not sure if there are other solutions they provide…
| fi | ||
|
|
||
| echo "--- :bun: install Bun $bun_version" | ||
| curl -fsSL https://bun.sh/install | bash -s "bun-v$bun_version" |
There was a problem hiding this comment.
I wish there were a safer way to install a specific version of bun on the Mac; because curl … | bash doesn't feel super secure (the shell script we curl and run could end up being compromised one day…)
Any other, safer alternatives?
There was a problem hiding this comment.
Good point! Tracked in https://linear.app/a8c/issue/AINFRA-3562
Closes AINFRA-3535.
Builds all four binaries on Buildkite and signs and notarizes the two macOS ones with the Automattic Developer ID, so any team member can cut a release, not just from Batuhan's Mac.
Each build saves the files a GitHub Release needs as artifacts: the four archives,
homebrew.json, andbinaries.json. They come frombuild-homebrew-archive.ts, so the layout matchespackages/cli/dist/.The build publishes nothing.
Tradeoffs
fastlane/Fastfile), the same as our other CLIs, instead ofsign-macos-binaries.ts.sign_macos_binarieskeeps the script's contract: it signs everydarwin-*entry inbinaries.jsonand rewrites its checksum.beeper-darwin-<arch>, hardened runtime, no entitlements.I checked that a locally signed build still runs under the hardened runtime.
Publishing from a build
From the repo root, at the commit Buildkite built:
How to test
Build 2 notarized both macOS binaries. Gatekeeper accepts the downloaded arm64 one as
Notarized Developer ID. Download the macOS arm64 zip, unzip it, then runcodesign -dvv bin/beeperandbin/beeper --version.