Lorsqu’une équipe déploie des outils en ligne de commande, des agents en arrière-plan ou des applications internes sur plusieurs Mac, la simple copie de fichiers révèle rapidement trois problèmes : des chemins de destination incohérents, des fichiers obsolètes laissés après les mises à niveau et des installations impossibles à auditer. Un paquet macOS PKG permet de regrouper le payload, les droits, les scripts d’installation et les reçus de version dans un artefact traçable, à condition de ne pas transmettre directement l’espace de travail de développement à pkgbuild. L’exemple suivant utilise un composant en ligne de commande installé dans /Library/Application Support/AcmeTool pour mettre en place un processus de construction et de validation adapté à une CI Mac dans le cloud.
Définir d’abord le contrat d’installation
Avant de créer le paquet, définissez précisément le chemin de destination, le propriétaire, les droits, l’identifiant du paquet et les règles de mise à niveau. Une fois publié, l’identifiant du paquet doit rester stable, tandis que la version doit augmenter de façon monotone. Dans le cas contraire, les reçus système ne permettent pas de déterminer correctement les relations de remplacement.
| Élément | Exemple | Critère de validation |
|---|---|---|
| Répertoire racine d’installation | /Library/Application Support/AcmeTool |
Ne rien écrire dans le répertoire personnel de l’utilisateur |
| Fichier exécutable | bin/acmetool |
root:wheel, droits 0755 |
| Modèle de configuration | config/default.json |
Droits 0644, sans secret |
| Identifiant du paquet | com.example.acmetool.pkg |
Ne varie pas selon la branche |
| Version | 1.4.0 |
Correspond au tag de publication |
Le répertoire du projet sur la machine de construction ne fait pas partie du contrat d’installation. .git, les rapports de test, les caches de téléchargement, les journaux temporaires et les attributs étendus générés localement ne doivent pas être inclus dans le PKG.
La source de création de paquet la plus fiable n’est pas le « dépôt actuel », mais un répertoire de staging recréé à chaque fois et dont le contenu peut être entièrement énuméré.
Créer un payload propre
Au début de chaque tâche, supprimez l’ancienne zone de staging, copiez explicitement les fichiers autorisés à être livrés, puis uniformisez leurs droits. N’utilisez pas une commande générale comme cp -R ., car de nouveaux fichiers pourraient alors intégrer le paquet d’installation sans que personne ne s’en aperçoive.
set -euo pipefail
ROOT="$PWD"
STAGE="$ROOT/build/stage"
PKGDIR="$ROOT/build/packages"
INSTALL_DIR="$STAGE/Library/Application Support/AcmeTool"
rm -rf "$STAGE" "$PKGDIR"
mkdir -p "$INSTALL_DIR/bin" "$INSTALL_DIR/config" "$PKGDIR"
install -m 0755 "$ROOT/dist/acmetool" "$INSTALL_DIR/bin/acmetool"
install -m 0644 "$ROOT/packaging/default.json" \
"$INSTALL_DIR/config/default.json"
xattr -cr "$STAGE"
find "$STAGE" -type d -exec chmod 0755 {} +
find "$STAGE" -type f ! -path '*/bin/acmetool' -exec chmod 0644 {} +
Générez ensuite un manifeste. Il facilitera la revue de code et permettra de comparer les entrées réellement utilisées à la fin de la construction :
find "$STAGE" -print0 |
sort -z |
xargs -0 stat -f '%Sp %Su:%Sg %N' > "$PKGDIR/payload-manifest.txt"
grep -Eq '/(\.git|DerivedData|node_modules)(/|$)' \
"$PKGDIR/payload-manifest.txt" && exit 1 || true
Les attributs étendus sont supprimés avant l’application des droits afin d’éviter que les marqueurs d’origine des téléchargements ou les ACL de la machine de développement ne soient intégrés à l’artefact. Le modèle de configuration ne doit contenir que des valeurs par défaut ; les jetons d’exécution doivent être injectés lors du déploiement.
Générer le paquet de composant avec pkgbuild
Placez les scripts d’installation dans un répertoire séparé et assurez-vous qu’ils sont exécutables. Ces scripts doivent être idempotents, rapides et non interactifs. Ils ne doivent ni lire les entrées du terminal ni supposer qu’un utilisateur particulier est connecté.
mkdir -p packaging/scripts
cat > packaging/scripts/postinstall <<'SH'
#!/bin/sh
set -eu
TARGET="/Library/Application Support/AcmeTool"
test -x "$TARGET/bin/acmetool"
chown -R root:wheel "$TARGET"
chmod 0755 "$TARGET" "$TARGET/bin" "$TARGET/bin/acmetool"
chmod 0644 "$TARGET/config/default.json"
exit 0
SH
chmod 0755 packaging/scripts/postinstall
pkgbuild \
--root "$STAGE" \
--identifier "com.example.acmetool.pkg" \
--version "1.4.0" \
--install-location "/" \
--scripts packaging/scripts \
"$PKGDIR/AcmeTool-component.pkg"
Lorsqu’il n’y a qu’un seul composant, le paquet de composant peut déjà être installé. Si vous devez ajouter une page d’accueil commune, un texte de licence ou plusieurs composants, utilisez ensuite productbuild pour générer un paquet de distribution :
productbuild \
--package "$PKGDIR/AcmeTool-component.pkg" \
"$PKGDIR/AcmeTool-1.4.0.pkg"
Si une signature est nécessaire, récupérez l’identité de signature Installer depuis un environnement de CI protégé, puis construisez le paquet de production avec --sign "$INSTALLER_IDENTITY". Les artefacts non signés peuvent toujours servir aux tests préliminaires, mais ils ne doivent pas être présentés comme des livrables finaux.
Effectuer une validation statique avant toute installation
Le premier niveau de contrôle ne modifie pas le système. Vérifiez d’abord l’identifiant du paquet, sa version et son payload, puis développez le paquet de distribution afin d’examiner les scripts et les métadonnées :
PKG="$PKGDIR/AcmeTool-1.4.0.pkg"
EXPANDED="$PKGDIR/expanded"
pkgutil --check-signature "$PKG" || true
pkgutil --payload-files "$PKGDIR/AcmeTool-component.pkg"
rm -rf "$EXPANDED"
pkgutil --expand-full "$PKG" "$EXPANDED"
grep -R "com.example.acmetool.pkg" "$EXPANDED"
grep -R "1.4.0" "$EXPANDED"
find "$EXPANDED" -type f -name postinstall -exec sh -n {} \;
Si le paquet de production doit être signé, n’ajoutez aucune tolérance d’erreur à pkgutil --check-signature : un code de sortie non nul doit interrompre immédiatement le pipeline. Il faut également rejeter les chemins de construction absolus, les fragments de clés privées et les noms d’utilisateur provenant de l’espace de travail :
if grep -R -E "$HOME|BEGIN (RSA |EC )?PRIVATE KEY" "$EXPANDED"; then
echo "sensitive build data found" >&2
exit 1
fi
Une erreur fréquente consiste à comparer uniquement la taille des fichiers de paquet. Une taille stable ne garantit pas un contenu stable : le manifeste, l’identifiant, la version, la syntaxe des scripts et l’état de la signature doivent être contrôlés séparément.
Tester l’installation en environnement isolé et vérifier le reçu
La validation finale doit être effectuée dans un environnement de test pouvant être restauré, car installer écrit dans les chemins système et enregistre des reçus d’installation. Le nœud de test doit être réinitialisé dans un état connu avant chaque tâche et ne doit pas être partagé avec les sessions de développement quotidiennes.
sudo installer -pkg "$PKG" -target /
test -x "/Library/Application Support/AcmeTool/bin/acmetool"
test "$(stat -f '%Sp' \
'/Library/Application Support/AcmeTool/bin/acmetool')" = "-rwxr-xr-x"
pkgutil --pkg-info "com.example.acmetool.pkg"
pkgutil --files "com.example.acmetool.pkg" |
sort > "$PKGDIR/installed-files.txt"
"/Library/Application Support/AcmeTool/bin/acmetool" --version
Une installation réussie indique seulement que le script a renvoyé zéro. Il faut aussi vérifier que l’exécutable démarre, que le modèle de configuration peut être analysé, que la version du reçu est correcte, puis conserver le journal d’installation et la liste des fichiers parmi les artefacts de CI. En cas d’échec, sauvegardez d’abord la période correspondante de /var/log/install.log, puis restaurez l’environnement de test au lieu de relancer immédiatement la tâche et d’écraser les éléments utiles au diagnostic.
La vérification finale peut être standardisée autour de cinq points : aucun fichier supplémentaire dans le répertoire de staging, droits et propriétaires conformes au contrat, version du paquet augmentant de façon monotone, signature valide pour l’artefact de production, et commande comme reçu vérifiables après une installation isolée. Le PKG cesse ainsi d’être une simple « archive sur laquelle on peut double-cliquer » pour devenir un livrable technique auditable, reproductible et adapté aux tests de non-régression.
Questions fréquentes
Faut-il donner directement le dépôt comme racine à pkgbuild ?
Non. Créez une zone de staging qui ne contient que les fichiers destinés à la machine cible afin d’exclure les sources, caches, journaux et attributs locaux.
Peut-on tester le pipeline sans certificat de signature Installer ?
Oui. Validez d’abord un paquet non signé sur sa structure, ses droits, ses scripts et son installation isolée, puis signez la version distribuée et contrôlez-la avec pkgutil --check-signature.
Configurez un Mac cloud pour votre prochain build ou votre prochaine tâche d’inférence
Choisissez parmi trois configurations Apple Silicon, six nœuds et des durées de location fixes. La disponibilité réelle est indiquée en temps réel dans la console.