Promo

CI iOS/macOS sur Mac cloud Apple Silicon : codesign, Notarization, stapler et frontières du trousseau — pipelines reproductibles et tableau de codes de rejet

CI Déploiement et dépannage
2026-05-07 Environ 8 min de lecture

Faire tourner des builds iOS et macOS sur un Mac cloud Apple Silicon, c’est moins une affaire de drapeaux Xcode qu’une question de l’endroit où vivent les secrets : un trousseau de session dédié à la CI, des entrées codesign prévisibles, une soumission notarytool, puis stapler sur l’artefact distribué. Cet article trace une frontière nette entre postes de développement interactifs et runners non interactifs, propose un ordre minimal et reproductible, et se termine par un tableau compact symptôme – cause – action pour les échecs courants de notarisation et de signature.

Points clés

  1. Créez un fichier de trousseau dédié à la CI, importez-y les identités de distribution et déverrouillez-le à l’aide d’un mot de passe à durée de vie courte issu de votre coffre — ne dépendez jamais du trousseau de session par défaut au travers des redémarrages.
  2. Signez avec un --keychain / CODE_SIGN_KEYCHAIN explicite et vérifiez via security find-identity -v -p codesigning dans le même contexte shell que le build.
  3. Après xcodebuild archive/export, exécutez notarytool submit → poll → stapler staple sur le bundle externe ou l’image disque réellement téléchargée par les utilisateurs ; agrafer un binaire interne seul est un oubli fréquent.
  4. Le dimensionnement des runners et le comportement des files d’attente recoupent le choix entre Mac hébergé et Mac cloud dédié — croisez ces décisions avec un pipeline conteneurisé partageant la même machine.
Espace de travail développeur avec ordinateur portable et code, illustrant CI Mac cloud et flux de signature
Image illustrative ; en production, validez avec un vrai codesign -dv, des extraits du journal du notary et la présence du ticket sur l’artefact livré.

1. Frontières du trousseau sur des hôtes non interactifs

Les utilisateurs CI Mac cloud sont rarement à la console : tout ce qui suppose une approbation graphique ou les valeurs par défaut du trousseau de session deviendra instable après un rafraîchissement d’image. Standardisez sur un trousseau fichier (par exemple ~/Library/Keychains/ci-signing.keychain-db), importez le certificat Apple Distribution et la clé privée, fixez un mot de passe connu, et déverrouillez en début de job avec security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH". Faites de KEYCHAIN_PATH la seule source de vérité et passez-la à xcodebuild via OTHER_CODE_SIGN_FLAGS=--keychain "$KEYCHAIN_PATH" ou le réglage projet équivalent. Évitez de mélanger les identités Developer ID et Apple Distribution dans la même chaîne, sauf si votre ExportOptions.plist encode déjà la bonne équipe et le bon profil. Si la même machine héberge un démon Docker pour des outils de build auxiliaires, gardez disponibilités SSD et bind mounts dans le même runbook que la signature — comparez avec le guide Docker de production sur Mac cloud Apple Silicon (arm64/amd64, bind mounts et cache de build) pour cadrer le budget mémoire et disque partagé.

2. Couches codesign : entitlements, hardened runtime et bundles imbriqués

Une signature reproductible signifie les mêmes hachages d’entitlements plist et de profil de provisioning à chaque build. Après l’export, lancez codesign --verify --deep --strict sur le bundle de l’app, et pour les outils auxiliaires des PlugIns ou Frameworks, vérifiez que chaque cible imbriquée porte des Team ID cohérents et les drapeaux hardened-runtime attendus. Les divergences se manifestent souvent comme errSecInternalComponent ou errSecMissingEntitlement au moment de productbuild ou notarytool, longtemps après que l’app principale a semblé signer proprement. Lorsque vous emballez un .pkg, signez les composants du bas vers le haut, puis le paquet avec le certificat installeur documenté dans votre runbook.

3. Notarization et stapler : un ordre strict

Utilisez notarytool avec une clé d’API App Store Connect (issuer, key ID, chemin de clé privée) stockée hors du dépôt — préférez l’injection de chemins par variable d’environnement à la livraison de fichiers .p8 dans le repo, et traitez les flux Transporter comme du legacy sauf contrainte fournisseur stricte. Soumettez le binaire exact que Gatekeeper évaluera — typiquement le zip, le bundle d’app ou le .dmg prêt à être notarisé — puis attendez Accepted avant d’agrafer. Lancez xcrun stapler staple <chemin> et vérifiez avec stapler validate. Si vous agrafez avant le retour positif d’Apple, ou si vous n’agrafez qu’un .app interne tout en livrant une archive externe recompressée, vos clients voient des hachages différents de ceux que le service de notary a enregistrés. Conservez la rotation des clés d’API et les submission IDs dans les journaux de modifications afin de corréler l’historique App Store Connect avec les logs CI ; quand Apple rejette un envoi, récupérez le journal JSON via notarytool log <submission-id> et joignez le premier rule ID en échec à votre ticket.

4. Checklist pipeline (minimale)

  1. Déverrouiller le trousseau CI ; confirmer les identités via security find-identity.
  2. Vider DerivedData pour diagnostiquer un profil obsolète ; sinon, privilégier les builds incrémentaux avec versions de dépendances figées.
  3. Archiver et exporter avec un ExportOptions.plist figé ; uploader le dSYM séparément de la notarisation.
  4. Soumettre à Apple ; attendre Accepted ; agrafer ; valider ; publier les checksums à côté des artefacts.

Les helpers de build conteneurisés tournant sur le même hôte ont besoin de montages corrects et de marge disque — adossez cette checklist au runbook conteneurs lorsque Docker et Xcode partagent la même machine. Pour les arbitrages d’architecture et la politique de cache BuildKit côté CI, voyez aussi WireGuard et appairage passerelle pour le contrôle à distance transfrontalier (MTU, DNS, latence) si vos runners doivent rester joignables depuis plusieurs régions.

5. Symptôme – cause – action (signature et notarisation)

Symptôme / extrait de log Cause racine probable Action privilégiée
errSecInternalComponent à la signature Clé privée inutilisable dans le trousseau CI ; ACL ou mot de passe désaligné Ré-importer clé + cert ; déverrouiller le trousseau dans le job ; passer un --keychain explicite
No signing certificate found Liste de recherche du trousseau erronée ou profil de provisioning manquant Définir CODE_SIGN_KEYCHAIN ; vérifier l’UUID du profil dans ~/Library/MobileDevice/Provisioning Profiles
Notarisation Invalid avec hardened runtime Entitlement non autorisé en distribution ; helper imbriqué non signé Comparer entitlements aux docs Apple ; deep-verify les bundles imbriqués
Gatekeeper continue de mettre en quarantaine après un « succès » CI Stapler non exécuté sur l’artefact livré ; zip recompressé qui invalide le ticket Agrafer le livrable le plus externe ; valider ; ne pas re-paquetiser après agrafage
Erreurs d’authentification notarytool Issuer / key ID erronés ; dérive d’horloge ; clé d’API révoquée Faire tourner la clé ; synchroniser le temps (NTP) ; stocker le JSON hors du dépôt

6. Conclusion

Traitez signature, notarisation et agrafage comme une seule machine à états : les entrées de chaque étape sont les sorties de la précédente. Documentez le chemin du trousseau, les UUID de profil et les submission IDs du notary dans la même entrée de runbook, afin que la prochaine astreinte n’ait pas à deviner quelle identité était en service. Une fois la chaîne stabilisée, exécutez un build à froid sur une image runner fraîche pour prouver que le processus survit aux redémarrages et à la rotation des credentials.

Pourquoi un Mac mini cloud convient à une CI à signature lourde

Apple Silicon vous donne une chaîne d’outils arm64 native sans surprises d’émulation, et la mémoire unifiée garde Xcode, simulateurs et agents légers dans un même bassin prévisible. macOS intègre Gatekeeper, SIP et des protections de type FileVault qui réduisent les risques d’altération par rapport à des VM Windows de build improvisées, tandis que la consommation au repos d’un Mac mini M reste basse pour des runners 7 × 24. Un Mac cloud dédié évite la contention « voisin bruyant » sur le débit de signature et l’I/O disque — là où les files d’attente SaaS partagées font le plus mal — et le format compact garde le coût total de possession raisonnable face au renouvellement de flottes d’ordinateurs portables transformés en CI ad hoc.

Si vous voulez un matériel Apple stable et natif pour des pipelines de signature reproductibles, le Mac mini M4 cloud kvmboot est un point de départ pratiqueconsultez les forfaits et tarifs et alignez la disposition du trousseau avec les paliers que vous provisionnez.