Les tâches de CI doivent souvent monter des fichiers DMG afin de contrôler la structure d’un paquet d’installation, de lire des échantillons de test, de valider le répertoire de livraison après signature ou de comparer le contenu de deux images disque. Une exécution manuelle isolée ne pose généralement aucun problème. Les incidents apparaissent surtout lorsque plusieurs tâches s’exécutent en parallèle, qu’un script s’interrompt anormalement ou qu’un volume monté par une tâche précédente subsiste. Un script qui lit systématiquement /Volumes/Product risque alors d’accéder silencieusement au contenu d’une autre tâche au lieu d’échouer immédiatement.
Pourquoi le montage par défaut devient incontrôlable en cas d’exécution parallèle
hdiutil attach App.dmg choisit le nom du point de montage à partir du nom de volume enregistré dans l’image. Si un volume portant le même nom existe déjà, macOS peut créer un nouveau chemin numéroté. Si le script continue d’utiliser le répertoire fixe d’origine, les résultats des tests ne sont plus fiables.
Un autre problème fréquent consiste à n’exécuter detach qu’en cas de réussite. Dès qu’une commande de validation échoue, que la tâche est interrompue ou qu’une étape ultérieure se termine prématurément, la commande de nettoyage n’est plus exécutée. Les nœuds Mac cloud réutilisés sur de longues périodes accumulent alors progressivement des volumes résiduels, ce qui peut entraîner des conflits de noms, des fichiers encore utilisés ou une détection incorrecte du répertoire de travail.
Un point de montage doit être considéré comme une ressource temporaire propre à la tâche, et non comme un chemin partagé sur la machine. Sa création, son utilisation, son démontage et son diagnostic doivent relever de la même tâche.
Avant toute modification, commencez par relever l’état actuel :
/usr/bin/hdiutil info
/bin/df -h
/bin/ls -la /Volumes
hdiutil info permet de vérifier la correspondance entre les images, les périphériques et les chemins de montage. df indique uniquement l’occupation des systèmes de fichiers et ne remplace pas la vérification des relations avec les images.
Attribuer un point de montage unique à chaque tâche
Le répertoire de montage doit contenir un identifiant de tâche stable et unique. N’utilisez pas uniquement le nom du dépôt, car plusieurs branches ou nouvelles tentatives d’un même dépôt peuvent s’exécuter simultanément. L’identifiant doit également neutraliser les caractères de chemin tels que les barres obliques et les espaces.
Le script suivant vérifie d’abord l’image, puis la monte en lecture seule. Il tente de la démonter aussi bien après une exécution normale qu’en cas d’échec d’une commande ou de réception d’un signal d’arrêt :
#!/bin/bash
set -euo pipefail
IMAGE="${1:?usage: mount-image.sh path/to/file.dmg}"
RAW_JOB_ID="${CI_JOB_ID:-local-$$}"
JOB_ID="${RAW_JOB_ID//[^a-zA-Z0-9._-]/_}"
MOUNT="${TMPDIR%/}/sdkmac-image-${JOB_ID}"
ATTACHED=0
cleanup() {
local status=$?
trap - EXIT INT TERM
if (( ATTACHED == 1 )); then
if ! /usr/bin/hdiutil detach "$MOUNT"; then
printf 'unable to detach %s\n' "$MOUNT" >&2
fi
fi
/bin/rmdir "$MOUNT" 2>/dev/null || true
exit "$status"
}
trap cleanup EXIT INT TERM
/usr/bin/hdiutil verify "$IMAGE"
/bin/mkdir -p "$MOUNT"
/usr/bin/hdiutil attach \
-nobrowse \
-readonly \
-mountpoint "$MOUNT" \
"$IMAGE"
ATTACHED=1
test -r "$MOUNT"
/usr/bin/find "$MOUNT" -maxdepth 2 -type f -print
L’option -nobrowse empêche le volume monté d’entrer dans le flux de navigation habituel de l’interface graphique, tandis que -readonly évite qu’une étape de contrôle ne modifie accidentellement les échantillons. Le script utilise rmdir plutôt que rm -rf : si le démontage échoue, la première commande ne traverse pas le répertoire encore monté pour en supprimer le contenu.
La lecture seule ne convient pas à tous les scénarios
Pour tester des opérations d’écriture, ne rendez pas directement inscriptible l’image de référence partagée. Commencez par copier l’image pour la tâche en cours, vérifiez que cette copie se trouve dans un répertoire temporaire propre à la tâche, puis montez-la. Ainsi, une tâche en échec ne contamine pas les données de référence utilisées lors de l’exécution suivante.
| Objectif | Mode recommandé | Points de contrôle |
|---|---|---|
| Contrôler un paquet d’installation ou des échantillons | Montage en lecture seule | Présence des fichiers, autorisations et empreintes |
| Valider un flux d’écriture | Copie inscriptible propre à la tâche | Résultats des écritures et démontage complet |
| Comparer deux images | Deux points de montage indépendants en lecture seule | Chemins distincts et ordre de comparaison fixe |
Conserver des éléments de diagnostic en cas d’échec du démontage
Un échec de démontage ne signifie généralement pas que hdiutil a rencontré une erreur aléatoire. Il indique plutôt qu’un processus conserve son répertoire courant, un fichier ouvert ou un chemin de travail sur le volume. N’utilisez pas immédiatement un démontage forcé pour masquer la cause : identifiez d’abord le processus responsable.
/usr/sbin/lsof +D "$MOUNT" 2>/dev/null || true
/usr/bin/hdiutil info
/bin/ps -axo pid,ppid,command
lsof +D peut être lent sur les répertoires volumineux et ne doit donc être exécuté que dans la branche d’échec. Vérifiez en priorité les processus de test, les collecteurs de journaux, les outils de compression ainsi que les shells qui ont accédé au répertoire monté avec cd sans en ressortir. La correction consiste généralement à attendre la fin des processus enfants, à fermer les descripteurs de fichiers et à revenir explicitement dans le répertoire de travail de la tâche avant le démontage.
La fonction de nettoyage doit également préserver le code de sortie initial. Si un échec de démontage remplace l’erreur réelle du test, le pipeline n’affichera que l’anomalie de nettoyage et la cause première sera perdue. Il est plus robuste d’enregistrer séparément l’état des tests et celui du nettoyage, puis de les inscrire tous les deux dans le récapitulatif de la tâche.
Auditer les volumes résiduels sans les supprimer aveuglément
Avant de commencer une nouvelle tâche sur un nœud, il est possible de rechercher les répertoires de montage nommés par ce pipeline. Il ne faut toutefois jamais supprimer directement un répertoire au seul motif que son nom ressemble au modèle attendu. Vérifiez d’abord qu’il s’agit réellement d’un point de montage, puis qu’aucune tâche correspondante n’est encore active et que l’image appartient bien à l’espace de travail concerné.
Il est recommandé de répartir les résultats de l’audit en trois catégories :
- Volumes appartenant à la tâche en cours : ils sont démontés normalement par le piège de sortie.
- Volumes appartenant à d’autres tâches actives : ils sont consignés puis ignorés ; tout nettoyage entre tâches est interdit.
- Volumes résiduels potentiels sans tâche active identifiable : collectez
hdiutil info, les processus qui les utilisent et le contexte de création, puis démontez-les uniquement après confirmation.
Le démontage forcé ne doit intervenir qu’en dernier recours, après une validation humaine. Un script automatique qui se fie uniquement à l’âge d’un répertoire risque d’interrompre une tâche longue mais parfaitement opérationnelle. L’horodatage du répertoire ne correspond pas non plus à l’heure du montage : la copie de fichiers ou la lecture de métadonnées peuvent modifier les éléments utilisés pour prendre la décision.
Intégrer le traitement des images aux critères de validation du pipeline
Une procédure réutilisable de traitement des images disque doit au minimum vérifier les points suivants :
- Le fichier d’entrée existe et
hdiutil verifyest exécuté avant le montage. - Chaque tâche utilise un répertoire indépendant, sans générer son chemin à partir du nom de volume de l’image.
- Le montage se fait en lecture seule par défaut ; lorsqu’une écriture est nécessaire, une copie propre à la tâche est créée.
- Un piège de nettoyage couvre tous les chemins de sortie et les processus enfants peuvent eux aussi recevoir le signal d’arrêt.
- Le script quitte le répertoire monté avant le démontage et attend la fin des processus qui lisent le volume.
- En cas d’échec du démontage, les informations sur le périphérique, le chemin et les processus sont conservées, sans suppression récursive.
- À la fin de la tâche, le point de montage a disparu et aucun volume appartenant à une autre tâche parallèle n’a été nettoyé par erreur.
Sur les nœuds Mac physiques dédiés de SDKMac, cette méthode s’applique aussi bien aux diagnostics interactifs qu’aux pipelines sans surveillance. L’essentiel n’est pas d’ajouter davantage de commandes de nettoyage, mais d’attribuer à chaque volume monté un propriétaire, un cycle de vie et des éléments de diagnostic clairement définis. Une fois ces règles appliquées, le contrôle des DMG ne produit plus de résultats difficiles à reproduire en raison de la réutilisation des machines ou des exécutions parallèles.
Questions fréquentes
Pourquoi éviter le nom de volume par défaut sous /Volumes en CI ?
Des tâches parallèles peuvent monter des images portant le même nom. macOS ajoute alors un numéro, et un chemin codé en dur peut lire silencieusement le volume d'une autre tâche.
Peut-on supprimer le dossier si hdiutil detach échoue ?
Non. Il faut identifier le processus qui retient le volume puis retenter un démontage normal. Une suppression récursive peut effacer les données d'une image encore montée.
Faut-il monter les images disque en lecture seule par défaut ?
Oui pour inspecter des paquets, des jeux de test ou des artefacts immuables. Une copie inscriptible distincte ne doit être créée que si le test doit modifier son contenu.
Choisissez un Mac cloud pour vos builds continus
Comparez les configurations, les régions et les quatre cycles de facturation de SDKMac M4 et SDKMac M4 Pro, puis créez votre commande.