Inventaire des composants
L’inventaire des composants répond à deux questions sans ouvrir un seul SBOM : où ce composant est-il utilisé, et quels composants vulnérables sont en service en ce moment. Il est construit à partir des SBOM que fremforge détient pour votre organisation et il est activé pour toutes les organisations.
Vous le trouverez dans l’administration de l’organisation sous Sécurité › Composants, avec les onglets Inventaire, Vulnérables en service, Versions téléchargées, Déploiements et Règles d’environnement. Versions téléchargées liste les versions de paquets que vos consommateurs ont réellement téléchargées, voir Versions de paquets téléchargées. Déploiements est décrit plus bas.
Ce qui est indexé
Chaque SBOM CycloneDX actuel est lu dans l’inventaire, avec une ligne par composant et par endroit où il est utilisé :
| Endroit où il est utilisé | Ce qui compte comme actuel |
|---|---|
| Un dépôt | le SBOM de la tête de sa branche par défaut |
| Une version publiée | la version la plus récente du dépôt |
| Une image de conteneur | chaque condensé d’image encore publié dans votre registre |
| Un paquet du registre | chaque fichier de paquet qui n’a pas été supprimé, dès que les politiques de paquets sont disponibles pour votre organisation |
| Un SBOM envoyé | l’envoi le plus récent de chaque nom d’artefact |
Un nouveau SBOM ne met à jour que ce qui a changé : un composant toujours présent conserve sa ligne et la date à laquelle il a été vu pour la première fois, et un composant disparu est marqué comme retiré. Les utilisations retirées sont conservées 180 jours, pour que vous puissiez encore répondre à « quand avons-nous cessé d’utiliser X ». Les nouveaux SBOM sont indexés à leur arrivée ; une tâche de fond rattrape toutes les 30 minutes ce qui aurait été manqué.
Recherche
Chaque liste accepte les mêmes filtres, tous facultatifs et combinables :
| Paramètre | Correspond à |
|---|---|
q | le nom du composant, exact ou par préfixe ; une valeur commençant par pkg: correspond à la package URL |
purl | une package URL ; sans version, elle correspond à toutes les versions |
range | une plage de versions purl-spec, telle que vers:npm/>=4.17.0|<4.17.21 ; nécessite purl sans version |
ecosystem, version | l’écosystème, et une version exacte |
licence | un identifiant SPDX dans l’expression de licence, ou unknown |
environment | sandbox, development, test, staging, production ou unclassified |
environment_source | l’origine de la classe : deployment, reported ou rule |
subject_kind | repo, release, image, package ou artifact |
subject | le nom du dépôt, de l’image, du paquet ou de l’artefact |
current | true (par défaut) : en service maintenant ; false renvoie aussi les utilisations retirées |
API REST
L’API est servie sous https://frem.sh/_app/api/v1. Utilisez un jeton d’API d’organisation ou un PAT avec la portée components:read ; findings:read est également accepté.
| Point de terminaison | Renvoie |
|---|---|
GET /orgs/{slug}/components | les composants en service, une ligne par package URL, avec le nombre d’endroits qui utilisent chacun, dans quels environnements et pour quels types d’utilisation |
GET /orgs/{slug}/components/usages | « où X est-il utilisé » : une ligne par composant et par endroit |
GET /orgs/{slug}/components/{id} | un composant |
GET /orgs/{slug}/components/{id}/usages | où ce composant est utilisé |
GET /orgs/{slug}/components/vulnerable | les composants vulnérables en service, joints aux résultats ouverts ; min_severity=low|medium|high|critical |
GET /orgs/{slug}/components/vulnerable/summary | le nombre de composants et d’utilisations vulnérables, par sévérité et par environnement |
GET /orgs/{slug}/repos/{repo}/dependencies/paths | quelles dépendances directes introduisent un composant dans le dépôt, voir Chemins de dépendances |
GET /orgs/{slug}/components/environment-rules | vos règles et libellés d’environnement |
PUT /orgs/{slug}/components/environment-rules | remplace les règles (nécessite policy:write, consigné dans le journal d’audit) |
Par exemple, chaque endroit où lodash antérieur à 4.17.21 est en service :
curl -sS -H "Authorization: Bearer $FREMFORGE_TOKEN" \
"https://frem.sh/_app/api/v1/orgs/<org>/components/usages?purl=pkg:npm/lodash&range=vers:npm/%3C4.17.21"Pagination
Les listes sont paginées par curseur. Chaque réponse est de la forme { "items": [...], "next_cursor": "..." } ; renvoyez next_cursor comme cursor pour obtenir la page suivante, jusqu’à ce qu’il vaille null. limit va de 1 à 500 et vaut 100 par défaut. Un curseur appartient au point de terminaison qui l’a émis ; un autre point de terminaison le refuse avec invalid-cursor.
Export CSV
Ajoutez format=csv, ou envoyez Accept: text/csv, à n’importe quelle liste (/components, /components/usages, /components/{id}/usages, /components/vulnerable) et l’ensemble du résultat revient sous la forme d’un seul fichier CSV avec les mêmes filtres, sans pagination. Un CSV contient au plus 200 000 lignes ; au-delà, l’API répond 413 too-many-rows, et vous devez affiner les filtres, parcourir le JSON page par page ou utiliser l’export de données. Les pages d’administration proposent le même export sous forme de bouton de téléchargement.
L’inventaire complet, y compris les utilisations retirées, figure aussi dans chaque export de données sous metadata/components.ndjson, voir Schéma d’export.
Chemins de dépendances
Pour une dépendance transitive, l’inventaire montre quelle dépendance directe l’introduit, comme le fait le graphe de dépendances de GitHub. Dans Vulnérables en service, chaque ligne indique Introduit via suivi du chemin, par exemple async@2.6.3 → lodash ; sur la page d’un composant, la colonne Dépendance montre le même chemin, ou Directe lorsque le dépôt dépend du composant lui-même.
Le chemin provient du graphe de dépendances contenu dans un SBOM. fremforge conserve une copie compacte de ce graphe pour chaque SBOM qu’il indexe, si bien qu’un chemin ne coûte aucun téléchargement de SBOM. Les chemins n’existent que là où un SBOM contient des arêtes de dépendances. Avec les SBOM que fremforge génère lui-même (syft, à partir des fichiers du dépôt), cela donne :
| Écosystème | Fichier | Chemins |
|---|---|---|
| npm | package-lock.json, pnpm-lock.yaml, yarn.lock | oui |
| PyPI | uv.lock, poetry.lock | oui |
| Cargo | Cargo.lock | oui |
| Go | go.mod | oui : fremforge lit le go.mod de chaque module depuis son cache de modules Go, sans exécuter aucun code de votre dépôt |
| Maven | pom.xml | non : chaque paquet que le pom intègre est dans l’inventaire, mais sans les arêtes qui les relient ; poussez un SBOM CycloneDX depuis la CI pour obtenir les chemins, voir ci-dessous |
| Gradle | non : poussez un SBOM CycloneDX depuis la CI, voir ci-dessous | |
| NuGet | packages.lock.json | oui, pour les SBOM générés depuis le 2026-10-10 (syft 1.54.1) ; les SBOM plus anciens n’en montrent aucun, car les versions antérieures de syft écrivaient mal ces arêtes |
Composer, RubyGems, requirements.txt, Pipfile.lock | non : le SBOM ne contient aucune arête de dépendance |
Là où il n’y a pas de chemin, la ligne n’en affiche aucun plutôt que d’en deviner un.
La manière dont une dépendance directe est déterminée dépend du fichier de verrouillage. Un package-lock.json npm, un uv.lock, un Cargo.lock et un go.mod listent le projet lui-même, et ses dépendances sont les dépendances directes (dans go.mod, les exigences non marquées // indirect). pnpm-lock.yaml, yarn.lock, poetry.lock et packages.lock.json ne listent pas le projet dans le SBOM : une dépendance directe est donc considérée comme un paquet dont rien d’autre dans le fichier de verrouillage ne dépend. Une dépendance directe qu’un autre paquet requiert aussi est alors affichée via ce paquet. Un SBOM dont le composant racine liste ses propres dépendances, comme l’écrivent les plugins de build CycloneDX, indique lesquelles sont directes. L’API indique la règle appliquée dans graph.direct_basis (project, roots ou declared).
Côté API, GET /orgs/{slug}/repos/{repo}/dependencies/paths répond pour la tête de la branche par défaut du dépôt, et pour les SBOM que votre CI a poussés pour celui-ci (voir ci-dessous), avec un plus court chemin par dépendance directe menant au composant, du plus court au plus long. Passez purl (sans version, il correspond à toutes les versions) ou component_id, plus limit (de 1 à 100, 20 par défaut) et cursor pour la page suivante. Chaque chemin indique sa provenance dans source (scan ou upload) et sbom_id, et graph.sources liste chaque graphe qui a été lu. Les éléments de /components/vulnerable et /components/usages portent via, la package URL de la dépendance directe, et dependency_path, le plus court chemin de celle-ci jusqu’au composant.
curl -sS -H "Authorization: Bearer $FREMFORGE_TOKEN" \
"https://frem.sh/_app/api/v1/orgs/<org>/repos/<repo>/dependencies/paths?purl=pkg:npm/lodash"Chemins pour Maven, Gradle et Go depuis la CI
Résoudre un arbre de dépendances Maven ou Gradle implique d’exécuter l’outil de build, et l’outil de build exécute des plugins issus de vos fichiers de build. fremforge n’exécute pas votre build sur ses serveurs ; pour ces écosystèmes, le graphe provient donc de votre propre CI : générez un SBOM CycloneDX avec le plugin CycloneDX de l’outil de build, qui écrit le graphe dependencies complet et résolu, et poussez-le avec source_repo défini sur le dépôt. L’API des chemins, via dans Vulnérables en service et la page du composant utilisent alors ce graphe pour le dépôt. Poussez-le depuis la branche par défaut, car c’est l’envoi le plus récent de chaque artifact_name qui compte.
La même étape de push fonctionne pour les trois. Le secret FREMFORGE_API_TOKEN contient un jeton avec la portée sboms:write ; fremforge le crée dans chaque nouveau dépôt.
- name: Push the SBOM to fremforge
env:
FREMFORGE_API_TOKEN: ${{ secrets.FREMFORGE_API_TOKEN }}
run: |
set -euo pipefail
DIGEST=$(sha256sum "$SBOM" | cut -d' ' -f1)
curl -sS --fail-with-body \
-H "Authorization: Bearer $FREMFORGE_API_TOKEN" \
-F "sbom=@$SBOM" \
-F "format=cyclonedx-json" \
-F "sha256_digest=$DIGEST" \
-F "artifact_name=${GITHUB_REPOSITORY#*/}-cyclonedx" \
-F "artifact_version=$GITHUB_SHA" \
-F "source_repo=$GITHUB_REPOSITORY" \
-F "repo_full_name=$GITHUB_REPOSITORY" \
-F "commit_sha=$GITHUB_SHA" \
-F "git_ref=$GITHUB_REF" \
"$GITHUB_SERVER_URL/_app/api/v1/orgs/$GITHUB_REPOSITORY_OWNER/sboms"Maven, avec le cyclonedx-maven-plugin. Rien ne doit changer dans votre pom.xml :
name: sbom
on:
push:
branches: [main]
jobs:
sbom:
runs-on: fremforge
env:
SBOM: target/bom.json
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: CycloneDX SBOM with the full dependency graph
run: mvn -B -q org.cyclonedx:cyclonedx-maven-plugin:2.9.1:makeBom -DoutputFormat=json -DoutputName=bom -DschemaVersion=1.6
# then the push step abovePour un build multimodule, utilisez plutôt l’objectif makeAggregateBom ; son SBOM est le target/bom.json du projet de premier niveau.
Gradle, avec le plugin CycloneDX pour Gradle. Ajoutez le plugin à build.gradle :
plugins {
id 'org.cyclonedx.bom' version '3.5.1'
}et générez le SBOM dans le job, avec SBOM: build/reports/cyclonedx-direct/bom.json :
- name: CycloneDX SBOM with the full dependency graph
run: gradle cyclonedxDirectBomGo, avec cyclonedx-gomod. fremforge trouve déjà seul les chemins pour Go (voir le tableau ci-dessus). Poussez depuis la CI lorsque fremforge ne peut pas récupérer vos modules, par exemple des modules privés que son cache de modules Go ne peut pas atteindre, avec SBOM: bom.json :
- uses: actions/setup-go@v5
with:
go-version: '1.27'
- name: CycloneDX SBOM with the module graph
run: |
go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@v1.9.0
"$(go env GOPATH)/bin/cyclonedx-gomod" mod -json -output "$SBOM" .Le SBOM poussé est aussi indexé comme un artefact envoyé à part entière, si bien que ses composants apparaissent dans l’inventaire sous son artifact_name en plus du dépôt. Une analyse des dépendances d’un fichier de build Gradle ne voit que les dépendances que le fichier déclare, et celle d’un pom.xml voit ce vers quoi ses poms se résolvent, pas ce qu’un plugin modifie. Chaque composant Maven d’un graphe poussé, y compris les composants transitifs, est donc confronté à la même base d’avis de sécurité que les analyses, et chaque correspondance est un résultat de dépendance du dépôt nommé dans source_repo. Ces résultats ont le manifeste sbom:<artifact_name>. Ils apparaissent dans Vulnérables en service avec leur chemin, dans les résultats de dépendances des pages Sécurité et dans l’API des résultats, et ils se rejettent comme tout autre résultat. Ils sont recalculés lorsque le SBOM est poussé, après chaque analyse de la branche par défaut du dépôt et après chaque actualisation de la base d’avis, si bien qu’un nouvel avis ajoute un résultat et qu’un avis retiré le supprime. Un avis que l’analyse propre au dépôt signale déjà n’est pas listé deux fois. Ce sont des résultats de branche par défaut : un SBOM poussé ne change pas le statut fremforge/dep-scan d’une pull request. Un graphe NuGet poussé de cette manière est utilisé tel quel, sauf s’il a été écrit par une version de syft antérieure à 1.54.1.
Classes d’environnement
Chaque utilisation peut porter une classe d’environnement : sandbox, development, test, staging ou production. Elle provient de l’une de trois sources, et la première qui s’applique l’emporte :
deployment: un déploiement que votre CI/CD a signalé avecPOST /orgs/{slug}/repos/{repo}/deployments, dont le dernier statut estsuccess, nomme le condensé d’image, le commit, l’étiquette de version ou la version de paquet de l’utilisation. Lorsque plusieurs le font, la classe la plus élevée l’emporte. La ligne d’utilisation portedeployment_idetdeployment_environment. Voir la référence de l’API.reported: un envoi de SBOM a fourni son propreenvironment.rule: la première règle correspondante sous Règles d’environnement, qui porte sur le type d’utilisation, un dépôt, une étiquette, une image ou un nom d’artefact.
La classe sert à la recherche et aux rapports ; elle ne change ni la conservation ni aucun contrôle.
Déploiements
L’onglet Déploiements liste les déploiements que votre CI/CD a signalés, du plus récent au plus ancien : le dépôt, le nom de l’environnement et sa classe, l’état (un déploiement dont le dernier statut est success est marqué comme actuellement déployé), le commit ou la référence, les condensés d’images et les versions de paquets qu’il nomme, et qui l’a signalé (un job CI avec son exécution, un robot de registre, un utilisateur ou un jeton d’API). Filtrez par dépôt, nom d’environnement, classe d’environnement et état, ou cochez Déployés actuellement uniquement. Page suivante et Première page permettent de parcourir la liste. La même liste est disponible dans l’API à GET /orgs/{slug}/deployments/reported (portée components:read), et chaque export de données la contient sous metadata/deployments.ndjson avec l’historique des statuts de chaque déploiement, voir Schéma d’export.
Voir aussi
- SBOM : d’où viennent les SBOM.
- Rapport de conformité : sa section « composants les plus risqués » lit l’inventaire.
- Versions de paquets téléchargées : quelles versions vulnérables vos consommateurs téléchargent réellement, à
GET /orgs/{slug}/components/pulled.