Automation
Azure DevOps : prouver la provenance d'un artifact avant la promotion en production
Un runbook de production pour relier un artifact Azure DevOps à sa source, son run de build, son empreinte et son approbation avant promotion, quarantaine ou rollback.
Le déploiement en staging est valide, mais le job de production ne sait pas prouver quel package il va promouvoir. Le pipeline pointe vers un build réussi, le nom du fichier semble correct et le commit a été approuvé. Pourtant, le package peut avoir été reconstruit depuis le même commit, téléchargé depuis un autre run, reconditionné par un stage de déploiement ou mélangé à des fichiers restés sur un agent auto-hébergé.
Le cas fil rouge est un pipeline Azure DevOps qui construit une API web une seule fois, publie un Pipeline Artifact nommé, le déploie en staging puis promeut exactement les mêmes octets en production après approbation. Ce runbook établit une chaîne vérifiable de la source au runtime. La décision finale est explicite : promouvoir l’artifact, le placer en quarantaine et reconstruire, ou revenir au dernier artifact dont la provenance est complète.
Geler la promotion et nommer le candidat
Arrêtez le stage de production avant qu’un autre run ne modifie les preuves. Relevez le pipeline exact, l’ID du run, le commit source, le nom de l’artifact, l’environnement cible et le job de déploiement en attente. Un numéro de build ou un nom de fichier ne suffit pas : ils peuvent être recopiés dans un autre contexte.
candidate:
pipeline_id: <pipeline-id>
build_run_id: <run-id>
source_repository: <repository>
source_commit: <full-sha>
artifact_name: api-drop
artifact_sha256: <sha256>
build_definition_revision: <revision-or-commit>
promotion:
target: production
deployment_job: <job-name>
approval_reference: <approval-or-change-id>
staging_validation: <evidence-link>
decision_owner: <role>
rollback_artifact_sha256: <last-known-good-sha256> Conservez le run d’origine et ses logs tant que la décision reste ouverte. La suppression d’un run Azure DevOps supprime aussi les Pipeline Artifacts associés : nettoyer n’est pas contenir lorsque ce run porte une partie des preuves.
Prouver séparément la source et le contrat de build
Le commit source indique quel code a été extrait. Il ne prouve pas ce que le build a produit. Les dépendances, fichiers générés, images de base, versions d’outils et templates de pipeline peuvent modifier le résultat sans changement du commit applicatif.
Comparez le run candidat au contrat approuvé :
- SHA complet et dépôt source, pas seulement le nom de branche ;
- révision du YAML ou de la définition utilisée par le run ;
- paramètres et Variable Groups qui influencent compilation ou packaging ;
- image de l’agent ou pool auto-hébergé et versions de la chaîne de build ;
- dépendances résolues, lockfiles et digest d’image de base selon le cas ;
- tests et contrôles de sécurité rattachés à ce même run.
Lorsqu’une entrée est inconnue, marquez-la comme telle. Ne remplacez pas une provenance manquante par « le run a réussi ». Le succès prouve la fin des tâches, pas l’identité de l’artifact.
Télécharger depuis le run exact et calculer l’empreinte
Adressez l’artifact par ID de run et par nom. Téléchargez-le dans un répertoire d’investigation propre, puis calculez une empreinte déterministe du fichier déployable. Pour un répertoire, produisez une archive déterministe pendant le build ou publiez un manifeste contenant l’empreinte de chaque fichier.
set -euo pipefail
rm -rf ./candidate-artifact
mkdir -p ./candidate-artifact
az pipelines runs artifact download \
--run-id <run-id> \
--artifact-name api-drop \
--path ./candidate-artifact \
--organization https://dev.azure.com/<organization> \
--project <project>
find ./candidate-artifact -type f -print0 \
| sort -z \
| xargs -0 sha256sum \
> artifact-files.sha256
sha256sum artifact-files.sha256 Conservez le manifeste obtenu comme preuve de promotion, pas comme variable de pipeline modifiable. Recalculez la même empreinte après le téléchargement en staging puis juste avant le déploiement en production. Toute différence bloque la promotion, même si les deux packages annoncent la même version sémantique.
Inspecter le contenu sans l’exécuter
Une provenance cohérente peut désigner un package dangereux. Inspectez l’archive ou le répertoire sans charger de binaire ni lancer de hook d’installation. Comparez sa structure avec l’artifact précédemment approuvé et avec la sortie de build attendue.
Recherchez notamment :
- exécutables, scripts ou manifestes de déploiement inattendus ;
- configurations contenant endpoints propres à un environnement ou secrets ;
- lockfile, SBOM, signature ou inventaire de dépendances manquant alors que le pipeline les produit habituellement ;
- symboles de debug, fixtures de test ou sources qui ne devraient pas être livrés ;
- variation inexpliquée de taille, nombre de fichiers ou dépendances.
Une SBOM enrichit la preuve, mais ne remplace ni l’empreinte ni le lien vers le run producteur. Une signature n’est utile que si le vérificateur contrôle aussi le signataire attendu, la politique de confiance et le digest signé.
Séparer les autorités de build et de promotion
Le stage de déploiement doit consommer un artifact précis. Il ne doit pas extraire le code puis reconstruire « par commodité ». Une reconstruction après approbation produit de nouveaux octets hors du build relu, même si le SHA source reste identique.
Séparez aussi les permissions. L’identité de build publie l’artifact ; l’identité de déploiement lit l’artifact approuvé et écrit vers l’environnement cible. Aucune n’a besoin de modifier les approbations. Restreignez l’upload manuel d’artifacts et la sélection des runs afin qu’un opérateur ne puisse pas remplacer silencieusement le candidat.
Sur les agents auto-hébergés, utilisez une destination propre et supprimez-la après le job. Un workspace réutilisé ne doit jamais devenir une source implicite. Le log de déploiement doit consigner l’ID du run, le nom de l’artifact et son empreinte avant toute écriture en production.
Valider les mêmes octets en staging puis sur un canari
Déployez le candidat vérifié en staging sans le reconditionner. Relevez un endpoint de version, digest d’image, numéro d’assembly ou autre marqueur runtime relié au manifeste. Des tests fonctionnels ne suffisent pas s’ils n’identifient pas les octets testés.
La promotion commence par un canari de production borné : une instance, un slot, un ring ou un tenant peu risqué. Pendant la fenêtre d’observation, validez comportement et identité :
Contrôles d'identité
La production télécharge l'ID de run et le nom d'artifact consignés
L'empreinte avant déploiement égale l'empreinte approuvée
Le marqueur runtime correspond au même artifact
Contrôles opérationnels
Santé, latence et taux d'erreur du canari restent dans l'enveloppe convenue
Les migrations requises sont rétrocompatibles ou contrôlées séparément
Aucune erreur inattendue de dépendance ou d'autorisation n'apparaît
Décision
PROMOTE: provenance et canari sont valides
HOLD: la preuve est incomplète mais aucune écriture production n'a eu lieu
QUARANTINE_AND_REBUILD: l'empreinte ou le contenu diffère
ROLL_BACK: la santé production régresse après l'écriture canari N’écrasez pas le candidat lorsqu’un contrôle échoue. Conservez-le sous accès restreint pour expliquer l’écart, puis démarrez un nouveau build avec un nouvel ID de run.
Rollbacker vers des octets déjà connus
Le rollback doit référencer le dernier ID de run, nom d’artifact et digest connus comme sains. Reconstruire un ancien commit n’est pas le même rollback : registres, dépendances et images de build peuvent avoir évolué depuis la livraison d’origine.
Avant promotion, confirmez que l’artifact précédent reste conservé et déployable, que ses dépendances runtime sont disponibles et que les changements de base de données ou de configuration restent rétrocompatibles. Si le retour exige une migration compensatoire, traitez-la comme une action approuvée distincte avec sa propre validation.
Après rollback, vérifiez le marqueur runtime et la santé du service. Gardez le candidat en échec en quarantaine jusqu’à distinguer erreur de sélection du pipeline, dérive de l’environnement de build, contamination du workspace ou modification non autorisée.
Conclusion
Un commit approuvé est nécessaire, mais insuffisant pour une promotion en production. L’unité opérationnelle est l’artifact exact produit par un run identifié, avec des entrées de build connues, une empreinte stable et un chemin de déploiement qui ne le reconstruit ni ne le reconditionne.
La décision devient mécanique : promouvoir seulement lorsque source, run, digest, approbation et canari désignent les mêmes octets. Mettre en quarantaine et reconstruire lorsque l’identité reste ambiguë. Si le canari régresse, revenir à l’artifact conservé déjà prouvé en production, pas à une reconstruction fraîche d’un ancien code source.