Skip to content

ci: build darwin releases with cgo so macOS Keychain backend is present [INT-446]#164

Merged
rianjs merged 1 commit into
mainfrom
fix/INT-446-darwin-cgo-keychain
May 19, 2026
Merged

ci: build darwin releases with cgo so macOS Keychain backend is present [INT-446]#164
rianjs merged 1 commit into
mainfrom
fix/INT-446-darwin-cgo-keychain

Conversation

@rianjs
Copy link
Copy Markdown
Collaborator

@rianjs rianjs commented May 19, 2026

Problem

Released slck macOS binaries fail closed on every credential op. .goreleaser.yaml set CGO_ENABLED=0 and the release job ran on ubuntu-latest; 99designs/keyring's Keychain backend is //go:build darwin && cgo, so with cgo off it was never compiled in. On macOS credstore auto-selects the Keychain backend then keyring.Open returns ErrNoAvailImpl → fail-closed. Every Mac user who upgraded since the credstore migration (#158) is broken. Verified macOS-only (Windows wincred and Linux godbus secret-service are pure Go, fine under CGO_ENABLED=0).

Fix (pipeline-only — no Go source change)

  • .goreleaser.yaml: split builds — slck-darwin (CGO_ENABLED=1, fully-keyed per-arch CC=xcrun clang -arch … overrides for darwin_amd64_v1 / darwin_arm64_v8.0) + slck-unix-win (CGO_ENABLED=0 static). nfpms.ids: [slck-unix-win] (not the deprecated builds). Both macOS arches (Intel + Apple Silicon) still produced — the split is by GOOS, not arch.
  • release.yml: goreleaser job → pinned macos-15 (cgo+darwin can't cross-compile from Linux). Restructured to verify before publish: goreleaser checkrelease --snapshot (no publish) → pre-publish gate → real release --clean --release-notes. The gate parses dist/artifacts.json and asserts: arm64 binary functionally reports backend=keychain backend_source=auto credential_ref=slack-chat-api/default (isolated HOME/XDG, -u SLACK_CHAT_API_KEYRING_BACKEND); amd64 binary links Security.framework (necessary cgo signal for the slice the runner can't execute); both darwin archives present exactly once. A backend-less darwin binary can no longer be published silently.
  • Hardened the update-homebrew checksum step (set -euo pipefail + non-empty SHA assertions) so a renamed/missing archive can't publish a broken cask.

Non-goals

  • No cgo on linux/windows (glibc portability regression, zero benefit — pure-Go backends).
  • No runtime env credential fallback (would unwind the §1.11 keyring-only invariant).
  • The pre-existing workflow_dispatch TAG: github.ref_name || inputs.tag bug is out of scope (only affects the dispatch path; this fix uses the tag-push path) — separate ticket.

Validation

goreleaser check passes; both cgo cross-builds succeed locally (arm64 native + amd64 cross, correct Mach-O archs, amd64 links Security.framework); the gate's functional assertion reproduced on real hardware (backend=keychain/auto).

Release mechanics

auto-release.yml Gate-1 is a path filter (**.go|go.mod|go.sum); a pipeline-only diff matches none, so this is a ci: commit that does not auto-release. After merge the corrected release is cut by a deliberate annotated tag push (release.yml on: push: tags: v*).

Pilot for the cross-CLI CGO regression (Jira INT-446, child of INT-310); verified on a non-dev Mac before any fan-out to nrq/gro/atlassian.

Closes #163

…resent [INT-446]

Release binaries were built CGO_ENABLED=0 on ubuntu-latest, so
99designs/keyring's `//go:build darwin && cgo` Keychain backend was never
compiled in and credstore failed closed on macOS for every user who
upgraded since the credential-store migration.

Split the goreleaser build: darwin builds with CGO_ENABLED=1 (fully-keyed
per-arch CC overrides) on a pinned macos-15 runner; linux/windows stay
CGO-off static (their backends are pure Go; cgo there would regress glibc
portability). Verify before publish: `goreleaser check`, snapshot build,
then a pre-publish gate that proves the darwin binaries carry the Keychain
backend (arm64 functional config-show check; amd64 Security.framework link
check) and that both darwin archives exist exactly once — a backend-less
darwin binary can never be published silently. Harden the Homebrew
checksum step against empty SHAs.

No Go source change. Both macOS arches (Intel + Apple Silicon) still
produced.

Closes #163
@rianjs
Copy link
Copy Markdown
Collaborator Author

rianjs commented May 19, 2026

Findings

  • None.

The PR adheres to the converged INT-446 plan. The diff is scoped to .goreleaser.yaml and release.yml; no unrelated code or product behavior crept in. GoReleaser split is correct: darwin is CGO-on with fully keyed overrides and quoted CC, linux/windows remain CGO-off, nfpms.ids targets the non-darwin build, and archives remain unfiltered with disjoint GOOS sets.

The pre-publish gate is sound: snapshot build happens before publish, artifact lookup uses artifacts.json by type/OS/arch, arm64 proves keychain/auto through the shipped binary under isolated HOME/XDG, amd64 gets the necessary Security.framework check, and release notes are verified with GH_TOKEN. Bash is macOS-safe: no Bash 4 constructs, set -euo pipefail is present, heredoc and $RUNNER_TEMP are quoted, and Homebrew checksum parsing now fails before writing empty SHAs. GoReleaser Action supports version: "~> v2" and install-only per its docs.

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.

slck macOS binaries fail closed: CGO_ENABLED=0 strips the Keychain backend [INT-446]

1 participant