Dans le flux CI décrit par Apple pour les projets Swift et les applications, quatre zones doivent être distinguées : résolution des versions, connexion aux dépôts Git, téléchargement des artefacts binaires et compilation. La recommandation opérationnelle est donc immédiate : ne supprimez pas d’abord le cache et n’ouvrez pas un identifiant partagé ; validez Package.resolved, l’identité du compte de service et une clé SSH en lecture seule, puis seulement le cache. Les dépendances privées doivent être résolues sur un périmètre séparé de la signature de production.
Cet article est destiné aux équipes qui maintiennent des projets iOS ou macOS contenant des Swift Packages privés et dont le poste local fonctionne alors que l’agent CI échoue. Il concerne aussi les équipes qui administrent Jenkins, GitHub Actions, GitLab ou un autre agent Mac autogéré, ainsi que les responsables sécurité et IT qui doivent évaluer l’isolement d’un Mac distant.
SECTION 01 Le diagnostic commence par les responsabilités, pas par le cache
Responsable technique : établir la frontière exacte de l’échec
Le premier livrable n’est pas une modification de pipeline, mais une fiche de reproduction. Pour le même commit, consignez :
- le dépôt et le projet ou espace de travail concernés ;
- la valeur de
Package.resolvedutilisée ; - le compte macOS qui lance réellement
xcodebuild; - le point de terminaison qui échoue ;
- la commande minimale exécutée ;
- le code de sortie et les journaux associés.
Cette fiche doit séparer quatre phases. Une erreur de résolution peut signaler un fichier absent, incohérent ou modifié automatiquement. Une erreur de connexion Git indique plutôt un problème d’URL, de clé, de known_hosts, de proxy ou de configuration SCM. Un téléchargement binaire qui échoue ne prouve pas que le dépôt source est inaccessible. Enfin, une compilation interrompue après une résolution réussie relève d’un autre périmètre : outil, architecture, module ou environnement de build.
Point de contrôle : si votre rapport contient seulement « Swift Package Manager ne télécharge pas le package », il est trop imprécis pour attribuer une action. Le ticket doit préciser la phase, l’identité d’exécution, l’URL et le statut de sortie.
Équipe applicative : rendre la version résolue vérifiable
Package.swift décrit les contraintes de dépendances ; Package.resolved conserve la sélection effectivement résolue pour le projet de premier niveau. La documentation officielle de Swift Package Manager sur la résolution des versions explique le rôle de cette résolution et les conséquences d’une mise à jour.
Pour la CI de production, vérifiez successivement que :
- le fichier se trouve au niveau attendu par le projet ou l’espace de travail ;
- il est bien présent dans le contrôle de version ;
- sa modification passe par une revue de code ;
- le pipeline utilise le même commit que celui examiné ;
- aucune étape préalable ne réécrit les dépendances sans décision explicite.
Une tâche d’actualisation des dépendances et une tâche de construction reproductible ne doivent pas avoir le même comportement. La première peut proposer une nouvelle sélection de versions dans une branche dédiée. La seconde doit consommer la sélection validée et signaler toute divergence, au lieu de la corriger silencieusement.
Pour établir une preuve indépendante du poste du développeur, lancez la résolution avec un compte propre, dans un espace de travail propre, sur le commit concerné. La commande doit rester minimale, par exemple xcodebuild -resolvePackageDependencies avec les paramètres réellement utilisés par votre projet. Le guide Apple consacré aux workflows CI doit être la référence lorsque vous choisissez le comportement de résolution et de construction.
Responsable des composants : inventorier les accès directs et transitifs
Le dépôt visible dans Package.swift n’est pas nécessairement le seul accès effectué pendant la résolution. Un package privé peut lui-même référencer un autre package privé, ou une cible binaire peut télécharger un artefact depuis un emplacement distinct. La documentation Apple sur Package.Dependency aide à distinguer les formes de dépendances déclarées, mais votre inventaire doit aussi couvrir les dépendances transitives observées dans le projet réel.
Créez une liste d’éléments comprenant :
- les dépôts Git directs ;
- les dépôts appelés par les packages internes ;
- les URL de registres ou d’artefacts binaires ;
- les éventuels miroirs et règles de réécriture ;
- les hôtes effectivement contactés pendant la résolution.
Ensuite, choisissez une méthode d’accès approuvée. Mélanger une URL SSH pour un dépôt et une URL HTTPS réécrite pour sa dépendance peut produire une identité inattendue, surtout si la configuration globale Git de l’administrateur n’est pas celle du compte CI. La documentation de Swift Package Manager sur l’ajout de dépendances fournit le cadre de déclaration ; elle ne remplace pas l’inventaire des règles locales de votre agent.
Chaque autorisation doit être limitée aux dépôts nécessaires et à la lecture lorsque l’étape ne publie rien. Conservez la date de création, la personne responsable, la procédure de rotation et la preuve de révocation. Une clé qui fonctionne n’est pas encore une clé correctement gouvernée.
SECTION 02 Le compte qui lance xcodebuild doit devenir votre seule référence
Équipe plateforme : reconstruire le contexte SSH réel
Le test effectué dans un Terminal ouvert par un administrateur ne valide pas un agent CI. Vous devez exécuter les vérifications avec le compte macOS qui lance la tâche non interactive. Relevez son HOME, son répertoire de travail, son PATH, son SSH_AUTH_SOCK et sa configuration Git effective. Contrôlez également :
- la présence du fichier
known_hostsau bon emplacement ; - les permissions restrictives de la clé privée ;
- l’existence ou non d’un
ssh-agent; - les règles
HostetIdentityFileappliquées ; - le proxy ou le miroir utilisé par cette identité ;
- le fournisseur SCM choisi par l’outil de construction.
Pour une résolution SSH, la commande de test doit cibler le même hôte que le package et produire une preuve exploitable, sans afficher la clé privée. Selon votre hébergeur Git, une commande de type ssh -T peut confirmer l’identité reconnue ; son message de succès ou d’échec doit être conservé dans le rapport, sans être confondu avec une résolution complète.
L’accès à une clé ne doit jamais reposer sur l’héritage implicite de la session d’un administrateur. Si votre plateforme injecte temporairement un secret, documentez son emplacement, sa durée de vie et son nettoyage. Si vous utilisez une configuration Git système ou une réécriture d’URL, déclarez-la explicitement dans l’agent concerné et testez-la avec le compte de service.
Séquence de validation à exécuter après chaque correction
Ne relancez pas immédiatement toute la chaîne de publication. Utilisez une progression qui permet d’identifier le moment où la preuve devient valide :
- Reproduisez la résolution depuis un espace de travail propre avec le compte CI réel.
- Vérifiez l’accès à chaque hôte privé et à chaque dépôt transitif.
- Lancez une compilation minimale qui consomme les packages résolus.
- Redémarrez l’agent ou le Mac de build, puis répétez la résolution.
- Rejouez la tâche sur un nœud nouvellement livré ou réinitialisé.
- Comparez les journaux, les identités et les fichiers générés avec ceux du nœud initial.
La séquence n’a pas pour but de mesurer une durée moyenne non documentée ; elle sert à démontrer que la correction ne dépend ni d’une session interactive, ni d’un cache personnel, ni d’un fichier résiduel. Une résolution réussie avant redémarrage mais échouant après redémarrage signale une injection de secret ou une configuration non persistante, pas un défaut aléatoire de Swift Package Manager.
À ne pas mélanger :
Package.resolvedcontrôle la sélection des versions ; le cache conserve des données déjà récupérées ; la clé SSH autorise l’accès au dépôt ; le trousseau de signature autorise une opération Apple distincte. Modifier l’un ne corrige pas automatiquement les trois autres.
SECTION 03 La séparation des identifiants devient une exigence d’architecture
Sécurité et publication : isoler les secrets par fonction
Une clé qui lit un dépôt privé ne doit pas être stockée avec une clé privée Apple, un jeton de publication ou un compte administrateur partagé. Les fonctions doivent être séparées :
- identité de lecture des dépendances privées ;
- identité de construction ;
- identité de signature ;
- identité de publication ;
- identité d’administration du nœud.
Un service account peut disposer d’une clé de lecture limitée à un groupe de dépôts, tandis que la signature de production est disponible uniquement sur un nœud ou dans un trousseau temporaire prévu pour cette tâche. Les branches non fiables, les contributions externes et les demandes de fusion ordinaires ne doivent pas recevoir l’accès complet aux dépendances privées de production et aux actifs de signature.
L’isolement doit aussi concerner le disque. Utilisez un espace de travail distinct par tâche ou par périmètre de confiance, évitez les répertoires persistants partagés et supprimez les secrets, journaux sensibles et fichiers temporaires à la fin du travail. Si un cache est conservé, définissez ce qu’il peut contenir, qui peut le lire et selon quelle procédure il est invalidé.
Pour une équipe qui utilise un Mac distant sans droits administrateur, le contrôle ne s’arrête pas à l’accès graphique. Vous devez aussi examiner les comptes locaux, les sessions SSH, les volumes de travail et les mécanismes de réinitialisation. Un accès VNC pratique ne justifie jamais le partage d’une clé de production.
Quand faut-il séparer le nœud de dépendances du nœud de signature ?
Si la résolution privée et la signature exécutent des tâches avec des niveaux de confiance différents, séparez-les par défaut. Un nœud capable de lire des dépôts privés peut traiter du code ou des scripts qui ne doivent pas atteindre une clé de publication. Inversement, un nœud de signature ne devrait pas servir de bac à sable permanent pour toutes les branches et tous les essais de dépendances.
La séparation est particulièrement importante lorsque plusieurs projets partagent un Mac. Elle devient un critère de rejet si vous ne pouvez pas démontrer :
- quel compte lance chaque tâche ;
- quels dépôts ce compte peut lire ;
- où résident les clés ;
- quand elles sont injectées et supprimées ;
- comment le nœud est nettoyé après un échec ;
- comment un autre projet est empêché de lire les artefacts précédents.
Un Mac partagé peut convenir à une équipe de confiance lorsque les comptes, les espaces de travail et les credentials sont réellement séparés. Il ne convient pas comme nœud de signature commun si les journaux, les caches ou les sessions persistantes permettent à une tâche de voir les secrets d’une autre.
SECTION 04 Décision opérationnelle : réparer, isoler ou remplacer le nœud
Utilisez les conditions suivantes après la première campagne de validation :
- Si
Package.resolvedest versionné, la résolution propre réussit avec le compte réel et le nœud survit au redémarrage, choisissez la réparation documentée du nœud existant. - Si la résolution réussit seulement grâce à un cache résiduel, revenez à une validation sur espace propre avant toute mise en production.
- Si plusieurs projets ont besoin de dépôts distincts mais que les identités ne peuvent pas être séparées, choisissez un nœud dédié par périmètre de confiance.
- Si les branches non fiables peuvent atteindre une clé de signature, revenez à un pool de construction sans signature, puis réservez la publication à un nœud séparé.
- Si l’identité SSH varie entre le Terminal administrateur et l’agent, choisissez la correction du compte de service avant de modifier les règles réseau.
- Si un Mac physique partagé ne permet pas de prouver le nettoyage après tâche, choisissez un Mac distant isolé ou une remise à zéro vérifiable.
- Si la capacité varie fortement entre les campagnes de build, choisissez une architecture avec nœud temporaire pour la résolution et nœud de publication séparé, plutôt que de surcharger la machine de signature.
Les deux options ne se valent pas en coût opérationnel. Réparer un nœud existant conserve les outils et les habitudes, mais prolonge une dette de configuration si le compte, le cache et les secrets restent difficiles à auditer. Ajouter un nœud isolé augmente la surface d’administration, mais rend la preuve de séparation plus simple et limite le rayon d’impact d’une clé compromise.
Voici la matrice à remettre au responsable de plateforme avant de modifier la capacité :
| Situation observée | Action immédiate | Preuve attendue |
|---|---|---|
| Échec avant tout accès Git | Contrôler Package.resolved et le contexte du projet |
Fichier versionné, commit identifié, journal de résolution |
| Échec sur un dépôt privé | Tester le compte CI, SSH et known_hosts |
Hôte, identité reconnue, statut de sortie |
| Échec sur une dépendance transitive | Inventorier les URL indirectes et les règles de réécriture | Liste des endpoints et autorisations correspondantes |
| Résolution réussie, compilation échouée | Séparer dépendance, outil et signature | Journal de résolution distinct du journal de build |
| Réussite seulement après session interactive | Corriger l’injection et le HOME du service account | Reproduction non interactive après redémarrage |
| Accès privé et signature sur le même périmètre | Créer un pool séparé | Comptes, clés, espaces de travail et nettoyage vérifiables |
Le choix du support doit ensuite tenir compte du type de travail. Un nœud local acheté peut être pertinent pour une charge stable, un accès physique obligatoire ou une équipe qui possède déjà les compétences d’exploitation. Un Mac distant est plus adapté lorsque vous devez ouvrir temporairement une capacité de build, tester une nouvelle séparation ou fournir un environnement Apple à une équipe distribuée sans acheter un poste pour chaque développeur.
| Option d’infrastructure | Dépendances privées | Séparation des secrets | Reprise après incident | Cas où elle est cohérente |
|---|---|---|---|---|
| Mac partagé durable | Possible, mais exige des comptes et espaces distincts | Moyenne si les règles sont bien contrôlées | Dépend fortement du nettoyage | Petite équipe de confiance avec procédures strictes |
| Mac dédié aux dépendances | Bonne lisibilité des accès | Bonne si aucune signature de production n’y réside | Plus simple à réinitialiser | Résolution privée et builds fréquents |
| Nœud séparé de signature | Accès privé limité au besoin | Élevée lorsque la clé Apple reste isolée | Meilleure maîtrise du rayon d’impact | Publication contrôlée et branches de confiance |
| Mac distant temporaire | À valider sur un nœud propre | Bonne si l’identité est injectée par tâche | Remplacement plus rapide si la livraison est documentée | Pilote, surcharge ponctuelle ou équipe distribuée |
| Poste local acheté | Dépend des pratiques internes | Variable selon l’administration du parc | Remplacement matériel à organiser | Charge stable et besoin d’accès physique |
SECTION 05 FAQ de validation pour les équipes CI
Pourquoi le poste local réussit-il alors que l’agent CI échoue-t-il ?
Le poste local combine généralement le compte du développeur, son HOME, son agent SSH, ses hôtes connus, sa configuration Git et son cache. L’agent CI peut utiliser une identité totalement différente, même si les deux machines exécutent la même commande. Comparez ces contextes avec le même commit et la même phase de résolution avant d’accuser le réseau ou de modifier les versions.
Quelle place donner à Package.resolved dans un dépôt d’entreprise ?
Traitez-le comme une preuve de sélection approuvée pour le projet de premier niveau. Il doit être versionné, revu et associé au commit construit. Séparez la tâche qui actualise les packages de celle qui publie l’application. Si le pipeline modifie silencieusement le fichier, vous perdez la capacité de relier un artefact à une sélection de versions examinée.
Comment vérifier qu’xcodebuild utilise bien la clé SSH attendue ?
Lancez la vérification avec le même compte macOS et le même environnement que l’agent. Contrôlez HOME, SSH_AUTH_SOCK, known_hosts, les permissions et les règles Host. Testez ensuite l’hôte du dépôt, puis exécutez la résolution minimale. Une session administrateur réussie ne constitue pas une preuve, car elle peut charger d’autres clés ou une autre configuration.
Comment gérer plusieurs projets sur un même Mac de build ?
Définissez des périmètres d’identité et de travail, au lieu de simplement créer plusieurs dossiers. Chaque projet doit recevoir uniquement les autorisations de dépôt nécessaires, avec un nettoyage vérifiable après la tâche. Si une branche non fiable peut lire un cache ou un fichier d’un autre projet, le partage n’est pas suffisamment isolé pour une chaîne de production.
Le cache doit-il être conservé après un incident ?
Conservez d’abord les preuves, puis comparez une résolution propre avec le nœud existant. Si le nœud propre échoue également, le cache n’était pas la cause principale. Si seul le nœud ancien réussit, recherchez une configuration résiduelle plutôt que de considérer le cache comme une réparation. Une purge contrôlée peut faire partie du test, mais pas remplacer le diagnostic d’identité.
SECTION 06 Choisir une capacité Mac sans transférer la dette de sécurité
Après avoir corrigé le compte de service et validé Package.resolved, vous pouvez tester la chaîne sur un Mac distant isolé. Cette approche est pertinente pour une équipe qui doit vérifier une livraison propre, absorber une campagne de build ou séparer temporairement la résolution des dépendances de la signature. Consultez la présentation française de VPSNIX pour examiner le cadre d’accès, puis utilisez la page de tarification des Mac distants uniquement après avoir défini vos exigences d’isolement et de durée.
Une infrastructure achetée en interne offre un contrôle physique et peut être préférable pour une charge permanente, mais elle vous laisse gérer l’amortissement, le remplacement, la capacité de réserve et la remise en état après incident. Un Mac partagé mal séparé ajoute en outre un risque de fuite entre projets. La location d’un Mac distant ne résout pas automatiquement ces problèmes : elle devient intéressante lorsque vous exigez un environnement livré pour un usage précis, une capacité temporaire et une procédure claire de réinitialisation. Si votre nœud actuel ne permet pas de distinguer les comptes, les credentials et les espaces de travail, un essai VPSNIX sur un périmètre isolé constitue alors une comparaison plus honnête qu’une nouvelle purge de cache.