← retour aux snippets

checksum de répertoire reproductible (sha256)

Obtenir un hash stable d'un dossier (build, site) pour vérifier l'intégrité des releases.


objectif

Calculer un SHA-256 stable d’un répertoire afin de comparer des releases entre machines/CI.

code minimal

# dépôt git: hash stable des fichiers suivis (portable)
git ls-files -z \
  | xargs -0 shasum -a 256 \
  | shasum -a 256 \
  | awk '{print $1}'

utilisation

# 1) générer la somme d'un build statique (data.pm) et la publier
(
  cd ./build/data.pm
  git init -q >/dev/null 2>&1 || true
  git add -f . >/dev/null 2>&1 || true
  SUM="$(git ls-files -z | xargs -0 shasum -a 256 | shasum -a 256 | awk '{print $1}')"
  echo "$SUM" > ../CHECKSUM.SHA256
)
echo "checksum: $(cat build/CHECKSUM.SHA256)"

# 2) vérifier dans un autre environnement
(
  cd ./build/data.pm
  SUM="$(git ls-files -z | xargs -0 shasum -a 256 | shasum -a 256 | awk '{print $1}')"
  test "$SUM" = "$(cat ../CHECKSUM.SHA256)" && echo "OK" || { echo "MISMATCH"; exit 1; }
)

# 3) Linux (GNU coreutils) hors git: inclure tout sauf .git et node_modules
LC_ALL=C \
find . -type f -not -path './.git/*' -not -path './node_modules/*' -print0 \
  | sort -z \
  | xargs -0 sha256sum \
  | sha256sum \
  | awk '{print $1}'

variante(s) utile(s)

# archive deterministe (GNU tar) puis hash (utile pour publier sur cdn.data.pm)
tar -C . --sort=name --mtime='UTC 2020-01-01' --numeric-owner --owner=0 --group=0 \
  --exclude='.git' --exclude='node_modules' -cf - . \
  | sha256sum | awk '{print $1}'

# fallback portable sans GNU sort/sum: script Python (ignore .git et node_modules)
python3 - <<'PY'
import os, sys, hashlib
root = sys.argv[1] if len(sys.argv)>1 else '.'
h = hashlib.sha256()
for dp, dn, fn in os.walk(root):
    dn[:] = [d for d in dn if d not in ('.git','node_modules')]
    for name in sorted(fn):
        p = os.path.join(dp, name)
        with open(p,'rb') as f:
            for chunk in iter(lambda: f.read(8192), b''):
                h.update(chunk)
        h.update(b'\0')
print(h.hexdigest())
PY

# comparer deux répertoires (ex: build local vs artefact décompressé de data.pm)
A="./build-local" B="./artifact-data.pm"
hash_dir() { (cd "$1" && git ls-files -z | xargs -0 shasum -a 256 | shasum -a 256 | awk '{print $1}'); }
[ "$(hash_dir "$A")" = "$(hash_dir "$B")" ] && echo "identiques" || echo "différents"

# lister les différences de contenu (hash par fichier trié, portable)
find . -type f -not -path './.git/*' -print0 \
 | xargs -0 shasum -a 256 \
 | sort > /tmp/list.sha

notes

  • la méthode git ls-files produit un ensemble trié et portable; idéale pour des artefacts versionnés.
  • sur Linux hors git, la chaîne find -print0 | sort -z | xargs -0 sha256sum | sha256sum donne un hash stable.
  • pour publier, combinez une archive déterministe et son checksum (ex: site.tar.zst + site.tar.zst.sha256) sur cdn.data.pm.
  • ne hashez pas des fichiers volatils (timestamps incrustés, manifest non figé) si vous visez la reproductibilité.