bots-garden/sidekickspublic Fork
⑂ v1.0.0-macos
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/sidekicks.git
git clone ssh://git@rickub.com/bots-garden/sidekicks.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. 8990cef · on v1.0.0-macos · k33g · 2d ago
sign-and-notarize-on-macos.md · 176 lines · 9.3 KBmarkdown
Blame HistoryOpen raw

How to sign and notarize Sidekicks for macOS

This guide shows how to sign Sidekicks with a Developer ID certificate and have Apple notarize it, so that it opens on any Mac without Open Anyway. It assumes a paid Apple Developer Program membership of which you are the Account Holder (only that role can create a Developer ID certificate), an Apple Silicon Mac with the project's development tools (Develop the application), and a release built as RELEASING.md describes.

  • Part A is done once (allow 30 minutes).
  • Part B is done for every release, after make release-build, until signing is automated (issue #58). Allow 10 to 20 minutes, mostly waiting for Apple.

Keep a Terminal window open at the root of the repository.

What signing and notarizing do

Step Tool What it brings
Sign codesign with your Developer ID certificate macOS knows who made the app and that it was not changed
Hardened runtime codesign --options runtime required by Apple to notarize
Notarize xcrun notarytool Apple scans the app and issues a "ticket"
Staple xcrun stapler the ticket is attached to the app and the .dmg: Gatekeeper accepts them even offline

The app and the .dmg are signed, notarized and stapled. The .zip holds the stapled app.

Part A — once

A1. Note your Team ID

  1. Open developer.apple.com/account, Membership details.
  2. Note the Team ID (10 characters, e.g. AB12CD34EF).

A2. Create the Developer ID Application certificate

With Xcode (the simplest):

  1. Open Xcode → Settings… → Accounts. If it is not there, click +, choose Apple ID and sign in with the email address and password of your Apple Developer account (the Apple ID, not the Team ID).
  2. Your team shows under the account, with its Team ID: select it, click Manage Certificates….
  3. Click + at the bottom left, then Developer ID Application.

Without Xcode:

  1. Open Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…, give your address, tick Saved to disk. You get a .certSigningRequest file.
  2. On developer.apple.com/account/resources/certificates, choose Developer ID Application, profile G2 Sub-CA, upload the request, then download the certificate.
  3. Double-click the .cer file: it goes to the login keychain.

A3. Check that the certificate can be used

security find-identity -v -p codesigning

A line "Developer ID Application: First Last (AB12CD34EF)" must show. That is your signing identity: copy it exactly, without the quotes.

If it is missing, or shows CSSMERR_TP_NOT_TRUSTED, install the Developer ID - G2 intermediate certificate from apple.com/certificateauthority, then run the command again.

A4. Back up the certificate and its key

The private key only exists on this Mac: without a backup, a failure means revoking the certificate and making a new one.

  1. In Keychain Access, login keychain, My Certificates, unfold Developer ID Application: … (the key shows under it).
  2. Select the certificate, File → Export Items…, format .p12, choose a password.
  3. Keep the .p12 and its password in your password manager. Never put it in the repository.

A5. Create an app-specific password for notarization

  1. Open account.apple.com, Sign-In and Security → App-Specific Passwords.
  2. Create one called sidekicks-notary and copy it (it is not shown again).

A6. Store the notarization profile in the keychain

xcrun notarytool store-credentials sidekicks-notary \
  --apple-id "you@example.com" \
  --team-id "AB12CD34EF"

Paste the app-specific password when asked. Check:

xcrun notarytool history --keychain-profile sidekicks-notary

A list (empty the first time) shows, with no authentication error.

A7. Set the two variables

Add to your ~/.zshrc, then open a new Terminal:

export SIDEKICKS_SIGN_IDENTITY="Developer ID Application: First Last (AB12CD34EF)"
export SIDEKICKS_NOTARY_PROFILE="sidekicks-notary"

Part B uses them; the automation (issue #58) will too.

A8. Keep the app's identifier

CFBundleIdentifier is com.k33g.sidekicks in build/darwin/Info.plist (and Info.dev.plist). Do not change it any more: macOS ties the permissions given to the app to it.

Part B — for every release

These commands take the packages make release-build just put in dist/ and the app left in bin/sidekicks.app.

B1. Build the release

As usual (RELEASING.md, steps Before and 1):

make release-build

B2. Sign the app

xattr -cr bin/sidekicks.app
codesign --force --options runtime --timestamp \
  --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.app
codesign --verify --strict --verbose=2 bin/sidekicks.app
codesign -dv --verbose=4 bin/sidekicks.app 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp="

The last command must show the Developer ID Application authority, the runtime flag and a Timestamp line.

B3. Notarize the app and staple the ticket

ditto -c -k --keepParent bin/sidekicks.app /tmp/sidekicks-app.zip
xcrun notarytool submit /tmp/sidekicks-app.zip --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait
xcrun stapler staple bin/sidekicks.app
spctl -a -vvv -t exec bin/sidekicks.app

notarytool waits for Apple's answer (a few minutes) and must end with status: Accepted. spctl must say accepted and source=Notarized Developer ID.

B4. Make the .dmg again from the stapled app, sign it, notarize it

wails3 task darwin:create:dmg
codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.dmg
xcrun notarytool submit bin/sidekicks.dmg --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait
xcrun stapler staple bin/sidekicks.dmg
spctl -a -vvv -t open --context context:primary-signature bin/sidekicks.dmg

spctl must say accepted and source=Notarized Developer ID.

B5. Replace the macOS packages of dist/ and compute the checksums again

names=($(scripts/package.sh names macos arm64))   # the .dmg, then the .zip
mv bin/sidekicks.dmg "dist/${names[0]}"
rm -f "dist/${names[1]}" && ditto -c -k --keepParent bin/sidekicks.app "dist/${names[1]}"
(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > ../SHA256SUMS.tmp) && mv SHA256SUMS.tmp dist/SHA256SUMS
cat dist/SHA256SUMS

B6. Try it on another Mac

  1. Copy the .dmg to another Mac (or another user account), through the web or AirDrop: it must carry the quarantine attribute of a real download.
  2. Open it, drag sidekicks to Applications, launch it: it opens directly, without Open Anyway.
  3. Go through what the hardened runtime could hinder: a local agent, an agent in a container or in sbx, the Terminal tab, opening a file, drag and drop, Settings → Open….

B7. Tag and publish

Follow the rest of RELEASING.md (steps 2 to 4): the files to attach are those of dist/.

Variants

  • A separate macOS release, on a version already published (e.g. v1.0.0-macos, issue #57): do not change info.version (the app stays 1.0.0; Windows refuses a version that is not made of numbers, Apple too for CFBundleShortVersionString, and the packages would be called …-1.0.0-macos-macos-…). Build macOS only with SKIP=windows make release-build, do part B, then create the tag by hand: git tag -a v1.0.0-macos -m "Sidekicks 1.0.0, macOS signed and notarized" && git push origin v1.0.0-macos. The Release workflow starts and stops at its check (the tag is not v + the version of build/config.yml): this is expected. Create the release on Rickub from that tag and attach the .dmg, the .zip and SHA256SUMS. You can also simply replace the macOS files of the v1.0.0 release.
  • Notarization is refused (status: Invalid): xcrun notarytool log <id> --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" gives the reason. The usual ones: a signature without --options runtime or without --timestamp, or an unsigned file in the app.
  • codesign refuses ("resource fork, Finder information, or similar detritus"): the repository is in a synced folder, which adds metadata. xattr -cr bin/sidekicks.app and try again; if it comes back, copy the app to /tmp and sign it there.
  • The signed app does not start, or a feature no longer works: the hardened runtime blocks something. Read Console.app at launch; if one entitlement is missing, add an entitlements file (--entitlements build/darwin/entitlements.plist in B2) with that entitlement only, and note it in issue #57.
  • Check an installed app: spctl -a -vvv /Applications/sidekicks.app and xcrun stapler validate /Applications/sidekicks.app.
  • Another Mac to build on: import the .p12 (double-click), then do A6 and A7 again.

See also

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# How to sign and notarize Sidekicks for macOS

This guide shows how to sign Sidekicks with a **Developer ID** certificate and have Apple **notarize** it, so that it opens on any Mac without **Open Anyway**. It assumes a paid Apple Developer Program membership of which you are the **Account Holder** (only that role can create a Developer ID certificate), an Apple Silicon Mac with the project's development tools ([Develop the application](develop-the-application.md)), and a release built as [RELEASING.md](../../../RELEASING.md) describes.

- **Part A** is done **once** (allow 30 minutes).
- **Part B** is done **for every release**, after `make release-build`, until signing is automated (issue #58). Allow 10 to 20 minutes, mostly waiting for Apple.

Keep a Terminal window open at the root of the repository.

## What signing and notarizing do

| Step | Tool | What it brings |
| --- | --- | --- |
| Sign | `codesign` with your Developer ID certificate | macOS knows who made the app and that it was not changed |
| Hardened runtime | `codesign --options runtime` | required by Apple to notarize |
| Notarize | `xcrun notarytool` | Apple scans the app and issues a "ticket" |
| Staple | `xcrun stapler` | the ticket is attached to the app and the `.dmg`: Gatekeeper accepts them even offline |

The app **and** the `.dmg` are signed, notarized and stapled. The `.zip` holds the stapled app.

## Part A — once

### A1. Note your Team ID

1. Open [developer.apple.com/account](https://developer.apple.com/account), **Membership details**.
2. Note the **Team ID** (10 characters, e.g. `AB12CD34EF`).

### A2. Create the Developer ID Application certificate

With Xcode (the simplest):

1. Open **Xcode → Settings… → Accounts**. If it is not there, click **+**, choose **Apple ID** and sign in with the email address and password of your Apple Developer account (the Apple ID, not the Team ID).
2. Your team shows under the account, with its Team ID: select it, click **Manage Certificates…**.
3. Click **+** at the bottom left, then **Developer ID Application**.

Without Xcode:

1. Open **Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…**, give your address, tick **Saved to disk**. You get a `.certSigningRequest` file.
2. On [developer.apple.com/account/resources/certificates](https://developer.apple.com/account/resources/certificates/add), choose **Developer ID Application**, profile **G2 Sub-CA**, upload the request, then download the certificate.
3. Double-click the `.cer` file: it goes to the **login** keychain.

### A3. Check that the certificate can be used

```bash
security find-identity -v -p codesigning
```

A line `"Developer ID Application: First Last (AB12CD34EF)"` must show. That is your **signing identity**: copy it exactly, without the quotes.

If it is missing, or shows `CSSMERR_TP_NOT_TRUSTED`, install the **Developer ID - G2** intermediate certificate from [apple.com/certificateauthority](https://www.apple.com/certificateauthority/), then run the command again.

### A4. Back up the certificate and its key

The private key only exists on this Mac: without a backup, a failure means revoking the certificate and making a new one.

1. In **Keychain Access**, **login** keychain, **My Certificates**, unfold **Developer ID Application: …** (the key shows under it).
2. Select the certificate, **File → Export Items…**, format **.p12**, choose a password.
3. Keep the `.p12` and its password in your password manager. Never put it in the repository.

### A5. Create an app-specific password for notarization

1. Open [account.apple.com](https://account.apple.com), **Sign-In and Security → App-Specific Passwords**.
2. Create one called `sidekicks-notary` and copy it (it is not shown again).

### A6. Store the notarization profile in the keychain

```bash
xcrun notarytool store-credentials sidekicks-notary \
  --apple-id "you@example.com" \
  --team-id "AB12CD34EF"
```

Paste the app-specific password when asked. Check:

```bash
xcrun notarytool history --keychain-profile sidekicks-notary
```

A list (empty the first time) shows, with no authentication error.

### A7. Set the two variables

Add to your `~/.zshrc`, then open a new Terminal:

```bash
export SIDEKICKS_SIGN_IDENTITY="Developer ID Application: First Last (AB12CD34EF)"
export SIDEKICKS_NOTARY_PROFILE="sidekicks-notary"
```

Part B uses them; the automation (issue #58) will too.

### A8. Keep the app's identifier

`CFBundleIdentifier` is `com.k33g.sidekicks` in `build/darwin/Info.plist` (and `Info.dev.plist`). Do not change it any more: macOS ties the permissions given to the app to it.

## Part B — for every release

These commands take the packages `make release-build` just put in `dist/` and the app left in `bin/sidekicks.app`.

### B1. Build the release

As usual ([RELEASING.md](../../../RELEASING.md), steps Before and 1):

```bash
make release-build
```

### B2. Sign the app

```bash
xattr -cr bin/sidekicks.app
codesign --force --options runtime --timestamp \
  --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.app
codesign --verify --strict --verbose=2 bin/sidekicks.app
codesign -dv --verbose=4 bin/sidekicks.app 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp="
```

The last command must show the **Developer ID Application** authority, the **runtime** flag and a **Timestamp** line.

### B3. Notarize the app and staple the ticket

```bash
ditto -c -k --keepParent bin/sidekicks.app /tmp/sidekicks-app.zip
xcrun notarytool submit /tmp/sidekicks-app.zip --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait
xcrun stapler staple bin/sidekicks.app
spctl -a -vvv -t exec bin/sidekicks.app
```

`notarytool` waits for Apple's answer (a few minutes) and must end with `status: Accepted`. `spctl` must say `accepted` and `source=Notarized Developer ID`.

### B4. Make the `.dmg` again from the stapled app, sign it, notarize it

```bash
wails3 task darwin:create:dmg
codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.dmg
xcrun notarytool submit bin/sidekicks.dmg --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait
xcrun stapler staple bin/sidekicks.dmg
spctl -a -vvv -t open --context context:primary-signature bin/sidekicks.dmg
```

`spctl` must say `accepted` and `source=Notarized Developer ID`.

### B5. Replace the macOS packages of `dist/` and compute the checksums again

```bash
names=($(scripts/package.sh names macos arm64))   # the .dmg, then the .zip
mv bin/sidekicks.dmg "dist/${names[0]}"
rm -f "dist/${names[1]}" && ditto -c -k --keepParent bin/sidekicks.app "dist/${names[1]}"
(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > ../SHA256SUMS.tmp) && mv SHA256SUMS.tmp dist/SHA256SUMS
cat dist/SHA256SUMS
```

### B6. Try it on another Mac

1. Copy the `.dmg` to another Mac (or another user account), through the web or AirDrop: it must carry the quarantine attribute of a real download.
2. Open it, drag **sidekicks** to **Applications**, launch it: it opens directly, without **Open Anyway**.
3. Go through what the hardened runtime could hinder: a local agent, an agent in a container or in sbx, the Terminal tab, opening a file, drag and drop, Settings → Open….

### B7. Tag and publish

Follow the rest of [RELEASING.md](../../../RELEASING.md) (steps 2 to 4): the files to attach are those of `dist/`.

## Variants

- **A separate macOS release, on a version already published** (e.g. `v1.0.0-macos`, issue #57): **do not change** `info.version` (the app stays `1.0.0`; Windows refuses a version that is not made of numbers, Apple too for `CFBundleShortVersionString`, and the packages would be called `…-1.0.0-macos-macos-…`). Build macOS only with `SKIP=windows make release-build`, do part B, then create the tag by hand: `git tag -a v1.0.0-macos -m "Sidekicks 1.0.0, macOS signed and notarized" && git push origin v1.0.0-macos`. The **Release** workflow starts and stops at its check (the tag is not `v` + the version of `build/config.yml`): this is expected. Create the release on Rickub from that tag and attach the `.dmg`, the `.zip` and `SHA256SUMS`. You can also simply replace the macOS files of the `v1.0.0` release.
- **Notarization is refused** (`status: Invalid`): `xcrun notarytool log <id> --keychain-profile "$SIDEKICKS_NOTARY_PROFILE"` gives the reason. The usual ones: a signature without `--options runtime` or without `--timestamp`, or an unsigned file in the app.
- **`codesign` refuses ("resource fork, Finder information, or similar detritus")**: the repository is in a synced folder, which adds metadata. `xattr -cr bin/sidekicks.app` and try again; if it comes back, copy the app to `/tmp` and sign it there.
- **The signed app does not start, or a feature no longer works**: the hardened runtime blocks something. Read **Console.app** at launch; if one entitlement is missing, add an entitlements file (`--entitlements build/darwin/entitlements.plist` in B2) with that entitlement only, and note it in issue #57.
- **Check an installed app**: `spctl -a -vvv /Applications/sidekicks.app` and `xcrun stapler validate /Applications/sidekicks.app`.
- **Another Mac to build on**: import the `.p12` (double-click), then do A6 and A7 again.

## See also

- [How to publish a release](publish-a-release.md) · [RELEASING.md](../../../RELEASING.md)
- [How to install Sidekicks](install-sidekicks.md)
- Apple: [Notarizing macOS software before distribution](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution)