🛟 Updated.
78ee671 parent: 8990cef modified
docs/en/how-to/sign-and-notarize-on-macos.md +59 -27 | @@ -95,79 +95,111 @@ Part B uses them; the automation (issue #58) will too. | ||
| 95 | 95 | |
| 96 | 96 | ## Part B — for every release |
| 97 | 97 | |
| 98 | -These commands take the packages `make release-build` just put in `dist/` and the app left in `bin/sidekicks.app`. | |
| 98 | +**First pause syncing** if the repository is in a synced folder (kDrive, iCloud Drive, Dropbox…): it changes the files while `codesign` and `stapler` rewrite them, which breaks the signatures and gives "corrupted" `.dmg` files. Everything then happens in a working folder, `bin/sign` (ignored by git). | |
| 99 | 99 | |
| 100 | 100 | ### B1. Build the release |
| 101 | 101 | |
| 102 | 102 | As usual ([RELEASING.md](../../../RELEASING.md), steps Before and 1): |
| 103 | 103 | |
| 104 | 104 | ```bash |
| 105 | -make release-build | |
| 105 | +make release-build # or SKIP=windows make release-build for a macOS-only release | |
| 106 | 106 | ``` |
| 107 | 107 | |
| 108 | -### B2. Sign the app | |
| 108 | +`dist/` holds the unsigned packages, and `bin/sidekicks.app` the ad-hoc signed app. | |
| 109 | + | |
| 110 | +### B2. Copy the app to the working folder | |
| 111 | + | |
| 112 | +```bash | |
| 113 | +W="$PWD/bin/sign" | |
| 114 | +rm -rf "$W" && mkdir -p "$W" | |
| 115 | +ditto bin/sidekicks.app "$W/sidekicks.app" | |
| 116 | +``` | |
| 117 | + | |
| 118 | +Keep this Terminal open, at the root of the repository: the next steps use `$W`. If syncing cannot be paused, take `W="$(mktemp -d /tmp/sidekicks-sign.XXXXXX)"` instead. | |
| 119 | + | |
| 120 | +### B3. Sign the app | |
| 109 | 121 | |
| 110 | 122 | ```bash |
| 111 | -xattr -cr bin/sidekicks.app | |
| 123 | +xattr -cr "$W/sidekicks.app" | |
| 112 | 124 | codesign --force --options runtime --timestamp \ |
| 113 | - --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.app | |
| 114 | -codesign --verify --strict --verbose=2 bin/sidekicks.app | |
| 115 | -codesign -dv --verbose=4 bin/sidekicks.app 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" | |
| 125 | + --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.app" | |
| 126 | +codesign --verify --strict --verbose=2 "$W/sidekicks.app" | |
| 127 | +codesign -dv --verbose=4 "$W/sidekicks.app" 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" | |
| 116 | 128 | ``` |
| 117 | 129 | |
| 118 | 130 | The last command must show the **Developer ID Application** authority, the **runtime** flag and a **Timestamp** line. |
| 119 | 131 | |
| 120 | -### B3. Notarize the app and staple the ticket | |
| 132 | +### B4. Notarize the app and staple the ticket | |
| 121 | 133 | |
| 122 | 134 | ```bash |
| 123 | -ditto -c -k --keepParent bin/sidekicks.app /tmp/sidekicks-app.zip | |
| 124 | -xcrun notarytool submit /tmp/sidekicks-app.zip --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 125 | -xcrun stapler staple bin/sidekicks.app | |
| 126 | -spctl -a -vvv -t exec bin/sidekicks.app | |
| 135 | +ditto -c -k --keepParent "$W/sidekicks.app" "$W/notarize.zip" | |
| 136 | +xcrun notarytool submit "$W/notarize.zip" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 137 | +xcrun stapler staple "$W/sidekicks.app" | |
| 138 | +spctl -a -vvv -t exec "$W/sidekicks.app" | |
| 127 | 139 | ``` |
| 128 | 140 | |
| 129 | 141 | `notarytool` waits for Apple's answer (a few minutes) and must end with `status: Accepted`. `spctl` must say `accepted` and `source=Notarized Developer ID`. |
| 130 | 142 | |
| 131 | -### B4. Make the `.dmg` again from the stapled app, sign it, notarize it | |
| 143 | +### B5. Make the `.dmg` from the stapled app | |
| 132 | 144 | |
| 133 | 145 | ```bash |
| 134 | -wails3 task darwin:create:dmg | |
| 135 | -codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.dmg | |
| 136 | -xcrun notarytool submit bin/sidekicks.dmg --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 137 | -xcrun stapler staple bin/sidekicks.dmg | |
| 138 | -spctl -a -vvv -t open --context context:primary-signature bin/sidekicks.dmg | |
| 146 | +wails3 tool package --format dmg --name sidekicks --out "$W" \ | |
| 147 | + --background build/darwin/dmg-background.png \ | |
| 148 | + --volume-icon build/darwin/icons.icns \ | |
| 149 | + --file-icon build/darwin/dmg-file-icon.icns \ | |
| 150 | + --window-width 540 --window-height 380 | |
| 151 | +hdiutil verify "$W/sidekicks.dmg" | |
| 139 | 152 | ``` |
| 140 | 153 | |
| 141 | -`spctl` must say `accepted` and `source=Notarized Developer ID`. | |
| 154 | +The command runs from the root of the repository (for the images) but reads the app and writes the `.dmg` in `$W`, with the same layout as `make release-build`. `hdiutil verify` must end with `checksum … is VALID`. | |
| 142 | 155 | |
| 143 | -### B5. Replace the macOS packages of `dist/` and compute the checksums again | |
| 156 | +### B6. Sign, notarize and staple the `.dmg` | |
| 157 | + | |
| 158 | +```bash | |
| 159 | +codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.dmg" | |
| 160 | +xcrun notarytool submit "$W/sidekicks.dmg" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 161 | +xcrun stapler staple "$W/sidekicks.dmg" | |
| 162 | +hdiutil verify "$W/sidekicks.dmg" | |
| 163 | +spctl -a -vvv -t open --context context:primary-signature "$W/sidekicks.dmg" | |
| 164 | +hdiutil attach -nobrowse -readonly "$W/sidekicks.dmg" && hdiutil detach "/Volumes/sidekicks" | |
| 165 | +``` | |
| 166 | + | |
| 167 | +`spctl` must say `accepted` and `source=Notarized Developer ID`; the `.dmg` must mount then unmount without error. If the volume is not called `sidekicks`, detach the one `hdiutil attach` printed. | |
| 168 | + | |
| 169 | +### B7. Replace the macOS packages of `dist/` and compute the checksums again | |
| 144 | 170 | |
| 145 | 171 | ```bash |
| 146 | 172 | names=($(scripts/package.sh names macos arm64)) # the .dmg, then the .zip |
| 147 | -mv bin/sidekicks.dmg "dist/${names[0]}" | |
| 148 | -rm -f "dist/${names[1]}" && ditto -c -k --keepParent bin/sidekicks.app "dist/${names[1]}" | |
| 149 | -(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > ../SHA256SUMS.tmp) && mv SHA256SUMS.tmp dist/SHA256SUMS | |
| 173 | +cp "$W/sidekicks.dmg" "dist/${names[0]}" | |
| 174 | +rm -f "dist/${names[1]}" && ditto -c -k --keepParent "$W/sidekicks.app" "dist/${names[1]}" | |
| 175 | +cmp "$W/sidekicks.dmg" "dist/${names[0]}" && echo "identical copy" | |
| 176 | +spctl -a -vvv -t open --context context:primary-signature "dist/${names[0]}" # accepted · Notarized Developer ID | |
| 177 | +(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > "$W/SHA256SUMS") && cp "$W/SHA256SUMS" dist/SHA256SUMS | |
| 150 | 178 | cat dist/SHA256SUMS |
| 151 | 179 | ``` |
| 152 | 180 | |
| 153 | -### B6. Try it on another Mac | |
| 181 | +Do not go on if `cmp` reports a difference or `spctl` refuses: `dist/` would still hold the unsigned `.dmg` of B1, and so would the release. | |
| 182 | + | |
| 183 | +### B8. Try it on another Mac | |
| 154 | 184 | |
| 155 | 185 | 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. |
| 156 | 186 | 2. Open it, drag **sidekicks** to **Applications**, launch it: it opens directly, without **Open Anyway**. |
| 157 | 187 | 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…. |
| 158 | 188 | |
| 159 | -### B7. Tag and publish | |
| 189 | +### B9. Tag and publish | |
| 160 | 190 | |
| 161 | -Follow the rest of [RELEASING.md](../../../RELEASING.md) (steps 2 to 4): the files to attach are those of `dist/`. | |
| 191 | +Follow the rest of [RELEASING.md](../../../RELEASING.md) (steps 2 to 4): the files to attach are those of `dist/`. Once the release is published, download its `.dmg` and check that `shasum -a 256` gives the same sum as `SHA256SUMS` (a truncated upload also gives "corrupted image"). Then delete `$W` and resume syncing. | |
| 162 | 192 | |
| 163 | 193 | ## Variants |
| 164 | 194 | |
| 165 | 195 | - **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. |
| 166 | 196 | - **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. |
| 167 | -- **`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. | |
| 197 | +- **"The disk image is corrupted" when opening the `.dmg`**: it was changed after it was signed (synced folder) or truncated (upload, download). `hdiutil verify` on the file and `shasum -a 256` compared with `SHA256SUMS` tell which. Do B2 to B7 again with syncing paused (or with `$W` in `/tmp`). | |
| 198 | +- **`codesign` refuses ("resource fork, Finder information, or similar detritus")**: the app comes from a synced folder, which adds metadata. `xattr -cr "$W/sidekicks.app"` and do B3 again. | |
| 168 | 199 | - **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. |
| 169 | 200 | - **Check an installed app**: `spctl -a -vvv /Applications/sidekicks.app` and `xcrun stapler validate /Applications/sidekicks.app`. |
| 170 | 201 | - **Another Mac to build on**: import the `.p12` (double-click), then do A6 and A7 again. |
| 202 | +- **The `.dmg` to make again, the app already notarized**: if `$W/sidekicks.app` is still there and `xcrun stapler validate "$W/sidekicks.app"` succeeds, go straight to B5. | |
| 171 | 203 | |
| 172 | 204 | ## See also |
| 173 | 205 | |
| @@ -95,79 +95,111 @@ Part B uses them; the automation (issue #58) will too. | |||
| 95 | 95 | ||
| 96 | ## Part B — for every release | 96 | ## Part B — for every release |
| 97 | 97 | ||
| 98 | -These commands take the packages `make release-build` just put in `dist/` and the app left in `bin/sidekicks.app`. | 98 | +**First pause syncing** if the repository is in a synced folder (kDrive, iCloud Drive, Dropbox…): it changes the files while `codesign` and `stapler` rewrite them, which breaks the signatures and gives "corrupted" `.dmg` files. Everything then happens in a working folder, `bin/sign` (ignored by git). |
| 99 | 99 | ||
| 100 | ### B1. Build the release | 100 | ### B1. Build the release |
| 101 | 101 | ||
| 102 | As usual ([RELEASING.md](../../../RELEASING.md), steps Before and 1): | 102 | As usual ([RELEASING.md](../../../RELEASING.md), steps Before and 1): |
| 103 | 103 | ||
| 104 | ```bash | 104 | ```bash |
| 105 | -make release-build | 105 | +make release-build # or SKIP=windows make release-build for a macOS-only release |
| 106 | ``` | 106 | ``` |
| 107 | 107 | ||
| 108 | -### B2. Sign the app | 108 | +`dist/` holds the unsigned packages, and `bin/sidekicks.app` the ad-hoc signed app. |
| 109 | + | ||
| 110 | +### B2. Copy the app to the working folder | ||
| 111 | + | ||
| 112 | +```bash | ||
| 113 | +W="$PWD/bin/sign" | ||
| 114 | +rm -rf "$W" && mkdir -p "$W" | ||
| 115 | +ditto bin/sidekicks.app "$W/sidekicks.app" | ||
| 116 | +``` | ||
| 117 | + | ||
| 118 | +Keep this Terminal open, at the root of the repository: the next steps use `$W`. If syncing cannot be paused, take `W="$(mktemp -d /tmp/sidekicks-sign.XXXXXX)"` instead. | ||
| 119 | + | ||
| 120 | +### B3. Sign the app | ||
| 109 | 121 | ||
| 110 | ```bash | 122 | ```bash |
| 111 | -xattr -cr bin/sidekicks.app | 123 | +xattr -cr "$W/sidekicks.app" |
| 112 | codesign --force --options runtime --timestamp \ | 124 | codesign --force --options runtime --timestamp \ |
| 113 | - --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.app | 125 | + --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.app" |
| 114 | -codesign --verify --strict --verbose=2 bin/sidekicks.app | 126 | +codesign --verify --strict --verbose=2 "$W/sidekicks.app" |
| 115 | -codesign -dv --verbose=4 bin/sidekicks.app 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" | 127 | +codesign -dv --verbose=4 "$W/sidekicks.app" 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" |
| 116 | ``` | 128 | ``` |
| 117 | 129 | ||
| 118 | The last command must show the **Developer ID Application** authority, the **runtime** flag and a **Timestamp** line. | 130 | The last command must show the **Developer ID Application** authority, the **runtime** flag and a **Timestamp** line. |
| 119 | 131 | ||
| 120 | -### B3. Notarize the app and staple the ticket | 132 | +### B4. Notarize the app and staple the ticket |
| 121 | 133 | ||
| 122 | ```bash | 134 | ```bash |
| 123 | -ditto -c -k --keepParent bin/sidekicks.app /tmp/sidekicks-app.zip | 135 | +ditto -c -k --keepParent "$W/sidekicks.app" "$W/notarize.zip" |
| 124 | -xcrun notarytool submit /tmp/sidekicks-app.zip --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | 136 | +xcrun notarytool submit "$W/notarize.zip" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait |
| 125 | -xcrun stapler staple bin/sidekicks.app | 137 | +xcrun stapler staple "$W/sidekicks.app" |
| 126 | -spctl -a -vvv -t exec bin/sidekicks.app | 138 | +spctl -a -vvv -t exec "$W/sidekicks.app" |
| 127 | ``` | 139 | ``` |
| 128 | 140 | ||
| 129 | `notarytool` waits for Apple's answer (a few minutes) and must end with `status: Accepted`. `spctl` must say `accepted` and `source=Notarized Developer ID`. | 141 | `notarytool` waits for Apple's answer (a few minutes) and must end with `status: Accepted`. `spctl` must say `accepted` and `source=Notarized Developer ID`. |
| 130 | 142 | ||
| 131 | -### B4. Make the `.dmg` again from the stapled app, sign it, notarize it | 143 | +### B5. Make the `.dmg` from the stapled app |
| 132 | 144 | ||
| 133 | ```bash | 145 | ```bash |
| 134 | -wails3 task darwin:create:dmg | 146 | +wails3 tool package --format dmg --name sidekicks --out "$W" \ |
| 135 | -codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.dmg | 147 | + --background build/darwin/dmg-background.png \ |
| 136 | -xcrun notarytool submit bin/sidekicks.dmg --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | 148 | + --volume-icon build/darwin/icons.icns \ |
| 137 | -xcrun stapler staple bin/sidekicks.dmg | 149 | + --file-icon build/darwin/dmg-file-icon.icns \ |
| 138 | -spctl -a -vvv -t open --context context:primary-signature bin/sidekicks.dmg | 150 | + --window-width 540 --window-height 380 |
| 151 | +hdiutil verify "$W/sidekicks.dmg" | ||
| 139 | ``` | 152 | ``` |
| 140 | 153 | ||
| 141 | -`spctl` must say `accepted` and `source=Notarized Developer ID`. | 154 | +The command runs from the root of the repository (for the images) but reads the app and writes the `.dmg` in `$W`, with the same layout as `make release-build`. `hdiutil verify` must end with `checksum … is VALID`. |
| 142 | 155 | ||
| 143 | -### B5. Replace the macOS packages of `dist/` and compute the checksums again | 156 | +### B6. Sign, notarize and staple the `.dmg` |
| 157 | + | ||
| 158 | +```bash | ||
| 159 | +codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.dmg" | ||
| 160 | +xcrun notarytool submit "$W/sidekicks.dmg" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | ||
| 161 | +xcrun stapler staple "$W/sidekicks.dmg" | ||
| 162 | +hdiutil verify "$W/sidekicks.dmg" | ||
| 163 | +spctl -a -vvv -t open --context context:primary-signature "$W/sidekicks.dmg" | ||
| 164 | +hdiutil attach -nobrowse -readonly "$W/sidekicks.dmg" && hdiutil detach "/Volumes/sidekicks" | ||
| 165 | +``` | ||
| 166 | + | ||
| 167 | +`spctl` must say `accepted` and `source=Notarized Developer ID`; the `.dmg` must mount then unmount without error. If the volume is not called `sidekicks`, detach the one `hdiutil attach` printed. | ||
| 168 | + | ||
| 169 | +### B7. Replace the macOS packages of `dist/` and compute the checksums again | ||
| 144 | 170 | ||
| 145 | ```bash | 171 | ```bash |
| 146 | names=($(scripts/package.sh names macos arm64)) # the .dmg, then the .zip | 172 | names=($(scripts/package.sh names macos arm64)) # the .dmg, then the .zip |
| 147 | -mv bin/sidekicks.dmg "dist/${names[0]}" | 173 | +cp "$W/sidekicks.dmg" "dist/${names[0]}" |
| 148 | -rm -f "dist/${names[1]}" && ditto -c -k --keepParent bin/sidekicks.app "dist/${names[1]}" | 174 | +rm -f "dist/${names[1]}" && ditto -c -k --keepParent "$W/sidekicks.app" "dist/${names[1]}" |
| 149 | -(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > ../SHA256SUMS.tmp) && mv SHA256SUMS.tmp dist/SHA256SUMS | 175 | +cmp "$W/sidekicks.dmg" "dist/${names[0]}" && echo "identical copy" |
| 176 | +spctl -a -vvv -t open --context context:primary-signature "dist/${names[0]}" # accepted · Notarized Developer ID | ||
| 177 | +(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > "$W/SHA256SUMS") && cp "$W/SHA256SUMS" dist/SHA256SUMS | ||
| 150 | cat dist/SHA256SUMS | 178 | cat dist/SHA256SUMS |
| 151 | ``` | 179 | ``` |
| 152 | 180 | ||
| 153 | -### B6. Try it on another Mac | 181 | +Do not go on if `cmp` reports a difference or `spctl` refuses: `dist/` would still hold the unsigned `.dmg` of B1, and so would the release. |
| 182 | + | ||
| 183 | +### B8. Try it on another Mac | ||
| 154 | 184 | ||
| 155 | 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. | 185 | 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. |
| 156 | 2. Open it, drag **sidekicks** to **Applications**, launch it: it opens directly, without **Open Anyway**. | 186 | 2. Open it, drag **sidekicks** to **Applications**, launch it: it opens directly, without **Open Anyway**. |
| 157 | 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…. | 187 | 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…. |
| 158 | 188 | ||
| 159 | -### B7. Tag and publish | 189 | +### B9. Tag and publish |
| 160 | 190 | ||
| 161 | -Follow the rest of [RELEASING.md](../../../RELEASING.md) (steps 2 to 4): the files to attach are those of `dist/`. | 191 | +Follow the rest of [RELEASING.md](../../../RELEASING.md) (steps 2 to 4): the files to attach are those of `dist/`. Once the release is published, download its `.dmg` and check that `shasum -a 256` gives the same sum as `SHA256SUMS` (a truncated upload also gives "corrupted image"). Then delete `$W` and resume syncing. |
| 162 | 192 | ||
| 163 | ## Variants | 193 | ## Variants |
| 164 | 194 | ||
| 165 | - **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. | 195 | - **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. |
| 166 | - **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. | 196 | - **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. |
| 167 | -- **`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. | 197 | +- **"The disk image is corrupted" when opening the `.dmg`**: it was changed after it was signed (synced folder) or truncated (upload, download). `hdiutil verify` on the file and `shasum -a 256` compared with `SHA256SUMS` tell which. Do B2 to B7 again with syncing paused (or with `$W` in `/tmp`). |
| 198 | +- **`codesign` refuses ("resource fork, Finder information, or similar detritus")**: the app comes from a synced folder, which adds metadata. `xattr -cr "$W/sidekicks.app"` and do B3 again. | ||
| 168 | - **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. | 199 | - **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. |
| 169 | - **Check an installed app**: `spctl -a -vvv /Applications/sidekicks.app` and `xcrun stapler validate /Applications/sidekicks.app`. | 200 | - **Check an installed app**: `spctl -a -vvv /Applications/sidekicks.app` and `xcrun stapler validate /Applications/sidekicks.app`. |
| 170 | - **Another Mac to build on**: import the `.p12` (double-click), then do A6 and A7 again. | 201 | - **Another Mac to build on**: import the `.p12` (double-click), then do A6 and A7 again. |
| 202 | +- **The `.dmg` to make again, the app already notarized**: if `$W/sidekicks.app` is still there and `xcrun stapler validate "$W/sidekicks.app"` succeeds, go straight to B5. | ||
| 171 | 203 | ||
| 172 | ## See also | 204 | ## See also |
| 173 | 205 | ||
modified
docs/fr/how-to/signer-et-notariser-sous-macos.md +59 -27 | @@ -95,79 +95,111 @@ La partie B les utilise ; l'automatisation (issue #58) les utilisera aussi. | ||
| 95 | 95 | |
| 96 | 96 | ## Partie B — à chaque release |
| 97 | 97 | |
| 98 | -Ces commandes reprennent les paquets que `make release-build` vient de mettre dans `dist/` et l'app restée dans `bin/sidekicks.app`. | |
| 98 | +**Mettez d'abord en pause la synchronisation** si le dépôt est dans un dossier synchronisé (kDrive, iCloud Drive, Dropbox…) : elle modifie les fichiers pendant que `codesign` et `stapler` les réécrivent, ce qui casse les signatures et donne des `.dmg` « endommagés ». Tout se fait ensuite dans un dossier de travail, `bin/sign` (ignoré par git). | |
| 99 | 99 | |
| 100 | 100 | ### B1. Construire la release |
| 101 | 101 | |
| 102 | 102 | Comme d'habitude ([RELEASING.fr.md](../../../RELEASING.fr.md), étapes Avant et 1) : |
| 103 | 103 | |
| 104 | 104 | ```bash |
| 105 | -make release-build | |
| 105 | +make release-build # ou SKIP=windows make release-build pour une release macOS seule | |
| 106 | 106 | ``` |
| 107 | 107 | |
| 108 | -### B2. Signer l'app | |
| 108 | +`dist/` contient les paquets non signés, et `bin/sidekicks.app` l'app signée en ad hoc. | |
| 109 | + | |
| 110 | +### B2. Copier l'app dans le dossier de travail | |
| 111 | + | |
| 112 | +```bash | |
| 113 | +W="$PWD/bin/sign" | |
| 114 | +rm -rf "$W" && mkdir -p "$W" | |
| 115 | +ditto bin/sidekicks.app "$W/sidekicks.app" | |
| 116 | +``` | |
| 117 | + | |
| 118 | +Gardez ce Terminal ouvert, à la racine du dépôt : les étapes suivantes utilisent `$W`. Si la synchronisation ne peut pas être mise en pause, prenez plutôt `W="$(mktemp -d /tmp/sidekicks-sign.XXXXXX)"`. | |
| 119 | + | |
| 120 | +### B3. Signer l'app | |
| 109 | 121 | |
| 110 | 122 | ```bash |
| 111 | -xattr -cr bin/sidekicks.app | |
| 123 | +xattr -cr "$W/sidekicks.app" | |
| 112 | 124 | codesign --force --options runtime --timestamp \ |
| 113 | - --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.app | |
| 114 | -codesign --verify --strict --verbose=2 bin/sidekicks.app | |
| 115 | -codesign -dv --verbose=4 bin/sidekicks.app 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" | |
| 125 | + --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.app" | |
| 126 | +codesign --verify --strict --verbose=2 "$W/sidekicks.app" | |
| 127 | +codesign -dv --verbose=4 "$W/sidekicks.app" 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" | |
| 116 | 128 | ``` |
| 117 | 129 | |
| 118 | 130 | La dernière commande doit afficher l'autorité **Developer ID Application**, le drapeau **runtime** et une ligne **Timestamp**. |
| 119 | 131 | |
| 120 | -### B3. Notariser l'app et agrafer le ticket | |
| 132 | +### B4. Notariser l'app et agrafer le ticket | |
| 121 | 133 | |
| 122 | 134 | ```bash |
| 123 | -ditto -c -k --keepParent bin/sidekicks.app /tmp/sidekicks-app.zip | |
| 124 | -xcrun notarytool submit /tmp/sidekicks-app.zip --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 125 | -xcrun stapler staple bin/sidekicks.app | |
| 126 | -spctl -a -vvv -t exec bin/sidekicks.app | |
| 135 | +ditto -c -k --keepParent "$W/sidekicks.app" "$W/notarize.zip" | |
| 136 | +xcrun notarytool submit "$W/notarize.zip" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 137 | +xcrun stapler staple "$W/sidekicks.app" | |
| 138 | +spctl -a -vvv -t exec "$W/sidekicks.app" | |
| 127 | 139 | ``` |
| 128 | 140 | |
| 129 | 141 | `notarytool` attend la réponse d'Apple (quelques minutes) et doit finir par `status: Accepted`. `spctl` doit dire `accepted` et `source=Notarized Developer ID`. |
| 130 | 142 | |
| 131 | -### B4. Refaire le `.dmg` à partir de l'app agrafée, le signer, le notariser | |
| 143 | +### B5. Faire le `.dmg` à partir de l'app agrafée | |
| 132 | 144 | |
| 133 | 145 | ```bash |
| 134 | -wails3 task darwin:create:dmg | |
| 135 | -codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.dmg | |
| 136 | -xcrun notarytool submit bin/sidekicks.dmg --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 137 | -xcrun stapler staple bin/sidekicks.dmg | |
| 138 | -spctl -a -vvv -t open --context context:primary-signature bin/sidekicks.dmg | |
| 146 | +wails3 tool package --format dmg --name sidekicks --out "$W" \ | |
| 147 | + --background build/darwin/dmg-background.png \ | |
| 148 | + --volume-icon build/darwin/icons.icns \ | |
| 149 | + --file-icon build/darwin/dmg-file-icon.icns \ | |
| 150 | + --window-width 540 --window-height 380 | |
| 151 | +hdiutil verify "$W/sidekicks.dmg" | |
| 139 | 152 | ``` |
| 140 | 153 | |
| 141 | -`spctl` doit dire `accepted` et `source=Notarized Developer ID`. | |
| 154 | +La commande se lance depuis la racine du dépôt (pour les images) mais lit l'app et écrit le `.dmg` dans `$W`, avec la même mise en page que `make release-build`. `hdiutil verify` doit finir par `checksum … is VALID`. | |
| 142 | 155 | |
| 143 | -### B5. Remplacer les paquets macOS de `dist/` et recalculer les sommes | |
| 156 | +### B6. Signer, notariser et agrafer le `.dmg` | |
| 157 | + | |
| 158 | +```bash | |
| 159 | +codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.dmg" | |
| 160 | +xcrun notarytool submit "$W/sidekicks.dmg" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | |
| 161 | +xcrun stapler staple "$W/sidekicks.dmg" | |
| 162 | +hdiutil verify "$W/sidekicks.dmg" | |
| 163 | +spctl -a -vvv -t open --context context:primary-signature "$W/sidekicks.dmg" | |
| 164 | +hdiutil attach -nobrowse -readonly "$W/sidekicks.dmg" && hdiutil detach "/Volumes/sidekicks" | |
| 165 | +``` | |
| 166 | + | |
| 167 | +`spctl` doit dire `accepted` et `source=Notarized Developer ID` ; le `.dmg` doit se monter puis se démonter sans erreur. Si le volume ne s'appelle pas `sidekicks`, détachez celui que `hdiutil attach` a affiché. | |
| 168 | + | |
| 169 | +### B7. Remplacer les paquets macOS de `dist/` et recalculer les sommes | |
| 144 | 170 | |
| 145 | 171 | ```bash |
| 146 | 172 | names=($(scripts/package.sh names macos arm64)) # le .dmg, puis le .zip |
| 147 | -mv bin/sidekicks.dmg "dist/${names[0]}" | |
| 148 | -rm -f "dist/${names[1]}" && ditto -c -k --keepParent bin/sidekicks.app "dist/${names[1]}" | |
| 149 | -(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > ../SHA256SUMS.tmp) && mv SHA256SUMS.tmp dist/SHA256SUMS | |
| 173 | +cp "$W/sidekicks.dmg" "dist/${names[0]}" | |
| 174 | +rm -f "dist/${names[1]}" && ditto -c -k --keepParent "$W/sidekicks.app" "dist/${names[1]}" | |
| 175 | +cmp "$W/sidekicks.dmg" "dist/${names[0]}" && echo "copie identique" | |
| 176 | +spctl -a -vvv -t open --context context:primary-signature "dist/${names[0]}" # accepted · Notarized Developer ID | |
| 177 | +(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > "$W/SHA256SUMS") && cp "$W/SHA256SUMS" dist/SHA256SUMS | |
| 150 | 178 | cat dist/SHA256SUMS |
| 151 | 179 | ``` |
| 152 | 180 | |
| 153 | -### B6. Essayer sur un autre Mac | |
| 181 | +Ne passez pas à la suite si `cmp` signale une différence ou si `spctl` refuse : `dist/` contiendrait encore le `.dmg` non signé de B1, et la release aussi. | |
| 182 | + | |
| 183 | +### B8. Essayer sur un autre Mac | |
| 154 | 184 | |
| 155 | 185 | 1. Copiez le `.dmg` sur un autre Mac (ou un autre compte utilisateur), par le web ou AirDrop : il doit porter l'attribut de quarantaine d'un vrai téléchargement. |
| 156 | 186 | 2. Ouvrez-le, glissez **sidekicks** dans **Applications**, lancez-le : il s'ouvre directement, sans **Ouvrir quand même**. |
| 157 | 187 | 3. Faites le tour de ce que le runtime renforcé pourrait gêner : un agent local, un agent en conteneur ou en sbx, l'onglet Terminal, l'ouverture d'un fichier, le glisser-déposer, Settings → Open…. |
| 158 | 188 | |
| 159 | -### B7. Taguer et publier | |
| 189 | +### B9. Taguer et publier | |
| 160 | 190 | |
| 161 | -Suivez la suite de [RELEASING.fr.md](../../../RELEASING.fr.md) (étapes 2 à 4) : les fichiers à attacher sont ceux de `dist/`. | |
| 191 | +Suivez la suite de [RELEASING.fr.md](../../../RELEASING.fr.md) (étapes 2 à 4) : les fichiers à attacher sont ceux de `dist/`. Une fois la release publiée, téléchargez son `.dmg` et vérifiez que `shasum -a 256` donne la même somme que `SHA256SUMS` (un envoi tronqué donne aussi « image endommagée »). Supprimez ensuite `$W` et relancez la synchronisation. | |
| 162 | 192 | |
| 163 | 193 | ## Variantes |
| 164 | 194 | |
| 165 | 195 | - **Release macOS à part, sur une version déjà publiée** (par exemple `v1.0.0-macos`, issue #57) : **ne changez pas** `info.version` (l'app reste la `1.0.0` ; Windows refuse une version qui n'est pas faite de nombres, Apple aussi pour `CFBundleShortVersionString`, et les paquets s'appelleraient `…-1.0.0-macos-macos-…`). Construisez seulement macOS avec `SKIP=windows make release-build`, faites la partie B, puis créez le tag à la main : `git tag -a v1.0.0-macos -m "Sidekicks 1.0.0, macOS signé et notarisé" && git push origin v1.0.0-macos`. Le workflow **Release** démarre et s'arrête à sa vérification (le tag n'est pas `v` + la version de `build/config.yml`) : c'est attendu. Créez la release sur Rickub depuis ce tag et attachez le `.dmg`, le `.zip` et `SHA256SUMS`. Vous pouvez aussi simplement remplacer les fichiers macOS de la release `v1.0.0`. |
| 166 | 196 | - **La notarisation est refusée** (`status: Invalid`) : `xcrun notarytool log <id> --keychain-profile "$SIDEKICKS_NOTARY_PROFILE"` donne la raison. Les plus courantes : signature sans `--options runtime` ou sans `--timestamp`, ou un fichier non signé dans l'app. |
| 167 | -- **`codesign` refuse (« resource fork, Finder information, or similar detritus »)** : le dépôt est dans un dossier synchronisé, qui ajoute des métadonnées. `xattr -cr bin/sidekicks.app` puis recommencez ; si cela revient, copiez l'app dans `/tmp` et signez-la là. | |
| 197 | +- **« L'image disque est endommagée » à l'ouverture du `.dmg`** : il a été modifié après sa signature (dossier synchronisé) ou tronqué (envoi, téléchargement). `hdiutil verify` sur le fichier et `shasum -a 256` comparé à `SHA256SUMS` disent lequel. Refaites B2 à B7 avec la synchronisation en pause (ou avec `$W` dans `/tmp`). | |
| 198 | +- **`codesign` refuse (« resource fork, Finder information, or similar detritus »)** : l'app vient d'un dossier synchronisé, qui ajoute des métadonnées. `xattr -cr "$W/sidekicks.app"` puis recommencez B3. | |
| 168 | 199 | - **L'app signée ne démarre pas ou une fonction ne marche plus** : le runtime renforcé bloque quelque chose. Lisez **Console.app** au lancement ; si un droit précis manque, ajoutez un fichier d'entitlements (`--entitlements build/darwin/entitlements.plist` dans B2) avec seulement ce droit, et notez-le dans l'issue #57. |
| 169 | 200 | - **Vérifier une app installée** : `spctl -a -vvv /Applications/sidekicks.app` et `xcrun stapler validate /Applications/sidekicks.app`. |
| 170 | 201 | - **Un autre Mac pour construire** : importez le `.p12` (double-clic), puis refaites A6 et A7. |
| 202 | +- **Le `.dmg` à refaire, l'app déjà notarisée** : si `$W/sidekicks.app` est encore là et que `xcrun stapler validate "$W/sidekicks.app"` réussit, reprenez directement à B5. | |
| 171 | 203 | |
| 172 | 204 | ## Voir aussi |
| 173 | 205 | |
| @@ -95,79 +95,111 @@ La partie B les utilise ; l'automatisation (issue #58) les utilisera aussi. | |||
| 95 | 95 | ||
| 96 | ## Partie B — à chaque release | 96 | ## Partie B — à chaque release |
| 97 | 97 | ||
| 98 | -Ces commandes reprennent les paquets que `make release-build` vient de mettre dans `dist/` et l'app restée dans `bin/sidekicks.app`. | 98 | +**Mettez d'abord en pause la synchronisation** si le dépôt est dans un dossier synchronisé (kDrive, iCloud Drive, Dropbox…) : elle modifie les fichiers pendant que `codesign` et `stapler` les réécrivent, ce qui casse les signatures et donne des `.dmg` « endommagés ». Tout se fait ensuite dans un dossier de travail, `bin/sign` (ignoré par git). |
| 99 | 99 | ||
| 100 | ### B1. Construire la release | 100 | ### B1. Construire la release |
| 101 | 101 | ||
| 102 | Comme d'habitude ([RELEASING.fr.md](../../../RELEASING.fr.md), étapes Avant et 1) : | 102 | Comme d'habitude ([RELEASING.fr.md](../../../RELEASING.fr.md), étapes Avant et 1) : |
| 103 | 103 | ||
| 104 | ```bash | 104 | ```bash |
| 105 | -make release-build | 105 | +make release-build # ou SKIP=windows make release-build pour une release macOS seule |
| 106 | ``` | 106 | ``` |
| 107 | 107 | ||
| 108 | -### B2. Signer l'app | 108 | +`dist/` contient les paquets non signés, et `bin/sidekicks.app` l'app signée en ad hoc. |
| 109 | + | ||
| 110 | +### B2. Copier l'app dans le dossier de travail | ||
| 111 | + | ||
| 112 | +```bash | ||
| 113 | +W="$PWD/bin/sign" | ||
| 114 | +rm -rf "$W" && mkdir -p "$W" | ||
| 115 | +ditto bin/sidekicks.app "$W/sidekicks.app" | ||
| 116 | +``` | ||
| 117 | + | ||
| 118 | +Gardez ce Terminal ouvert, à la racine du dépôt : les étapes suivantes utilisent `$W`. Si la synchronisation ne peut pas être mise en pause, prenez plutôt `W="$(mktemp -d /tmp/sidekicks-sign.XXXXXX)"`. | ||
| 119 | + | ||
| 120 | +### B3. Signer l'app | ||
| 109 | 121 | ||
| 110 | ```bash | 122 | ```bash |
| 111 | -xattr -cr bin/sidekicks.app | 123 | +xattr -cr "$W/sidekicks.app" |
| 112 | codesign --force --options runtime --timestamp \ | 124 | codesign --force --options runtime --timestamp \ |
| 113 | - --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.app | 125 | + --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.app" |
| 114 | -codesign --verify --strict --verbose=2 bin/sidekicks.app | 126 | +codesign --verify --strict --verbose=2 "$W/sidekicks.app" |
| 115 | -codesign -dv --verbose=4 bin/sidekicks.app 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" | 127 | +codesign -dv --verbose=4 "$W/sidekicks.app" 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp=" |
| 116 | ``` | 128 | ``` |
| 117 | 129 | ||
| 118 | La dernière commande doit afficher l'autorité **Developer ID Application**, le drapeau **runtime** et une ligne **Timestamp**. | 130 | La dernière commande doit afficher l'autorité **Developer ID Application**, le drapeau **runtime** et une ligne **Timestamp**. |
| 119 | 131 | ||
| 120 | -### B3. Notariser l'app et agrafer le ticket | 132 | +### B4. Notariser l'app et agrafer le ticket |
| 121 | 133 | ||
| 122 | ```bash | 134 | ```bash |
| 123 | -ditto -c -k --keepParent bin/sidekicks.app /tmp/sidekicks-app.zip | 135 | +ditto -c -k --keepParent "$W/sidekicks.app" "$W/notarize.zip" |
| 124 | -xcrun notarytool submit /tmp/sidekicks-app.zip --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | 136 | +xcrun notarytool submit "$W/notarize.zip" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait |
| 125 | -xcrun stapler staple bin/sidekicks.app | 137 | +xcrun stapler staple "$W/sidekicks.app" |
| 126 | -spctl -a -vvv -t exec bin/sidekicks.app | 138 | +spctl -a -vvv -t exec "$W/sidekicks.app" |
| 127 | ``` | 139 | ``` |
| 128 | 140 | ||
| 129 | `notarytool` attend la réponse d'Apple (quelques minutes) et doit finir par `status: Accepted`. `spctl` doit dire `accepted` et `source=Notarized Developer ID`. | 141 | `notarytool` attend la réponse d'Apple (quelques minutes) et doit finir par `status: Accepted`. `spctl` doit dire `accepted` et `source=Notarized Developer ID`. |
| 130 | 142 | ||
| 131 | -### B4. Refaire le `.dmg` à partir de l'app agrafée, le signer, le notariser | 143 | +### B5. Faire le `.dmg` à partir de l'app agrafée |
| 132 | 144 | ||
| 133 | ```bash | 145 | ```bash |
| 134 | -wails3 task darwin:create:dmg | 146 | +wails3 tool package --format dmg --name sidekicks --out "$W" \ |
| 135 | -codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" bin/sidekicks.dmg | 147 | + --background build/darwin/dmg-background.png \ |
| 136 | -xcrun notarytool submit bin/sidekicks.dmg --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | 148 | + --volume-icon build/darwin/icons.icns \ |
| 137 | -xcrun stapler staple bin/sidekicks.dmg | 149 | + --file-icon build/darwin/dmg-file-icon.icns \ |
| 138 | -spctl -a -vvv -t open --context context:primary-signature bin/sidekicks.dmg | 150 | + --window-width 540 --window-height 380 |
| 151 | +hdiutil verify "$W/sidekicks.dmg" | ||
| 139 | ``` | 152 | ``` |
| 140 | 153 | ||
| 141 | -`spctl` doit dire `accepted` et `source=Notarized Developer ID`. | 154 | +La commande se lance depuis la racine du dépôt (pour les images) mais lit l'app et écrit le `.dmg` dans `$W`, avec la même mise en page que `make release-build`. `hdiutil verify` doit finir par `checksum … is VALID`. |
| 142 | 155 | ||
| 143 | -### B5. Remplacer les paquets macOS de `dist/` et recalculer les sommes | 156 | +### B6. Signer, notariser et agrafer le `.dmg` |
| 157 | + | ||
| 158 | +```bash | ||
| 159 | +codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.dmg" | ||
| 160 | +xcrun notarytool submit "$W/sidekicks.dmg" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait | ||
| 161 | +xcrun stapler staple "$W/sidekicks.dmg" | ||
| 162 | +hdiutil verify "$W/sidekicks.dmg" | ||
| 163 | +spctl -a -vvv -t open --context context:primary-signature "$W/sidekicks.dmg" | ||
| 164 | +hdiutil attach -nobrowse -readonly "$W/sidekicks.dmg" && hdiutil detach "/Volumes/sidekicks" | ||
| 165 | +``` | ||
| 166 | + | ||
| 167 | +`spctl` doit dire `accepted` et `source=Notarized Developer ID` ; le `.dmg` doit se monter puis se démonter sans erreur. Si le volume ne s'appelle pas `sidekicks`, détachez celui que `hdiutil attach` a affiché. | ||
| 168 | + | ||
| 169 | +### B7. Remplacer les paquets macOS de `dist/` et recalculer les sommes | ||
| 144 | 170 | ||
| 145 | ```bash | 171 | ```bash |
| 146 | names=($(scripts/package.sh names macos arm64)) # le .dmg, puis le .zip | 172 | names=($(scripts/package.sh names macos arm64)) # le .dmg, puis le .zip |
| 147 | -mv bin/sidekicks.dmg "dist/${names[0]}" | 173 | +cp "$W/sidekicks.dmg" "dist/${names[0]}" |
| 148 | -rm -f "dist/${names[1]}" && ditto -c -k --keepParent bin/sidekicks.app "dist/${names[1]}" | 174 | +rm -f "dist/${names[1]}" && ditto -c -k --keepParent "$W/sidekicks.app" "dist/${names[1]}" |
| 149 | -(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > ../SHA256SUMS.tmp) && mv SHA256SUMS.tmp dist/SHA256SUMS | 175 | +cmp "$W/sidekicks.dmg" "dist/${names[0]}" && echo "copie identique" |
| 176 | +spctl -a -vvv -t open --context context:primary-signature "dist/${names[0]}" # accepted · Notarized Developer ID | ||
| 177 | +(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > "$W/SHA256SUMS") && cp "$W/SHA256SUMS" dist/SHA256SUMS | ||
| 150 | cat dist/SHA256SUMS | 178 | cat dist/SHA256SUMS |
| 151 | ``` | 179 | ``` |
| 152 | 180 | ||
| 153 | -### B6. Essayer sur un autre Mac | 181 | +Ne passez pas à la suite si `cmp` signale une différence ou si `spctl` refuse : `dist/` contiendrait encore le `.dmg` non signé de B1, et la release aussi. |
| 182 | + | ||
| 183 | +### B8. Essayer sur un autre Mac | ||
| 154 | 184 | ||
| 155 | 1. Copiez le `.dmg` sur un autre Mac (ou un autre compte utilisateur), par le web ou AirDrop : il doit porter l'attribut de quarantaine d'un vrai téléchargement. | 185 | 1. Copiez le `.dmg` sur un autre Mac (ou un autre compte utilisateur), par le web ou AirDrop : il doit porter l'attribut de quarantaine d'un vrai téléchargement. |
| 156 | 2. Ouvrez-le, glissez **sidekicks** dans **Applications**, lancez-le : il s'ouvre directement, sans **Ouvrir quand même**. | 186 | 2. Ouvrez-le, glissez **sidekicks** dans **Applications**, lancez-le : il s'ouvre directement, sans **Ouvrir quand même**. |
| 157 | 3. Faites le tour de ce que le runtime renforcé pourrait gêner : un agent local, un agent en conteneur ou en sbx, l'onglet Terminal, l'ouverture d'un fichier, le glisser-déposer, Settings → Open…. | 187 | 3. Faites le tour de ce que le runtime renforcé pourrait gêner : un agent local, un agent en conteneur ou en sbx, l'onglet Terminal, l'ouverture d'un fichier, le glisser-déposer, Settings → Open…. |
| 158 | 188 | ||
| 159 | -### B7. Taguer et publier | 189 | +### B9. Taguer et publier |
| 160 | 190 | ||
| 161 | -Suivez la suite de [RELEASING.fr.md](../../../RELEASING.fr.md) (étapes 2 à 4) : les fichiers à attacher sont ceux de `dist/`. | 191 | +Suivez la suite de [RELEASING.fr.md](../../../RELEASING.fr.md) (étapes 2 à 4) : les fichiers à attacher sont ceux de `dist/`. Une fois la release publiée, téléchargez son `.dmg` et vérifiez que `shasum -a 256` donne la même somme que `SHA256SUMS` (un envoi tronqué donne aussi « image endommagée »). Supprimez ensuite `$W` et relancez la synchronisation. |
| 162 | 192 | ||
| 163 | ## Variantes | 193 | ## Variantes |
| 164 | 194 | ||
| 165 | - **Release macOS à part, sur une version déjà publiée** (par exemple `v1.0.0-macos`, issue #57) : **ne changez pas** `info.version` (l'app reste la `1.0.0` ; Windows refuse une version qui n'est pas faite de nombres, Apple aussi pour `CFBundleShortVersionString`, et les paquets s'appelleraient `…-1.0.0-macos-macos-…`). Construisez seulement macOS avec `SKIP=windows make release-build`, faites la partie B, puis créez le tag à la main : `git tag -a v1.0.0-macos -m "Sidekicks 1.0.0, macOS signé et notarisé" && git push origin v1.0.0-macos`. Le workflow **Release** démarre et s'arrête à sa vérification (le tag n'est pas `v` + la version de `build/config.yml`) : c'est attendu. Créez la release sur Rickub depuis ce tag et attachez le `.dmg`, le `.zip` et `SHA256SUMS`. Vous pouvez aussi simplement remplacer les fichiers macOS de la release `v1.0.0`. | 195 | - **Release macOS à part, sur une version déjà publiée** (par exemple `v1.0.0-macos`, issue #57) : **ne changez pas** `info.version` (l'app reste la `1.0.0` ; Windows refuse une version qui n'est pas faite de nombres, Apple aussi pour `CFBundleShortVersionString`, et les paquets s'appelleraient `…-1.0.0-macos-macos-…`). Construisez seulement macOS avec `SKIP=windows make release-build`, faites la partie B, puis créez le tag à la main : `git tag -a v1.0.0-macos -m "Sidekicks 1.0.0, macOS signé et notarisé" && git push origin v1.0.0-macos`. Le workflow **Release** démarre et s'arrête à sa vérification (le tag n'est pas `v` + la version de `build/config.yml`) : c'est attendu. Créez la release sur Rickub depuis ce tag et attachez le `.dmg`, le `.zip` et `SHA256SUMS`. Vous pouvez aussi simplement remplacer les fichiers macOS de la release `v1.0.0`. |
| 166 | - **La notarisation est refusée** (`status: Invalid`) : `xcrun notarytool log <id> --keychain-profile "$SIDEKICKS_NOTARY_PROFILE"` donne la raison. Les plus courantes : signature sans `--options runtime` ou sans `--timestamp`, ou un fichier non signé dans l'app. | 196 | - **La notarisation est refusée** (`status: Invalid`) : `xcrun notarytool log <id> --keychain-profile "$SIDEKICKS_NOTARY_PROFILE"` donne la raison. Les plus courantes : signature sans `--options runtime` ou sans `--timestamp`, ou un fichier non signé dans l'app. |
| 167 | -- **`codesign` refuse (« resource fork, Finder information, or similar detritus »)** : le dépôt est dans un dossier synchronisé, qui ajoute des métadonnées. `xattr -cr bin/sidekicks.app` puis recommencez ; si cela revient, copiez l'app dans `/tmp` et signez-la là. | 197 | +- **« L'image disque est endommagée » à l'ouverture du `.dmg`** : il a été modifié après sa signature (dossier synchronisé) ou tronqué (envoi, téléchargement). `hdiutil verify` sur le fichier et `shasum -a 256` comparé à `SHA256SUMS` disent lequel. Refaites B2 à B7 avec la synchronisation en pause (ou avec `$W` dans `/tmp`). |
| 198 | +- **`codesign` refuse (« resource fork, Finder information, or similar detritus »)** : l'app vient d'un dossier synchronisé, qui ajoute des métadonnées. `xattr -cr "$W/sidekicks.app"` puis recommencez B3. | ||
| 168 | - **L'app signée ne démarre pas ou une fonction ne marche plus** : le runtime renforcé bloque quelque chose. Lisez **Console.app** au lancement ; si un droit précis manque, ajoutez un fichier d'entitlements (`--entitlements build/darwin/entitlements.plist` dans B2) avec seulement ce droit, et notez-le dans l'issue #57. | 199 | - **L'app signée ne démarre pas ou une fonction ne marche plus** : le runtime renforcé bloque quelque chose. Lisez **Console.app** au lancement ; si un droit précis manque, ajoutez un fichier d'entitlements (`--entitlements build/darwin/entitlements.plist` dans B2) avec seulement ce droit, et notez-le dans l'issue #57. |
| 169 | - **Vérifier une app installée** : `spctl -a -vvv /Applications/sidekicks.app` et `xcrun stapler validate /Applications/sidekicks.app`. | 200 | - **Vérifier une app installée** : `spctl -a -vvv /Applications/sidekicks.app` et `xcrun stapler validate /Applications/sidekicks.app`. |
| 170 | - **Un autre Mac pour construire** : importez le `.p12` (double-clic), puis refaites A6 et A7. | 201 | - **Un autre Mac pour construire** : importez le `.p12` (double-clic), puis refaites A6 et A7. |
| 202 | +- **Le `.dmg` à refaire, l'app déjà notarisée** : si `$W/sidekicks.app` est encore là et que `xcrun stapler validate "$W/sidekicks.app"` réussit, reprenez directement à B5. | ||
| 171 | 203 | ||
| 172 | ## Voir aussi | 204 | ## Voir aussi |
| 173 | 205 | ||