Skip to content

Commit 4f133c5

Browse files
committed
build(release): notarize macos cli binaries
1 parent f46454b commit 4f133c5

5 files changed

Lines changed: 88 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,8 @@ jobs:
5353
args: release --clean --config .goreleaser.yaml
5454
env:
5555
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56+
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
57+
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
58+
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
59+
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
60+
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}

.goreleaser.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,20 @@ archives:
3232
- goos: windows
3333
format: zip
3434

35+
notarize:
36+
macos:
37+
- enabled: '{{ and (isEnvSet "MACOS_SIGN_P12") (isEnvSet "MACOS_NOTARY_ISSUER_ID") (isEnvSet "MACOS_NOTARY_KEY_ID") (isEnvSet "MACOS_NOTARY_KEY") }}'
38+
ids:
39+
- zen
40+
sign:
41+
certificate: "{{ .Env.MACOS_SIGN_P12 }}"
42+
password: "{{ .Env.MACOS_SIGN_PASSWORD }}"
43+
notarize:
44+
issuer_id: "{{ .Env.MACOS_NOTARY_ISSUER_ID }}"
45+
key_id: "{{ .Env.MACOS_NOTARY_KEY_ID }}"
46+
key: "{{ .Env.MACOS_NOTARY_KEY }}"
47+
wait: true
48+
timeout: 20m
49+
3550
checksum:
3651
name_template: checksums.txt

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
- groups and users helper commands
1515
- JSON and plain TSV output modes
1616
- Makefile, CI workflow, and GoReleaser config
17+
- GitHub Release flow for signed and notarized macOS CLI binaries
1718
- usage, auth, development, and release documentation
1819
- MIT license

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ Public replies are intentionally not supported by this workflow unless code expl
5656

5757
Choose one of the following options.
5858

59-
### Option A: Build locally
59+
### Option A: Download a release binary
60+
61+
Download the archive for your platform from GitHub Releases, extract it, and place `zen` somewhere on your `PATH`.
62+
63+
For macOS releases, the published CLI binaries are intended to be signed and notarized by the release workflow.
64+
65+
### Option B: Build locally
6066

6167
```bash
6268
git clone <your-repo-url>
@@ -70,7 +76,7 @@ This builds the binary to:
7076
./bin/zen
7177
```
7278

73-
### Option B: Plain `go build`
79+
### Option C: Plain `go build`
7480

7581
```bash
7682
go build -o ./bin/zen ./cmd/zen

docs/releasing.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This repo includes a GitHub Actions release workflow and a GoReleaser config.
99
3. create a semver tag
1010
4. push the tag
1111
5. GitHub Actions builds release archives and checksums
12+
6. macOS release binaries are signed and notarized when the Apple secrets are configured
1213

1314
## Example
1415

@@ -30,6 +31,51 @@ Configured in GoReleaser:
3031
- darwin amd64 / arm64
3132
- windows amd64 / arm64
3233

34+
## macOS signing and notarization
35+
36+
This repo is configured to sign and notarize the `darwin` CLI binaries during the normal GitHub Releases flow.
37+
38+
The GoReleaser notarization block is enabled only when all required Apple secrets are present in GitHub Actions.
39+
40+
### Apple prerequisites
41+
42+
You need:
43+
44+
- an Apple Developer account
45+
- a `Developer ID Application` certificate exported as `.p12`
46+
- the password for that `.p12`
47+
- an App Store Connect API key exported as `.p8`
48+
- the App Store Connect key ID
49+
- the App Store Connect issuer ID
50+
51+
### GitHub Actions secrets
52+
53+
Add these repository or organization secrets before cutting a release:
54+
55+
- `MACOS_SIGN_P12` — base64-encoded `.p12` certificate contents
56+
- `MACOS_SIGN_PASSWORD` — password for the `.p12` (may be empty if you exported the `.p12` without one)
57+
- `MACOS_NOTARY_KEY` — base64-encoded `.p8` App Store Connect key contents
58+
- `MACOS_NOTARY_KEY_ID` — App Store Connect key ID
59+
- `MACOS_NOTARY_ISSUER_ID` — App Store Connect issuer UUID
60+
61+
Example base64 commands:
62+
63+
```bash
64+
base64 < Certificates.p12 | tr -d '\n'
65+
base64 < ApiKey_ABC123XYZ.p8 | tr -d '\n'
66+
```
67+
68+
### Release result
69+
70+
When those secrets are present:
71+
72+
- Linux and Windows artifacts are built as before
73+
- macOS `amd64` and `arm64` binaries are signed before packaging
74+
- the macOS binaries are submitted to Apple for notarization
75+
- the notarized binaries are the ones included in the release archives
76+
77+
If the secrets are not present, the release still works, but macOS artifacts will be unsigned and unnotarized.
78+
3379
## Manual re-release
3480

3581
The workflow also supports `workflow_dispatch` with a tag input, for example:
@@ -46,8 +92,21 @@ If you want local GoReleaser snapshots, install GoReleaser and run:
4692
goreleaser release --snapshot --clean
4793
```
4894

95+
If the Apple environment variables are exported locally, the same config can sign and notarize macOS snapshot binaries as well.
96+
4997
## Notes
5098

5199
- release archives are named `zencli_<version>_<os>_<arch>`
52100
- Windows artifacts are zipped
53101
- other platforms are archived as `.tar.gz`
102+
- notarization is configured for standalone CLI binaries, not app bundles or `.pkg` installers
103+
104+
## Verifying a downloaded macOS binary
105+
106+
After downloading and extracting a macOS release archive:
107+
108+
```bash
109+
codesign --verify --verbose ./zen
110+
spctl --assess --type execute --verbose ./zen
111+
xattr -p com.apple.quarantine ./zen 2>/dev/null || true
112+
```

0 commit comments

Comments
 (0)