Signer et notariser Sidekicks pour macOS
Ce guide montre comment signer Sidekicks avec un certificat Developer ID et le faire notariser par Apple, pour qu'il s'ouvre sur n'importe quel Mac sans passer par Ouvrir quand même. Il suppose une adhésion payante à l'Apple Developer Program dont vous êtes le titulaire du compte (Account Holder : seul ce rôle peut créer un certificat Developer ID), un Mac Apple Silicon avec les outils de développement du projet (Développer l'application), et une release déjà construite comme le décrit RELEASING.fr.md.
- La partie A se fait une seule fois (compter 30 minutes).
- La partie B se fait à chaque release, après
make release-build, tant que la signature n'est pas automatisée (issue #58). Comptez 10 à 20 minutes, surtout de l'attente chez Apple.
Gardez une fenêtre du Terminal ouverte à la racine du dépôt.
Ce que font signature et notarisation
| Étape | Outil | Ce qu'elle apporte |
|---|---|---|
| Signer | codesign avec votre certificat Developer ID |
macOS sait qui a fait l'app et qu'elle n'a pas été modifiée |
| Runtime renforcé | codesign --options runtime |
exigé par Apple pour notariser |
| Notariser | xcrun notarytool |
Apple analyse l'app et délivre un « ticket » |
| Agrafer | xcrun stapler |
le ticket est collé à l'app et au .dmg : Gatekeeper l'accepte même hors ligne |
L'app et le .dmg sont signés, notarisés et agrafés. Le .zip contient l'app agrafée.
Partie A — une seule fois
A1. Relever votre Team ID
- Ouvrez developer.apple.com/account, section Membership details.
- Notez le Team ID (10 caractères, par exemple
AB12CD34EF).
A2. Créer le certificat Developer ID Application
Avec Xcode (le plus simple) :
- Ouvrez Xcode → Settings… → Accounts. S'il n'y est pas, cliquez sur +, choisissez Apple ID et connectez-vous avec l'adresse e-mail et le mot de passe de votre compte Apple Developer (l'Apple ID, pas le Team ID).
- Votre équipe apparaît sous le compte, avec son Team ID : sélectionnez-la, cliquez sur Manage Certificates….
- Cliquez sur + en bas à gauche, puis Developer ID Application.
Sans Xcode :
- Ouvrez Trousseaux d'accès → Assistant de certification → Demander un certificat à une autorité de certification…, indiquez votre adresse, cochez Enregistré sur le disque. Vous obtenez un fichier
.certSigningRequest. - Sur developer.apple.com/account/resources/certificates, choisissez Developer ID Application, profil G2 Sub-CA, envoyez le fichier de demande, puis téléchargez le certificat.
- Double-cliquez sur le fichier
.cer: il rejoint le trousseau session.
A3. Vérifier que le certificat est utilisable
security find-identity -v -p codesigning
Une ligne "Developer ID Application: Prénom Nom (AB12CD34EF)" doit apparaître. C'est votre identité de signature : copiez-la exactement, guillemets exclus.
Si elle manque, ou s'affiche avec CSSMERR_TP_NOT_TRUSTED, installez le certificat intermédiaire Developer ID - G2 depuis apple.com/certificateauthority, puis relancez la commande.
A4. Sauvegarder le certificat et sa clé
La clé privée n'existe que sur ce Mac : sans sauvegarde, une panne oblige à révoquer le certificat et à en refaire un.
- Dans Trousseaux d'accès, trousseau session, catégorie Mes certificats, dépliez Developer ID Application: … (la clé apparaît dessous).
- Sélectionnez le certificat, Fichier → Exporter les éléments…, format .p12, choisissez un mot de passe.
- Rangez le
.p12et son mot de passe dans votre gestionnaire de mots de passe. Ne le mettez jamais dans le dépôt.
A5. Créer un mot de passe d'application pour la notarisation
- Ouvrez account.apple.com, Connexion et sécurité → Mots de passe pour les apps.
- Créez-en un nommé
sidekicks-notaryet copiez-le (il ne sera plus affiché).
A6. Enregistrer le profil de notarisation dans le trousseau
xcrun notarytool store-credentials sidekicks-notary \
--apple-id "vous@example.com" \
--team-id "AB12CD34EF"
Collez le mot de passe d'application quand il est demandé. Vérifiez :
xcrun notarytool history --keychain-profile sidekicks-notary
Une liste (vide la première fois) s'affiche, sans erreur d'authentification.
A7. Définir les deux variables
Ajoutez à votre ~/.zshrc, puis ouvrez un nouveau Terminal :
export SIDEKICKS_SIGN_IDENTITY="Developer ID Application: Prénom Nom (AB12CD34EF)"
export SIDEKICKS_NOTARY_PROFILE="sidekicks-notary"
La partie B les utilise ; l'automatisation (issue #58) les utilisera aussi.
A8. Garder l'identifiant de l'app
CFBundleIdentifier vaut com.k33g.sidekicks dans build/darwin/Info.plist (et Info.dev.plist). Ne le changez plus : macOS y rattache les autorisations accordées à l'app.
Partie B — à chaque release
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).
B1. Construire la release
Comme d'habitude (RELEASING.fr.md, étapes Avant et 1) :
make release-build # ou SKIP=windows make release-build pour une release macOS seule
dist/ contient les paquets non signés, et bin/sidekicks.app l'app signée en ad hoc.
B2. Copier l'app dans le dossier de travail
W="$PWD/bin/sign"
rm -rf "$W" && mkdir -p "$W"
ditto bin/sidekicks.app "$W/sidekicks.app"
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)".
B3. Signer l'app
xattr -cr "$W/sidekicks.app"
codesign --force --options runtime --timestamp \
--sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.app"
codesign --verify --strict --verbose=2 "$W/sidekicks.app"
codesign -dv --verbose=4 "$W/sidekicks.app" 2>&1 | grep -E "Authority=Developer ID Application|flags=.*runtime|Timestamp="
La dernière commande doit afficher l'autorité Developer ID Application, le drapeau runtime et une ligne Timestamp.
B4. Notariser l'app et agrafer le ticket
ditto -c -k --keepParent "$W/sidekicks.app" "$W/notarize.zip"
xcrun notarytool submit "$W/notarize.zip" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait
xcrun stapler staple "$W/sidekicks.app"
spctl -a -vvv -t exec "$W/sidekicks.app"
notarytool attend la réponse d'Apple (quelques minutes) et doit finir par status: Accepted. spctl doit dire accepted et source=Notarized Developer ID.
B5. Faire le .dmg à partir de l'app agrafée
wails3 tool package --format dmg --name sidekicks --out "$W" \
--background build/darwin/dmg-background.png \
--volume-icon build/darwin/icons.icns \
--file-icon build/darwin/dmg-file-icon.icns \
--window-width 540 --window-height 380
hdiutil verify "$W/sidekicks.dmg"
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.
B6. Signer, notariser et agrafer le .dmg
codesign --force --timestamp --sign "$SIDEKICKS_SIGN_IDENTITY" "$W/sidekicks.dmg"
xcrun notarytool submit "$W/sidekicks.dmg" --keychain-profile "$SIDEKICKS_NOTARY_PROFILE" --wait
xcrun stapler staple "$W/sidekicks.dmg"
hdiutil verify "$W/sidekicks.dmg"
spctl -a -vvv -t open --context context:primary-signature "$W/sidekicks.dmg"
hdiutil attach -nobrowse -readonly "$W/sidekicks.dmg" && hdiutil detach "/Volumes/sidekicks"
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é.
B7. Remplacer les paquets macOS de dist/ et recalculer les sommes
DMG=$(scripts/package.sh names macos arm64 | sed -n 1p) # le .dmg et le .zip, avec la version de build/config.yml
ZIP=$(scripts/package.sh names macos arm64 | sed -n 2p)
echo "$W · $DMG · $ZIP" # aucune des trois valeurs ne doit être vide
rm -f dist/sidekicks.dmg # un reste éventuel d'une copie ratée
cp "$W/sidekicks.dmg" "dist/$DMG"
rm -f "dist/$ZIP" && ditto -c -k --keepParent "$W/sidekicks.app" "dist/$ZIP"
cmp "$W/sidekicks.dmg" "dist/$DMG" && echo "copie identique"
spctl -a -vvv -t open --context context:primary-signature "dist/$DMG" # accepted · Notarized Developer ID
(cd dist && rm -f SHA256SUMS && shasum -a 256 -- * > "$W/SHA256SUMS") && cp "$W/SHA256SUMS" dist/SHA256SUMS
cat dist/SHA256SUMS
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.
B8. Essayer sur un autre Mac
- Copiez le
.dmgsur 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. - Ouvrez-le, glissez sidekicks dans Applications, lancez-le : il s'ouvre directement, sans Ouvrir quand même.
- 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….
B9. Taguer et publier
Suivez la suite de 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.
Variantes
- Release macOS à part, sur une version déjà publiée (par exemple
v1.0.0-macos, issue #57) : ne changez pasinfo.version(l'app reste la1.0.0; Windows refuse une version qui n'est pas faite de nombres, Apple aussi pourCFBundleShortVersionString, et les paquets s'appelleraient…-1.0.0-macos-macos-…). Construisez seulement macOS avecSKIP=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 pasv+ la version debuild/config.yml) : c'est attendu. Créez la release sur Rickub depuis ce tag et attachez le.dmg, le.zipetSHA256SUMS. Vous pouvez aussi simplement remplacer les fichiers macOS de la releasev1.0.0. - 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 runtimeou sans--timestamp, ou un fichier non signé dans l'app. - « 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 verifysur le fichier etshasum -a 256comparé àSHA256SUMSdisent lequel. Refaites B2 à B7 avec la synchronisation en pause (ou avec$Wdans/tmp). codesignrefuse (« 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.- 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.plistdans B2) avec seulement ce droit, et notez-le dans l'issue #57. - Vérifier une app installée :
spctl -a -vvv /Applications/sidekicks.appetxcrun stapler validate /Applications/sidekicks.app. - Un autre Mac pour construire : importez le
.p12(double-clic), puis refaites A6 et A7. - Le
.dmgà refaire, l'app déjà notarisée : si$W/sidekicks.appest encore là et quexcrun stapler validate "$W/sidekicks.app"réussit, reprenez directement à B5.
Voir aussi
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 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
|