Un projet iOS peut compiler correctement sur la branche de développement, tout en intégrant discrètement dans son Archive un Framework dynamique supplémentaire, un lien absolu vers un répertoire de la machine de développement ou des symboles globaux qui devaient rester internes. L’examen des fichiers du projet suffit rarement à détecter ces changements, car le livrable réel est le Mach-O obtenu après l’édition de liens. Une approche plus fiable consiste à faire inspecter directement l’archive par le Mac CI dans le cloud, puis à transformer les variations de dépendances et de symboles en différences soumises à révision.
Définir d’abord les changements à bloquer
Ce type de contrôle ne doit pas déterminer si une bibliothèque est « bonne » ou « mauvaise », mais répondre à trois questions vérifiables :
- De quoi dépendent réellement l’application principale et les Frameworks intégrés ?
- Les bibliothèques embarquées référencées via
@rpathsont-elles bien présentes dans le bundle de l’App ? - Les nouveaux symboles globaux font-ils partie de l’interface prévue ?
La référence n’est pas une liste blanche définitive, mais un instantané du livrable validé manuellement. Elle peut être mise à jour après une évolution de la chaîne d’outils, des dépendances ou des interfaces, mais cette mise à jour doit être examinée avec les modifications du code.
Il est recommandé d’exécuter ces contrôles après la création d’une Archive en configuration Release. Une compilation Debug peut inclure des bibliothèques de diagnostic et produire des résultats d’optimisation différents ; elle ne représente donc pas la frontière réelle du livrable final. Lors du déploiement initial, générez uniquement un rapport sans bloquer la CI. Une fois le contenu de référence validé par l’équipe, faites échouer la tâche en cas de différence.
Extraire les éléments à contrôler depuis l’Archive
Commencez par générer une archive indépendante afin de ne pas réutiliser d’anciens artefacts présents sur la machine du développeur :
rm -rf out/App.xcarchive
xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "$PWD/out/App.xcarchive" \
clean archive
Si la signature est effectuée par une tâche distincte en aval, vous pouvez définir CODE_SIGNING_ALLOWED=NO selon les besoins du projet. N’ajoutez pas systématiquement cette option à tous les projets : pour ceux qui utilisent certaines capacités ou des phases de build personnalisées, vérifiez d’abord que l’archive non signée est complète.
Dans l’archive, l’application principale se trouve généralement sous Products/Applications. Le périmètre de contrôle doit au minimum inclure l’exécutable principal de l’App et l’exécutable de chaque Framework présent dans le répertoire Frameworks. Les cibles d’extension doivent également être traitées séparément, car elles possèdent leurs propres frontières de dépendances.
| Objet | Contrôles principaux | Anomalies courantes |
|---|---|---|
| Programme principal de l’App | Bibliothèques système, Frameworks embarqués, symboles globaux | Chemins absolus hors système |
| Framework dynamique | Dépendances de second niveau, nom d’installation, symboles publics | Dépendance absente du livrable |
| App Extension | Référence indépendante pour les dépendances et les symboles | Réutilisation incorrecte des hypothèses de l’application principale |
Générer l’inventaire des dépendances et des symboles
Le script ci-dessous analyse le programme principal et les Frameworks intégrés, puis génère des listes triées de manière stable pour les dépendances et les symboles globaux. Le tri évite que des variations dans l’ordre de sortie des outils ne produisent des différences sans intérêt.
set -euo pipefail
archive="${1:?archive path required}"
app=$(find "$archive/Products/Applications" -maxdepth 1 -name '*.app' -print -quit)
test -n "$app"
mkdir -p audit/current
main=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$app/Info.plist")
printf '%s
' "$app/$main" > audit/current/binaries.txt
if test -d "$app/Frameworks"; then
while IFS= read -r framework; do
executable=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$framework/Info.plist")
printf '%s
' "$framework/$executable"
done < <(find "$app/Frameworks" -maxdepth 1 -name '*.framework' -type d | sort)
fi >> audit/current/binaries.txt
: > audit/current/dependencies.txt
: > audit/current/symbols.txt
while IFS= read -r binary; do
name=${binary#"$app/"}
otool -L "$binary" |
sed '1d' |
awk -v n="$name" '{$1=$1; print n " " $1}' \
>> audit/current/dependencies.txt
xcrun nm -gU "$binary" |
awk -v n="$name" 'NF {print n " " $NF}' \
>> audit/current/symbols.txt
done < audit/current/binaries.txt
LC_ALL=C sort -u -o audit/current/dependencies.txt audit/current/dependencies.txt
LC_ALL=C sort -u -o audit/current/symbols.txt audit/current/symbols.txt
Lors de l’enregistrement de la référence, ne conservez que les noms d’objets relatifs et n’incluez pas le répertoire de travail du Mac dans le cloud. Le pipeline exécute ensuite :
diff -u audit/baseline/dependencies.txt audit/current/dependencies.txt
diff -u audit/baseline/symbols.txt audit/current/symbols.txt
Transformer le rapport en contrôle fiable
Une comparaison intégrale des fichiers peut être trop sensible. Une stratégie plus pratique consiste à appliquer d’abord des règles strictes, puis à vérifier les écarts par rapport à la référence. Les dépendances commençant par /System/Library/Frameworks/, /usr/lib/ ou un chemin @rpath/ contrôlé sont généralement légitimes ; tout autre chemin absolu doit provoquer un échec immédiat. Pour @rpath/Example.framework/Example, le script doit également confirmer que le Framework correspondant existe dans le bundle. Un préfixe valide ne suffit pas pour autoriser la dépendance.
Les variations de symboles se prêtent davantage à une révision manuelle. Les noms Swift peuvent devenir très longs après leur transformation ; leur longueur ne permet donc pas d’évaluer le risque. Recherchez surtout l’apparition soudaine d’un grand nombre de symboles globaux, d’interfaces d’assistance au débogage, de points d’entrée de test, ainsi que de symboles C ou Objective-C qui devraient être masqués mais restent visibles entre les modules.
Réduire les faux positifs
Figez la version de Xcode et la configuration Release, et assurez-vous de toujours comparer le même scheme. Si le projet contient plusieurs extensions, conservez une référence distincte pour chaque binaire au lieu de regrouper tous les résultats dans un seul ensemble. Lorsqu’une mise à niveau de la chaîne d’outils modifie les symboles système, mettez à jour la référence dans la demande de fusion consacrée à cette mise à niveau afin que l’origine des écarts reste explicable.
Remonter à la source d’un échec depuis le livrable
Lorsqu’une nouvelle dépendance apparaît, utilisez d’abord otool -L pour identifier le binaire qui l’introduit, puis examinez les réglages d’édition de liens de la cible, la compilation conditionnelle et la phase d’intégration des dépendances. Si une cible @rpath est absente, vérifiez en priorité si le Framework participe uniquement à l’édition de liens sans être copié dans le bundle. En cas de symbole inattendu, utilisez nm -gU pour localiser l’objet concerné, puis contrôlez les déclarations de visibilité, le code de pontage et la configuration des exports de l’éditeur de liens.
Ne remplacez pas directement la référence après un échec. L’ordre correct consiste à identifier l’origine du changement, à déterminer s’il affecte la frontière du livrable, à corriger ou approuver la modification, puis seulement à régénérer la référence. Ce contrôle ne dépend ainsi pas de l’état temporaire d’un Mac particulier dans le cloud et conserve, pour chaque version, un relevé vérifiable des frontières binaires.
Questions fréquentes
Pourquoi ne pas vérifier uniquement les dépendances déclarées par le projet ?
Les variantes de compilation, options de l’éditeur de liens et scripts peuvent modifier l’archive finale. Il faut donc inspecter directement ses fichiers Mach-O.
Tout changement de symbole exporté doit-il bloquer une livraison ?
Pas définitivement. La CI doit imposer une revue, puis la référence peut être mise à jour après confirmation d’une évolution voulue de l’API ou des outils.
L’inventaire des symboles permet-il de détecter les secrets intégrés ?
Non, pas seul. La recherche de secrets doit aussi couvrir le code source, les configurations, les ressources et les journaux de compilation.
Nœud physique dédié
Déployez vos tâches de développement et de build sur un Mac dédié dans le cloud
Choisissez le modèle, la région du nœud et la durée de location selon vos besoins. Chaque instance correspond à une machine physique dédiée, dans un environnement non virtualisé.