Aller au contenu principal
Nicolas Cousin Tech SolutionsNicolas Cousin Tech Solutions
Module 4 sur 6

Audit supply-chain : référence épinglée vs mutable

Le scénario

Vous avez maintenant deux surfaces construites dans ce parcours : le graphe de services du module 01 (une image de base, potentiellement des Features Dev Container) et le workflow CI du module 03, qui référence des dépôts de hooks pre-commit par leur rev. Votre lead sécurité vous demande un audit rapide : quelles références, dans ces deux surfaces, sont réellement épinglées à un point immuable dans le temps, et lesquelles peuvent changer de contenu sous le même nom sans que personne ne le remarque ?

Avant de continuer, une précision importante sur la portée de ce module : la seule source qui documente officiellement, avec précision, la sémantique d'immuabilité attendue est pre-commit.com lui-même, à propos du champ rev. Pour les autres références (tags d'image Docker, versions de GitHub Actions), le principe est analogue mais n'est pas garanti par la même documentation — traitez cette partie comme une extension raisonnée du même raisonnement, pas comme un fait documenté à la même autorité.

Consigne : produisez votre audit avant de lire la suite

Ouvrez vos fichiers des modules 01 et 03 et, pour chaque référence externe qu'ils contiennent, notez si elle pointe vers quelque chose d'immuable ou de mutable. Faites-le vous-même avant de lire le tableau plus bas.

Les extraits ci-dessous sont un exemple simplifié, pas nécessairement le contenu exact de vos fichiers (votre .pre-commit-config.yaml réel peut avoir des rev différents ou un dépôt de hooks en plus) — l'important est d'appliquer le même audit à votre fichier réel, pas de retrouver ces valeurs précises.

Dans votre .pre-commit-config.yaml (module 03) :

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
  - repo: https://github.com/psf/black
    rev: 24.4.2

Dans votre docker-compose.yml / Dockerfile (module 01) :

services:
  db:
    image: postgres:16

Pour chacune, posez-vous la même question : ce nom peut-il, en théorie, pointer vers un contenu différent demain sans que la référence elle-même change ?

Écrivez votre diagnostic avant de continuer — pour chaque référence, "immuable" ou "mutable", et pourquoi.

Ce que documente réellement pre-commit.com

Voici la seule source officielle et précise sur ce sujet (pre-commit.com), à ne pas paraphraser de mémoire :

« pre-commit assumes that the value of rev is an immutable ref (such as a tag or SHA) and will cache based on that. »

Et, plus loin, la mise en garde explicite :

« Using a branch name (or HEAD) for the value of rev is not supported and will only represent the state of that mutable ref at the time of hook installation (and will NOT update automatically). »

Ce que ça veut dire concrètement : rev: v4.6.0 est traité par pre-commit comme un point figé — pre-commit met en cache l'environnement du hook sur la base de cette valeur exacte. Mais un tag Git n'est pas cryptographiquement immuable : rien n'empêche, techniquement, un mainteneur de dépôt de déplacer un tag existant pour pointer vers un autre commit (git tag -f). C'est rare sur des dépôts bien maintenus comme pre-commit-hooks ou black, mais ce n'est pas impossible — et c'est exactement le trou que rev en tag, contrairement à rev en SHA, laisse ouvert. Un SHA de commit, lui, est un hash du contenu : il ne peut pas être "redéplacé" sans changer de valeur.

Le pire cas, documenté explicitement, c'est rev: main ou rev: HEAD : ça n'est pas "toujours la dernière version" comme on pourrait le croire — c'est un instantané figé au moment de l'installation du hook, qui ne se met jamais à jour tout seul. C'est le pire des deux mondes : ni la fraîcheur qu'on croit obtenir, ni la garantie d'immuabilité qu'un SHA offrirait.

La solution documentée : autoupdate --freeze

pre-commit autoupdate --freeze

L'exemple officiel :

Updating https://github.com/pre-commit/pre-commit-hooks ... updating v2.1.0 -> v2.4.0 (frozen).

Résultat dans le fichier : le rev devient le SHA du commit correspondant à v2.4.0, avec un commentaire qui préserve la lisibilité humaine :

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: a1b2c3d4e5f6...  # frozen: v2.4.0

Vous obtenez l'immuabilité garantie d'un SHA, sans perdre la capacité de savoir, d'un coup d'œil, à quelle version ça correspond.

Votre diff avant/après

Produisez maintenant, pour de vrai, le diff de votre .pre-commit-config.yaml :

pre-commit autoupdate --freeze
git diff .pre-commit-config.yaml

Le résultat attendu ressemble à :

   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.6.0
+    rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c  # frozen: v4.6.0
     hooks:
       - id: trailing-whitespace

Extension raisonnée : les autres références

Pour les images Docker du module 01 (postgres:16) et les actions GitHub du module 03 (actions/checkout@v4), le même principe de fond s'applique — un tag mutable peut, en théorie, se retrouver derrière un contenu différent — mais ce n'est pas pre-commit.com qui documente ce risque pour ces surfaces-là, c'est le même raisonnement appliqué par analogie. Notez-le clairement dans votre audit :

  • postgres:16 est un tag mineur : il pointe vers la dernière image 16.x publiée, et change de contenu à chaque publication de correctif — c'est un comportement voulu, pas un bug, mais ça reste un tag mutable. Un pin plus strict serait postgres:16.4 (toujours mutable en théorie, mais change moins souvent) ou un digest postgres@sha256:... (immuable, garanti par le registre).
  • actions/checkout@v4 est un tag mutable au même titre qu'un tag pre-commit non figé — GitHub permet aux mainteneurs de dépôts d'actions de redéplacer des tags majeurs. Un pin plus strict serait actions/checkout@<sha complet>.

Checklist d'auto-évaluation

Comparez votre audit à ces points :

  • Avez-vous distingué, pour chaque référence, "immuable garanti" (SHA/digest) de "mutable par convention mais rarement modifié en pratique" (tag versionné) de "mutable et non figé du tout" (main, latest, HEAD) ?
  • Avez-vous cité la phrase exacte de pre-commit.com pour justifier le risque sur rev, plutôt qu'une reformulation approximative ?
  • Votre diff avant/après montre-t-il un SHA réel, obtenu par une vraie exécution de pre-commit autoupdate --freeze, pas un exemple inventé ?
  • Avez-vous explicitement marqué la partie "images Docker / GitHub Actions" comme une extension par analogie, et non comme une garantie documentée par la même source que rev ?
  • Votre explication du risque nomme-t-elle un scénario concret (un mainteneur compromis qui redéploie un tag existant avec du code malveillant, par exemple) plutôt qu'une généralité du type "c'est plus sécurisé" ?

Ce qui vous attend au module suivant

Le module suivant change de nature : votre setup fonctionne, est miroité en CI, et est audité côté supply-chain — reste la question de la performance brute du conteneur lui-même.

Vérifiez votre compréhension

D'après la documentation officielle de pre-commit, que suppose pre-commit à propos de la valeur du champ rev dans .pre-commit-config.yaml ?

Que se passe-t-il, d'après la doc officielle, si vous mettez un nom de branche (ou HEAD) comme valeur de rev ?

Que fait concrètement pre-commit autoupdate --freeze ?

Envie d'être prévenu des prochains modules ?

L'Académie reste gratuite et en accès libre, sans inscription. Si vous voulez juste être averti par email à la sortie d'un nouveau module, c'est ici — aucune obligation, désinscription en un clic.