Aller au contenu principal

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ôtle SBOM de la tête de sa branche par défaut
Une version publiéela version la plus récente du dépôt
Une image de conteneurchaque condensé d’image encore publié dans votre registre
Un paquet du registrechaque 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ètreCorrespond à
qle nom du composant, exact ou par préfixe ; une valeur commençant par pkg: correspond à la package URL
purlune package URL ; sans version, elle correspond à toutes les versions
rangeune plage de versions purl-spec, telle que vers:npm/>=4.17.0|<4.17.21 ; nécessite purl sans version
ecosystem, versionl’écosystème, et une version exacte
licenceun identifiant SPDX dans l’expression de licence, ou unknown
environmentsandbox, development, test, staging, production ou unclassified
environment_sourcel’origine de la classe : deployment, reported ou rule
subject_kindrepo, release, image, package ou artifact
subjectle nom du dépôt, de l’image, du paquet ou de l’artefact
currenttrue (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 terminaisonRenvoie
GET /orgs/{slug}/componentsles 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}/usagesoù ce composant est utilisé
GET /orgs/{slug}/components/vulnerableles composants vulnérables en service, joints aux résultats ouverts ; min_severity=low|medium|high|critical
GET /orgs/{slug}/components/vulnerable/summaryle nombre de composants et d’utilisations vulnérables, par sévérité et par environnement
GET /orgs/{slug}/repos/{repo}/dependencies/pathsquelles dépendances directes introduisent un composant dans le dépôt, voir Chemins de dépendances
GET /orgs/{slug}/components/environment-rulesvos règles et libellés d’environnement
PUT /orgs/{slug}/components/environment-rulesremplace 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èmeFichierChemins
npmpackage-lock.json, pnpm-lock.yaml, yarn.lockoui
PyPIuv.lock, poetry.lockoui
CargoCargo.lockoui
Gogo.modoui : fremforge lit le go.mod de chaque module depuis son cache de modules Go, sans exécuter aucun code de votre dépôt
Mavenpom.xmlnon : 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
Gradlenon : poussez un SBOM CycloneDX depuis la CI, voir ci-dessous
NuGetpackages.lock.jsonoui, 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.locknon : 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 above

Pour 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 cyclonedxDirectBom

Go, 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 :

  1. deployment : un déploiement que votre CI/CD a signalé avec POST /orgs/{slug}/repos/{repo}/deployments, dont le dernier statut est success, 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 porte deployment_id et deployment_environment. Voir la référence de l’API.
  2. reported : un envoi de SBOM a fourni son propre environment.
  3. 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