Skip to content

ci(cli): add macOS code signing with rcodesign#5675

Merged
avallete merged 3 commits into
developfrom
claude/eloquent-heisenberg-d0cr8x
Jun 24, 2026
Merged

ci(cli): add macOS code signing with rcodesign#5675
avallete merged 3 commits into
developfrom
claude/eloquent-heisenberg-d0cr8x

Conversation

@avallete

@avallete avallete commented Jun 24, 2026

Copy link
Copy Markdown
Member

Implement Phase 1 of macOS code signing to fix the SIGKILL issue on macOS 26+ (CLI-1621). The Bun SFE and Go sidecar binaries are now signed with a full ad-hoc signature during the build pipeline, replacing the degenerate linker-signed signature that AMFI rejects.

Changes

  • Build pipeline signing: Added signDarwinBinaries() and resolveSignMode() to apps/cli/scripts/build.ts to sign macOS binaries (supabase and supabase-go) with rcodesign between compilation and archiving. This ensures all distribution channels (npm, Homebrew, GitHub Releases) ship the signed bytes.

  • CI integration: Updated .github/workflows/build-cli-artifacts.yml to install rcodesign v0.29.0 (pinned with sha256), set SUPABASE_CLI_REQUIRE_SIGNING=1 to enforce signing in release builds, and verify signatures post-build using rcodesign print-signature-info.

  • Smoke test verification: Extended apps/cli/tests/smoke-test-macos.ts with native signature verification via new verifyMacSignature() helper in apps/cli/tests/helpers/macos-signature.ts. On macOS runners, this checks the signature is valid, carries the correct identifier (com.supabase.cli / com.supabase.cli-go), and is no longer linker-signed.

  • Documentation: Added ADR 0013 documenting the decision, rationale, and Phase 2 roadmap (Developer ID + notarization). Updated release-process.md and binary-distribution.md to describe the signing step and its role in the release pipeline.

Implementation details

  • No Apple credentials required for Phase 1: Full ad-hoc signatures are self-contained and do not require an Apple Developer ID. This fixes the SIGKILL without blocking on account provisioning.

  • Linux-only signing: rcodesign runs on the existing Linux build runner, avoiding a macOS job and pipeline split. Verification happens on macOS smoke-test runners.

  • Graceful degradation: Local builds without rcodesign warn and skip signing (unless SUPABASE_CLI_REQUIRE_SIGNING=1 is set), allowing contributors to build unsigned binaries for testing.

  • Identifiers: com.supabase.cli for the Bun SFE, com.supabase.cli-go for the Go sidecar, configured in MACOS_IDENTIFIERS map.

See ADR 0013 for full context, Phase 2 roadmap (Developer ID + notarization), and related follow-ups (Windows Authenticode, Linux cosign).

Related #5556

https://claude.ai/code/session_01GnLjngbm48rMYVwn9Guduc

claude added 2 commits June 22, 2026 15:11
The released darwin binaries (Bun SFE and Go sidecar) carry only a
degenerate linker-signed ad-hoc signature (CS_ADHOC | CS_LINKER_SIGNED,
identifier `a.out`, no requirements blob). macOS 26/27 AMFI rejects this
and SIGKILLs the process at launch (CLI-1621 / #5556).

Re-sign both darwin binaries with a full ad-hoc signature in the build
pipeline using rcodesign on the Linux build runner — the same signature
shape `codesign --sign -` produces, requiring no Apple credentials. The
signed bytes flow into every channel (npm platform packages, Homebrew,
GitHub Release archives, checksums) since they all consume the same
packages/cli-*/bin/ binaries.

- build.ts: resolveSignMode() + signDarwinBinaries() between compile and
  archive; asserts the signature carries our identifier and is no longer
  linker-signed. SUPABASE_CLI_REQUIRE_SIGNING=1 hard-fails when rcodesign
  is missing; local builds warn and skip.
- build-cli-artifacts.yml: install pinned rcodesign, require signing, and
  verify darwin signatures.
- smoke-test-macos.ts + macos-signature.ts: verify signatures on the
  macOS smoke-test runners (ad-hoc now; Developer ID + Gatekeeper
  quarantine branch ready for Phase 2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GnLjngbm48rMYVwn9Guduc
Add ADR 0013 (macOS code signing & notarization) recording that ADR
0011's contingent follow-up A trigger fired, the rcodesign-on-Linux
decision, the two-phase rollout, identifiers, secret names, and the
no-staple rationale. Amend ADR 0011's signing row and follow-up A to
point to it.

Add a "Code signing (macOS)" section to release-process.md documenting
the required pre-release gate: a staged dry_run release must show the
macOS smoke legs green before any real cut, since signing is produced on
Linux and only macOS can confirm AMFI accepts it. Note signing in
binary-distribution.md's release workflow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GnLjngbm48rMYVwn9Guduc
@avallete avallete requested a review from a team as a code owner June 24, 2026 09:05
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

…isenberg-d0cr8x

# Conflicts:
#	.github/workflows/build-cli-artifacts.yml
#	apps/cli/docs/release-process.md
@github-actions

Copy link
Copy Markdown

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@03293273a6000572200238cc925cba326cec3f19

Preview package for commit 0329327.

@avallete avallete enabled auto-merge June 24, 2026 10:56

@Coly010 Coly010 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work 🎉 few things that claude highlighted just, nothing blocking though.

The CI signature check can let a mis-signed sidecar through. In the "Verify macOS signatures" step, grep -q 'identifier: com.supabase.cli' is a substring match, so it matches com.supabase.cli-go too. So if supabase-go ever got signed with com.supabase.cli by mistake, this would happily pass it — which kinda defeats the point of separate identifiers. Could we pick the expected id per binary and anchor the grep (com.supabase.cli$ vs com.supabase.cli-go$)?

signDarwinBinaries is reaching back into the module-level shell. The binary list is gated on if (shell === "legacy") reading the script-level const instead of anything passed in. Works fine today, but it's a little easy to miss, and it'll quietly need a tweak if the next shell ever gets a second sidecar. I'd just pass shell (or the resolved binary list) in as an arg so the function stands on its own.

The identifiers live in three places. MACOS_IDENTIFIERS in build.ts, EXPECTED_IDENTIFIERS in the test helper, and the hard-coded string in the workflow yaml — and nothing keeps them in sync. If one drifts we'd sign with one id and verify against another and only catch it on the macOS legs. Pulling them into one shared module that build.ts and the helper both import (and ideally pointing the CI check at the same thing) means one place to change — and it basically fixes the first point for free.

None of this blocks the actual fix though — the sign-on-Linux / verify-on-macOS approach looks solid.

@avallete avallete added this pull request to the merge queue Jun 24, 2026
Merged via the queue into develop with commit 71338e6 Jun 24, 2026
21 checks passed
@avallete avallete deleted the claude/eloquent-heisenberg-d0cr8x branch June 24, 2026 12:07
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.

3 participants