Skip to content

fix(release): build macOS binaries on a native runner so they load on macOS 15+ - #178

Merged
zzet merged 1 commit into
mainfrom
fix/macos-release-native-darwin
Jun 27, 2026
Merged

fix(release): build macOS binaries on a native runner so they load on macOS 15+#178
zzet merged 1 commit into
mainfrom
fix/macos-release-native-darwin

Conversation

@zzet

@zzet zzet commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Problem

The 0.52.2 Homebrew cask aborts at load on macOS Sequoia / Tahoe (fixes #176):

dyld: __DATA_CONST segment missing SG_READ_ONLY flag in .../Caskroom/gortex/0.52.2/gortex
[1]    abort      gortex --version

macOS 15+ dyld now enforces the SG_READ_ONLY (0x10) flag on the __DATA_CONST segment. darwin was cross-compiled inside goreleaser-cross, whose osxcross ld64 omits that flag. Apple's ld sets it — so locally built binaries (make build) always worked and the bug only ever surfaced in the released artifact (which is why it couldn't be reproduced locally).

Fix

Build darwin on a native macos-15 runner where Apple's ld sets the flag:

  • New build-darwin job: links arm64 natively + amd64 via clang -arch x86_64, codesigns with rcodesign, smoke-tests the segment flag, and runs gortex version on the enforcing dyld (the exact 0.52.2 brew cask binary broken for macos #176 repro) before handing off the tar.gz archives.
  • The release job now builds linux only, merges the darwin tarballs, notarizes, appends them to checksums.txt, cosign-signs, uploads, and feeds SLSA.

goreleaser's prebuilt builder is Pro-only, so the homebrew cask (which references all four os/arch tarballs) is assembled and pushed to zzet/homebrew-tap from the release job once every platform's hash exists, instead of by goreleaser. generate_completions_from_executable still runs at brew-install time, so nothing needs to execute at release time.

Smoke test

scripts/verify-macho-readonly.sh asserts __DATA_CONST carries SG_READ_ONLY and fails the release if a darwin binary ships without it — so this can't regress. The build-darwin job also actually loads + runs the arm64 binary on the Sequoia runner.

Validation

  • goreleaser check ✓, YAML parse ✓, actionlint ✓ (only pre-existing SC2035 infos)
  • Smoke-test script verified: passes a flag-correct binary, rejects a forged flagless one
  • Cask generation produces Ruby identical to the goreleaser output (ruby -c OK); packaging + checksum-append logic tested

Notes for reviewers

  • MACOS_CERTIFICATE_P12 / _PASSWORD are now also consumed by the build-darwin job (signing moved there); the release job keeps only the notary key.
  • Runner is macos-15 specifically so the execution smoke test runs under the enforcing dyld. On macos-14 (Sonoma) only the otool check would guard the flag.
  • This fixes future releases. To unbreak current users, cut a new patch tag so the cask points at correctly-linked binaries.

… macOS 15+

The 0.52.2 cask aborted at load on macOS Sequoia/Tahoe with
"__DATA_CONST segment missing SG_READ_ONLY flag" (#176). darwin was
cross-compiled inside goreleaser-cross, whose osxcross ld64 omits the
SG_READ_ONLY flag on the __DATA_CONST segment that the macOS 15+ dyld now
enforces. Apple's ld sets it, so locally built binaries always worked and
the bug only surfaced in the released artifact.

Build darwin on a native macos-15 runner instead:
- new build-darwin job links arm64 natively + amd64 via `clang -arch
  x86_64`, codesigns with rcodesign, smoke-tests the segment flag, and
  runs `gortex version` on the enforcing dyld before handing off archives.
- the release job now builds linux only, merges the darwin tarballs,
  notarizes, appends them to checksums.txt, signs, and uploads.

goreleaser's prebuilt builder is Pro-only, so the homebrew cask (which
references all four os/arch tarballs) is assembled and pushed to the tap
from the release job once every platform's hash exists, instead of by
goreleaser. Completions are still generated at brew-install time.

scripts/verify-macho-readonly.sh is the guard: it fails the release if a
darwin binary ships without SG_READ_ONLY, so this can never regress.
@zzet
zzet merged commit 0c937e2 into main Jun 27, 2026
9 checks passed
@zzet
zzet deleted the fix/macos-release-native-darwin branch June 27, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0.52.2 brew cask binary broken for macos

1 participant