Skip to content

Sign and notarise macOS release binaries #65

Description

@jamessawle

Problem

sbxflow's macOS binaries are neither code-signed nor notarised. The published cask works around this with a postflight hook that strips the quarantine attribute on install:

postflight do
  if OS.mac?
    system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/sbxflow"]
  end
end

That is GoReleaser's documented fallback, and #64 added a caveats stanza so users are told it happens. But it is a fallback, not a fix. From GoReleaser's own cask documentation:

Casks are supposed to be signed, even if they are coming from a tap.

Clearing the quarantine flag bypasses Gatekeeper on the user's behalf. Users have no way to verify the binary came from this project, and the approach depends on Apple continuing to permit it.

What proper notarisation needs

This is a decision as much as a task, because it carries a recurring cost:

  • An Apple Developer Program membership — Apple charges an annual fee. GoReleaser's documentation calls this out as the reason the quarantine workaround exists.
  • A Developer ID Application certificate, plus either an app-specific password or an App Store Connect API key.
  • Those credentials stored as repository secrets, which widens the release workflow's secret surface beyond the existing HOMEBREW_TAP_GITHUB_TOKEN.
  • GoReleaser configuration in its notarize section.

Acceptance criteria

  • Published macOS archives contain a signed, notarised executable that passes spctl assessment.
  • The cask no longer needs the postflight quarantine hook, and the hook is removed.
  • The caveats stanza describing the binary as unsigned is removed.
  • A clean brew install --cask jamessawle/tap/sbxflow on a machine that has never run sbxflow produces a working executable, satisfying the release-distribution requirement "Installed macOS executables run without manual intervention" without bypassing Gatekeeper.
  • The release runbook documents certificate rotation and what to do when notarisation fails.

Not blocking

The current cask installs and runs, and discloses what it does. This is a security-posture improvement gated on a paid membership, so it is a deliberate decision rather than outstanding work. Close it as wontfix if the cost is not worth it for this project — that is a legitimate outcome, and the caveats stanza keeps the trade-off visible to users either way.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions