File size: 2,071 Bytes
d0a3fab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/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())