Skip to content

Feat/macos notarize#24

Closed
gok03 wants to merge 2 commits into
mainfrom
feat/macos-notarize
Closed

Feat/macos notarize#24
gok03 wants to merge 2 commits into
mainfrom
feat/macos-notarize

Conversation

@gok03
Copy link
Copy Markdown
Contributor

@gok03 gok03 commented May 19, 2026

What

Why

Closes #

How

Test plan

  • go test ./... passes
  • go vet ./... clean
  • golangci-lint run clean (if applicable)
  • Manually tested:

Checklist

  • Added or updated tests
  • Updated README / docs for user-visible changes
  • Updated CHANGELOG.md under [Unreleased]
  • No new third-party Go dependencies (or, if there are, justified above)

gok03 added 2 commits May 19, 2026 17:38
…er ID

Apple Gatekeeper currently blocks first-launch of the macOS binaries with
"Apple could not verify 'refuse' is free of malware…" because the
artifacts are unsigned. Fix by signing with the Developer ID Application
certificate and submitting to Apple's notary service.

Implementation:
  - `.goreleaser.yaml` gains a `notarize.macos:` block, gated on
    `{{ isEnvSet "MACOS_SIGN_P12" }}` so forks without the secrets get a
    clean no-op rather than an error. Goreleaser's notarize step shells
    out to rcodesign (bundled), so the work runs on a Linux runner — no
    macOS runner needed.
  - `.github/workflows/release.yaml` exports the 5 secrets goreleaser
    reads at template time:
      MACOS_SIGN_P12             — base64 of the .p12 cert
      MACOS_SIGN_PASSWORD        — password the .p12 was exported with
      MACOS_NOTARY_KEY           — base64 of the App Store Connect .p8 key
      MACOS_NOTARY_KEY_ID        — 10-char Key ID from App Store Connect
      MACOS_NOTARY_ISSUER_ID     — UUID Issuer ID from App Store Connect

After this lands, the next tag push produces darwin binaries that are
signed by your Developer ID and stapled with an Apple notarization
ticket. `brew install refusehq/tap/refuse` (and direct .tar.gz
downloads) launch without the Gatekeeper dialog.
goreleaser's built-in `notarize.macos` block fails on Apple Developer ID
certificates with:

  failed to verify certificate chain: x509: unhandled critical extension

because Go's stdlib x509 verifier doesn't recognise Apple's critical
extension OIDs (e.g. 1.2.840.113635.100.6.1.13 for Developer ID
Application). Replace it with `rcodesign` (Rust) which handles them
correctly.

Pipeline shape:

  1. release.yaml downloads + installs the rcodesign binary on the
     ubuntu-latest runner before goreleaser runs.
  2. .goreleaser.yaml drops the broken `notarize:` block. Instead,
     `builds.hooks.post` invokes scripts/sign-macos.sh once per built
     binary, which signs darwin binaries with rcodesign +
     --code-signature-flags runtime. Non-darwin builds and missing
     secret = silent no-op.
  3. After goreleaser finishes (archives + checksums + cosign + sbom),
     release.yaml runs scripts/notarize-macos.sh against dist/, which
     re-zips each darwin binary, submits to Apple's notary API via the
     App Store Connect key, and waits for approval.

We don't staple — stapling only works on bundles/.pkg/.dmg, and a plain
Mach-O CLI binary can't carry a ticket. Apple records notarization
server-side and Gatekeeper online-queries at first launch, which is
sufficient for a CLI.

Both scripts are env-gated: forks and snapshot builds without the
secrets pass through unchanged.
@gok03
Copy link
Copy Markdown
Contributor Author

gok03 commented May 19, 2026

Superseded by #20 (rcodesign sign+notarize) and #22 (cert chain fix). Both already merged to main.

@gok03 gok03 closed this May 19, 2026
@gok03 gok03 deleted the feat/macos-notarize branch May 19, 2026 13:22
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.

1 participant