Picarones / scripts /gen_sbom.py
Claude
docs: refonte Diataxis + 8 documents institutionnels (S60)
d0a3fab unverified
#!/usr/bin/env python3
"""Génère le SBOM (Software Bill of Materials) au format CycloneDX.
Audience : DSI institutionnelle, conformité EU CRA (Cyber Resilience
Act, exigible à partir de 2027 pour livraisons institutionnelles).
Le SBOM liste tous les paquets Python installés dans l'environnement
courant avec leur version, licence et hash, au format CycloneDX 1.5
JSON.
Usage
-----
::
pip install cyclonedx-bom
python scripts/gen_sbom.py [--output sbom.json]
Le SBOM produit doit être attaché à chaque release tag (artefact
GitHub Release) — c'est ce que l'institution archive aux côtés du
wheel pour traçabilité supply-chain.
Pour un SBOM signé Sigstore (SLSA level 3), voir le pipeline GitHub
Actions ``release.yml`` qui invoque ``cosign sign-blob`` sur le
fichier produit.
"""
from __future__ import annotations
import argparse
import shutil
import subprocess
import sys
from pathlib import Path
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--output",
default="sbom.json",
help="Fichier de sortie CycloneDX JSON (défaut : sbom.json).",
)
parser.add_argument(
"--format",
choices=["json", "xml"],
default="json",
help="Format CycloneDX (défaut : json).",
)
args = parser.parse_args()
if shutil.which("cyclonedx-py") is None:
sys.stderr.write(
"[gen_sbom] cyclonedx-py absent. Installer avec : "
"pip install cyclonedx-bom\n",
)
return 1
out = Path(args.output).resolve()
cmd = [
"cyclonedx-py",
"environment",
"--output-format",
args.format,
"--outfile",
str(out),
]
print(f"[gen_sbom] {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
sys.stderr.write(result.stderr)
return result.returncode
print(f"[gen_sbom] SBOM écrit dans {out}")
return 0
if __name__ == "__main__":
sys.exit(main())