SBOM
Une SBOM doit décrire le build qui a été livré
Une SBOM au build est enregistrée pendant l'exécution du build, à partir du trafic qui y est réellement entré. La plupart des générateurs de SBOM reconstituent au contraire la liste après coup à partir du lockfile ou de la sortie, ce qui rate les dépendances cachées qu'un build récupère de lui-même. Voici pourquoi, et ce que change l'enregistrement du build.
Mis à jour le
SBOM de build, SBOM de source, SBOM analysée
Les recommandations de la CISA sur les types de SBOM les classent selon le moment et la manière dont elles sont produites. Trois d'entre eux couvrent presque tous les générateurs de SBOM utilisés :
| Type | Comment elle est produite | Ce qu'elle peut rater |
|---|---|---|
| Source | À partir des fichiers source, des manifestes et des lockfiles, généralement par un outil SCA | Les composants d'exécution, de plugin ou de plateforme ; tout ce qui n'est pas déclaré dans les fichiers |
| Build | Dans le cadre du build qui crée l'artefact à publier | Ce que l'environnement de build ne peut pas voir, d'où l'intérêt d'indiquer la complétude |
| Analysée | Après le build, par l'analyse d'un exécutable, d'un paquet ou d'une image de conteneur | Les composants que l'outil ne peut pas reconnaître ; les résultats dépendent d'heuristiques |
La CISA cite deux avantages d'une SBOM de build : une plus grande certitude que la SBOM représente correctement l'artefact, grâce
aux informations disponibles pendant le build et le processus CI/CD, et une plus grande confiance, car le même workflow de build
peut signer à la fois la SBOM et l'artefact. L'inconvénient qu'elle cite est qu'il faut parfois modifier le processus de build pour
en générer une. Avec CRACI, cette modification tient en une ligne, runs-on: craci, et l'enregistrement est fourni avec le
runner.
Scanner un dossier ou enregistrer un build
La plupart des générateurs de SBOM sont des scanners. Vous en pointez un vers une arborescence source ou une image de conteneur, et il déduit ce qui y est entré selon lui en lisant les manifestes, les lockfiles, les paquets installés ou les binaires. C'est utile, et pour les logiciels que vous n'avez pas construits vous-même, c'est souvent la seule option.
La faiblesse est qu'un scanner ne voit que ce qu'il a devant lui. Si aucun lockfile n'a été commité, si les dépendances n'ont pas été installées avant le scan, ou si le produit est livré sous forme de binaire compilé, le scanner dispose de moins d'éléments que le build. Un scan qui ne trouve aucun composant produit quand même un document SBOM valide, et c'est ce qui piège souvent les équipes.
CRACI adopte une autre approche. Il génère la SBOM dans son propre runner CI : l'artefact livré est donc l'artefact décrit. Ce n'est pas un scan exécuté quelque part à côté.
SBOM basics: SPDX, CycloneDX and OpenVEX
Ce qu'enregistre une SBOM, en quoi les formats SPDX et CycloneDX diffèrent en pratique, et ce qu'OpenVEX apporte pour savoir si une vulnérabilité affecte réellement un produit.
Petteri Pulkkinen et Erika Marttinen lors de Kubernetes Community Days Helsinki 2026, 16:50 à 22:05 de SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.
Ce dont dépend un scan
Syft, Trivy, cdxgen, le Microsoft SBOM Tool, l'export du graphe de dépendances de GitHub et la Socket CLI déduisent tous une SBOM de ce qu'ils peuvent lire. Les constats ci-dessous découlent du fonctionnement documenté de ces outils.
Les outils divergent sur ce qui compte comme composant
Chaque générateur décide lui-même de ce qui compte comme composant et des fichiers auxquels se fier : un même commit épinglé donne donc à chacun une liste différente.
Une partie tient au nommage. Les outils identifient la même GitHub Action sous des types de package URL différents : ils peuvent donc lister la même chose sans que cela corresponde. Cela fait aussi partie du problème : une SBOM qui utilise un autre identifiant pour un composant est plus difficile à faire correspondre aux données de vulnérabilité.
L'installation préalable peut compter davantage que l'outil
Express 5.2.1 ne commite pas de lockfile. Pointé vers un checkout propre, un
générateur qui résout les dépendances à partir des lockfiles ou d'une arborescence installée
n'a ni l'un ni l'autre devant lui : aucune des dépendances npm déclarées dans
package.json n'atteint donc le document. Il peut tout de même renvoyer une liste,
composée de tout ce qu'il reconnaît par ailleurs, comme les GitHub Actions et les
fichiers de workflow qui les référencent. Aucun outil n'est ici défaillant.
Sur une copie installée du même dépôt, un seul flag Syft change de nouveau la réponse. Même outil, même arborescence, même version. Par conception, un scan de répertoire Syft signale ce qu'un projet déclare, et le cataloger qui lit les paquets installés ne fait pas partie de son ensemble par défaut pour les répertoires.
Certains logiciels n'ont aucun manifeste à lire
Le dépôt anthropics/claude-code en v2.1.259 n'a aucun manifeste de
dépendances, de quelque sorte que ce soit : ni package.json, ni lockfile, ni
équivalent. Ce que renvoie chaque générateur est assemblé à partir d'autres types de
fichiers : la réponse en dit donc plus sur l'outil que sur le projet.
Le paquet npm publié n'est guère différent. @anthropic-ai/claude-code déclare zéro dépendance d'exécution et
huit paquets propres à une plateforme qui encapsulent un binaire précompilé.
@openai/codex 0.149.1 présente la même structure. Ce qui s'exécute sur la
machine du développeur est un binaire compilé dans lequel aucun lecteur de manifeste ne peut
voir. Ce n'est pas un défaut d'un outil en particulier. C'est un modèle de distribution que
le scan après coup ne peut pas décrire.
Versions et fournisseurs
Lorsque deux outils trouvent le même paquet, ils ne s'accordent pas toujours sur sa version. L'un peut épingler une GitHub Action à un SHA de commit tandis qu'un autre indique un tag de release. Une recherche de vulnérabilités fondée sur la mauvaise version donne une réponse fausse mais assurée.
Le champ fournisseur, l'un des éléments minimaux de la NTIA, reste souvent vide, car la plupart des générateurs n'ont aucune source pour le remplir.
Dépendances cachées : ce qu'aucun scan ne peut voir
Tous les outils ci-dessus partent du lockfile ou de la sortie du build et en déduisent ce qui y est entré. Un build récupère davantage. Ces dépendances cachées ne figurent dans aucun lockfile, et un scan ne peut donc pas les trouver :
-
Les hooks d'installation. Les scripts npm
preinstalletpostinstalls'exécutent pendant l'installation et peuvent télécharger davantage de code. C'est ainsi que s'est exécuté le ver Shai-Hulud. - Les scripts de build. Les scripts de build Rust, entre autres, téléchargent ce dont ils ont besoin au moment du build.
- Les images de base. Un build de conteneur récupère une image de base et ses couches de système d'exploitation, qu'aucun lockfile de langage ne liste.
- Les caches et les outils de build. Les paquets restaurés depuis les caches CI et les outils installés par les étapes de configuration arrivent eux aussi en dehors du lockfile.
Scanner la sortie après coup ne comble pas la lacune. Un binaire terminé, surtout du code compilé comme Rust, oblige le scanner à deviner ce qui y est entré.
Deux builds, deux SBOM
Il y a une seconde raison pour laquelle un scan ne peut pas remplacer le build : la plupart des builds ne sont pas reproductibles. Construisez deux fois de suite le même commit, et rien ne garantit que vous obtiendrez les mêmes paquets. Les gestionnaires de paquets résolvent et installent dans l'ordre d'arrivée des réponses, ce qui compte surtout en l'absence de lockfile, comme dans de nombreux projets Python, et les étapes de build peuvent comporter leur propre part d'aléatoire. Des builds reproductibles octet par octet sont possibles, avec des outils comme Nix, mais ils sont rares.
Une SBOM générée plus tard, sur une autre machine ou à partir d'un autre build, décrit donc un build qui n'a peut-être jamais été livré. Seule la SBOM enregistrée pendant le build CI qui a produit une release prouve ce qui est en production.
Ce que change l'enregistrement du build
CRACI voit le trafic ; pas les scanners. Il exécute vos jobs GitHub Actions sur ses propres runners et voit le trafic réseau entrant dans chaque build : la SBOM liste donc ce que le job a réellement récupéré, dépendances transitives et cachées comprises, et non ce qu'un manifeste dit qu'il devrait nécessiter.
C'est sur les caches que l'enregistrement au build se complique. Un paquet restauré depuis un cache ne passe jamais par un registre de paquets : un proxy seul le raterait donc. CRACI transmet les preuves de dépendances avec le cache, de sorte que les paquets restaurés depuis un cache restent dans la SBOM du job qui les a restaurés. Voir ce que le cache GitHub Actions dissimule.
Les écosystèmes détectés comprennent npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk et les sources Git, ainsi que les presets de téléchargement Yocto et OpenEmbedded. Les miroirs npm et PyPI de JFrog Artifactory fonctionnent. Les métadonnées de licence déclarée sont incluses dans l'export. Les SBOM s'exportent en CycloneDX et SPDX. La page génération de SBOM présente l'ensemble de la fonctionnalité.
Voir le trafic fonctionne aussi dans l'autre sens. Un build a besoin de paquets provenant de sources connues et publie sa sortie vers des destinations connues. La politique de trafic sortant de CRACI n'autorise que celles-ci et bloque immédiatement toute autre connexion sortante : un malware qui tente d'envoyer vos secrets vers le serveur d'un attaquant échoue donc. Comme la politique autorise ce dont le build a besoin au lieu de chercher des hôtes malveillants connus, elle tient même si vous êtes la première cible d'une attaque que personne n'a encore vue, comme avec Shai-Hulud. Voir comment une politique de trafic sortant arrête l'exfiltration.
SBOM de conteneurs et Docker
C'est sur les images de conteneur que la différence se voit le plus. Les méthodes habituelles pour obtenir une SBOM Docker analysent toutes l'image :
Syft et Trivy la scannent, docker scout sbom indexe son contenu lorsque l'image ne porte aucune attestation
SBOM, et l'attestation SBOM de BuildKit, activée avec --sbom=true, exécute par défaut un scanner basé sur Syft
sur l'étape finale de l'image. L'ancien plugin docker sbom est déprécié au profit de
docker scout sbom.
Chacun d'eux lit l'image terminée : il voit donc ce qui reste reconnaissable dans les couches. Il ne voit pas ce que le build a récupéré en cours de route. CRACI enregistre le job qui construit l'image : les images et les paquets que le job récupère depuis les registres OCI et les sources de paquets entrent dans la même SBOM que le reste du build. Pour une image que vous n'avez pas construite, le scan reste l'option pratique. Voir ce que ratent les SBOM d'images Docker.
La complétude, indiquée par job
Une SBOM enregistrée ne vaut que ce que vaut l'enregistrement. Plutôt que de présenter chaque SBOM comme complète, CRACI indique la complétude de chaque job et de chaque cache, selon cinq états :
- Complete. CRACI a observé des preuves complètes pour le job, et chaque cache restauré était complet.
- Complete with connections. Les exigences sont remplies, mais le job a utilisé une ou plusieurs connexions réseau personnalisées : il vaut donc la peine d'examiner ce qui est passé par elles.
- Incomplete. CRACI a identifié une condition susceptible de laisser des dépendances hors de la SBOM.
- Unavailable. CRACI n'a pas pu terminer l'évaluation des preuves.
- Not recorded. Le job est antérieur au suivi de la complétude.
La complétude est transitive à travers les caches. Si un job restaure un cache incomplet, sa SBOM est incomplète elle aussi, et tout cache produit par ce job reporte le statut incomplet. Vous savez sur quelles SBOM vous pouvez compter et lesquelles méritent un second examen.
The hard parts: hooks, noise and staying current
Trois problèmes que relève la conférence : les hooks post-installation qui récupèrent des éléments qu'aucun manifeste ne liste, repérer les dépendances qui comptent dans une longue liste, et garder la SBOM à jour, ce qui implique de la générer dans la CI à chaque build.
Petteri Pulkkinen et Erika Marttinen lors de Kubernetes Community Days Helsinki 2026, 25:39 à 27:22 de SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.
La provenance via l'API
La SBOM n'est qu'une partie de ce que CRACI enregistre pour chaque job. L'API renvoie les SBOM, les traces réseau et la provenance, toutes enregistrées à partir du même build.
Là où un scanner reste le bon outil
L'enregistrement au build couvre les logiciels que vous construisez. Pour une image ou un binaire tiers que vous n'avez pas construit, un scanner reste le choix pratique, et les outils ci-dessus sont performants et largement utilisés. Le propos n'est pas que les scanners soient mauvais. C'est que la SBOM de vos propres releases devrait venir du build qui les a produites.
Une SBOM CRACI a aussi ses propres limites. Elle couvre les jobs qui s'exécutent sur des runners CRACI, c'est-à-dire aujourd'hui GitHub Actions sous Linux, les autres systèmes CI figurant sur la roadmap.
Vous comparez des outils ? Voir le comparatif des outils SBOM, ou voyez comment les SBOM au build s'inscrivent dans le travail de conformité au CRA. Pour Syft, Trivy et cdxgen côte à côte, voir ce que ratent les générateurs de SBOM open source.
SBOM au build : questions fréquentes
Qu'est-ce qu'une SBOM au build ?
Une SBOM au build, que la CISA appelle build SBOM, est générée dans le cadre de la construction de l'artefact à publier. Au lieu de reconstituer la liste des composants à partir de fichiers après coup, elle décrit ce que le build lui-même a utilisé. CRACI l'enregistre à partir des paquets réellement récupérés par chaque job GitHub Actions.
Quelle est la différence entre une SBOM de build et une SBOM analysée ?
Une SBOM analysée est générée après le build par l'analyse d'un artefact tel qu'un exécutable ou une image de conteneur, ce qui exige généralement des heuristiques. Une SBOM de build est générée pendant le build, à partir des informations dont dispose le build. Les SBOM analysées fonctionnent sans accès au build, ce qui en fait le bon choix pour les logiciels que vous n'avez pas construits.
Comment générer une SBOM pour une image Docker ?
Pour une image existante, scannez-la avec un générateur tel que Syft, Trivy ou docker scout sbom. BuildKit peut aussi attacher une attestation SBOM lors du build, en scannant l'image finale. Pour enregistrer ce que le build d'une image a récupéré, exécutez le build sur un runner CRACI : la SBOM du job couvre les images et les paquets qu'il a récupérés.
Que sont les dépendances cachées ?
Tout ce qu'un build récupère et qu'aucun lockfile ne liste : le code téléchargé par les hooks d'installation npm, les fichiers que les scripts de build Rust téléchargent au moment du build, et l'image de base et ses couches de système d'exploitation dans un build de conteneur. Les outils qui lisent le lockfile ou scannent la sortie les ratent. CRACI les enregistre parce qu'il voit le trafic entrant dans le build.
Pourquoi deux builds du même code donnent-ils des SBOM différentes ?
Parce que la plupart des builds ne sont pas reproductibles. Le gestionnaire de paquets résout et installe les paquets dans l'ordre d'arrivée des réponses, surtout sans lockfile, et les étapes de build peuvent comporter une part d'aléatoire. Construisez deux fois de suite le même commit, et le second build peut contenir des paquets différents. Seule la SBOM enregistrée pendant le build qui a produit une release prouve ce que contient cette release.
Une SBOM au build est-elle toujours complète ?
Pas automatiquement. Un enregistrement ne vaut que ce qu'il peut observer. CRACI indique donc la complétude de chaque job et de chaque cache : Complete, Complete with connections, Incomplete, Unavailable ou Not recorded. Vous savez sur quelles SBOM vous pouvez compter et lesquelles méritent un second examen.
Une SBOM au build remplace-t-elle les scanners SBOM ?
Pour les logiciels que vous construisez, oui : la SBOM de vos releases devrait venir des builds qui les ont produites. Pour les images et binaires tiers que vous n'avez pas construits, un scanner reste le choix pratique. Le comparatif des outils SBOM présente les options.
Quel générateur de SBOM CRACI utilise-t-il ?
Aucun. CRACI ne scanne pas de fichiers. Un proxy qui comprend les paquets, sur ses runners, enregistre les paquets que chaque job récupère depuis npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk et les sources Git, ainsi que les presets de téléchargement Yocto et OpenEmbedded, et exporte le résultat en CycloneDX ou SPDX.
Comparez une SBOM issue de votre propre build
Réservez une démo et exécutez l'un de vos workflows sur CRACI. Comparez sa SBOM à celle que produit votre outil actuel et voyez où elles diffèrent.
Réserver une démo