Aller au contenu principal

SBOM (Software Bill of Materials)

Un SBOM (Software Bill of Materials) est la liste des ingrédients d’un build : chaque dépendance directe et transitive intégrée à un artefact, avec ses versions et ses hachages. fremforge stocke les SBOM que produit votre CI, afin que l’inventaire survive d’un build à l’autre, aux rotations d’images et à la dérive des dépendances.

Quand les SBOM sont générés automatiquement

Il n’y a rien à installer. fremforge génère un SBOM CycloneDX 1.6 de manière centralisée pour chaque pull request, sur ses propres runners, et lie ce SBOM à une release lorsque vous en publiez une : n’importe quel tag, y compris les formes semver / calver habituelles (v1.2.3, v2026.06).

Nous ne réanalysons délibérément pas au moment de la release. Un SBOM dépend de l’arborescence source, et l’arborescence que vous publiez a déjà été analysée en tant que tête de la pull request qui l’a fusionnée : en générer un second produirait un fichier identique octet pour octet. La publication d’une release marque plutôt le SBOM déjà détenu pour ce commit exact comme SBOM de la release. Deux conséquences à connaître :

  • C’est immédiat. Aucun build ne s’exécute, si bien que le SBOM de la release est disponible dès que la release est publiée.
  • Le lien est établi côté serveur. fremforge résout votre tag vers son commit via Forgejo et fait la correspondance sur ce commit, si bien que rien dans un build ne peut revendiquer un SBOM de release qu’il n’a pas mérité.

Si vous publiez une release pour un commit qui n’est jamais passé par une pull request (un tag sur un commit très ancien, ou un dépôt dont l’historique est antérieur à l’analyse), il n’y a pas de SBOM à lier. Cette release est signalée comme non couverte plutôt qu’ignorée en silence ; relancez une analyse sur le commit pour la couvrir.

Déclencher un SBOM en taguant une release

En ligne de commande :

git tag v1.2.3
git push origin v1.2.3

Depuis l’interface de Forgejo : ouvrez le dépôt → Publications → Nouvelle publication, saisissez un nom de tag commençant par v (par exemple v1.2.3) et cliquez sur Publier.

Un SBOM ponctuel pour un commit quelconque est aussi disponible via l’onglet Actions → SBOM (Syft) → Run workflow.

Pourquoi seule une release est-elle liée ? Un SBOM est généré pour chaque pull request, mais seul celui d’un commit publié devient un SBOM de release : les auditeurs veulent le SBOM « au moment où nous avons livré la release X ». Lier à la release garde le nombre de SBOM de release proportionnel à votre rythme réel de releases.

Ce que fremforge accepte

fremforge génère des SBOM CycloneDX 1.6 et SPDX 2.3, et accepte les deux à l’ingestion :

  • CycloneDX JSON (1.6) : l’inventaire que lit chaque fonctionnalité de fremforge (liaison aux releases, vérification d’inventaire vide, vue d’ensemble). L’écosystème d’outils plus large (Trivy, Syft, anchore) produit nativement du CycloneDX.
  • SPDX JSON (2.3) : généré à côté par la même exécution de Syft lors de chaque analyse de PR, et stocké sous le même build, si bien que la page des SBOM propose les deux téléchargements pour une même release. Vos propres envois peuvent être en CycloneDX 1.5–1.7 ou SPDX 2.x/3.x ; l’ingestion valide specVersion / spdxVersion avant le stockage.

Le document SPDX est un format d’export, généré au mieux : pour un très gros dépôt dont les deux documents ensemble dépasseraient la limite de livraison de 14 Mio, seul le SBOM CycloneDX est stocké, afin que l’inventaire ne soit jamais perdu pour faire de la place au second format.

Chaque SBOM est stocké avec :

  • Le digest SHA-256 du fichier SBOM. L’expéditeur l’envoie et le serveur le recalcule, si bien qu’un envoi tronqué ou modifié est refusé.
  • Un bundle d’attestation in-toto facultatif (JSONL), signé avec Cosign lorsque votre workflow signe le SBOM. L’ingestion valide la forme du JSONL et les champs in-toto de chaque ligne avant le stockage.
  • Le nom et la version de l’artefact, exactement tels que votre workflow les nomme. Ils servent de clé de déduplication (même digest + nom + version = une seule ligne, pas plusieurs).

Limite stricte de 5 Mio par SBOM. Le point de terminaison d’ingestion renvoie 413 payload-too-large au-delà ; découpez les SBOM de gros monodépôts par module si vous l’atteignez.

Comment envoyer un SBOM depuis la CI

L’image de runner fremforge embarque Syft et Trivy, si bien que la plupart des workflows tiennent en un court extrait :

- name: Generate + push SBOM
  run: |
    syft packages dir:. --output cyclonedx-json=sbom.json
    # The digest is the SHA-256 of the SBOM file itself; the server recomputes it
    # and refuses a mismatch with 400 digest-mismatch.
    DIGEST=$(sha256sum sbom.json | cut -d' ' -f1)
    curl -sS --fail \
      -H "Authorization: Bearer ${{ secrets.FREMFORGE_API_TOKEN }}" \
      -F "sbom=@sbom.json" \
      -F "artifact_name=myapp" \
      -F "artifact_version=${GITHUB_SHA}" \
      -F "sha256_digest=${DIGEST}" \
      -F "format=cyclonedx-json" \
      "https://frem.sh/_app/api/v1/orgs/${ORG}/sboms"

Le PAT a besoin de la portée sboms:write ; créez-en un depuis Administration de l’organisation → Jetons d’API en cochant la portée d’envoi de SBOM.

Deux champs facultatifs indiquent où l’artefact s’exécute et à partir de quel dépôt il a été construit :

  • environment : la classe d’environnement dans laquelle l’artefact s’exécute, parmi sandbox, development, test ou production. Toute autre valeur est refusée avec invalid-environment.
  • source_repo : le dépôt à partir duquel l’artefact a été construit, sous la forme owner/repo. Toute autre forme est refusée avec invalid-source-repo.
      -F "environment=production" \
      -F "source_repo=acme/payments-api" \

Aucun de ces champs ne modifie la conservation ni une quelconque vérification bloquante. Un SBOM CycloneDX avec source_repo prête aussi son graphe de dépendances aux chemins de dépendances de ce dépôt, c’est ainsi que les dépôts Maven et Gradle les obtiennent.

Où les SBOM apparaissent dans l’interface d’administration

Admin → Sécurité › Composants › SBOM liste chaque SBOM ingéré, groupé par artefact. Chaque ligne affiche :

  • le nom et la version de l’artefact, et son digest SHA-256 ;
  • le format (CycloneDX / SPDX) et la taille ;
  • l’horodatage d’ingestion et l’utilisateur ou le PAT qui l’a envoyé ;
  • un lien « Verify signature » lorsqu’une attestation est jointe.

Comment les SBOM interagissent avec les autres signaux de sécurité

  • Scorecard : ils alimentent les scores Dependencies et Vulnerabilities du calcul OpenSSF Scorecard.
  • Recommandations OSV : lorsqu’un avis OSV correspond à un composant listé dans un SBOM, la recommandation apparaît avec l’impact rattaché au SBOM (« ceci affecte le build myapp@v1.2.3 du 2026-05-12 »).
  • Cosign : la signature des SBOM utilise la même racine de confiance Cosign que la signature des images. Voir Cosign pour la procédure de vérification.

Conservation

Les SBOM des releases sont conservés tant que votre organisation existe. Les SBOM des builds qui n’ont pas fait l’objet d’une release sont supprimés après la durée de conservation des preuves sbom : 14 jours par défaut, de 0 à 3650 jours. Le SBOM de la tête de la branche par défaut, ceux des images actuelles et ceux des fichiers de paquets sont conservés quel que soit leur âge. Rien n’est supprimé tant qu’une conservation légale est en place. (Jusqu’au 2026-10-08, cette section indiquait que les SBOM suivaient les préréglages de conservation de l’audit ; cela n’a jamais été le cas.)

Voir aussi

  • Cosign : signature des images et des SBOM.
  • Recommandations OSV : vulnérabilités rapprochées des composants des SBOM.
  • Scorecard : les SBOM alimentent les scores de dépendances et de vulnérabilités.
  • Référence de l’API : point de terminaison d’ingestion POST /_app/api/v1/orgs/{slug}/sboms.