Naar de hoofdinhoud

SBOM’s (Software Bill of Materials)

Een SBOM (Software Bill of Materials) is de ingrediëntenlijst per build: elke directe en transitieve afhankelijkheid die in een artefact is ingebouwd, met versies en hashes. fremforge bewaart de SBOM’s die je CI produceert, zodat de inventaris bewaard blijft over builds, imagerotaties en verschuivende afhankelijkheden heen.

Wanneer SBOM’s automatisch worden gegenereerd

Er hoeft niets geïnstalleerd te worden. fremforge genereert centraal een CycloneDX 1.6-SBOM voor elke pull request, op zijn eigen runners, en koppelt die SBOM aan een release als je er een publiceert: elke tag, inclusief de gangbare semver- en calver-vormen (v1.2.3, v2026.06).

We scannen bij een release bewust niet opnieuw. Een SBOM is een functie van de broncode, en de boom die je uitbrengt is al gescand als de laatste commit van de pull request die hem heeft samengevoegd, dus een tweede SBOM genereren zou een byte-voor-byte identiek bestand opleveren. Het publiceren van een release markeert in plaats daarvan de SBOM die al voor precies die commit bestaat als de release-SBOM. Twee gevolgen die goed zijn om te weten:

  • Het gaat direct. Er draait geen build, dus de release-SBOM is beschikbaar zodra de release is gepubliceerd.
  • De koppeling gebeurt aan de serverkant. fremforge zoekt via Forgejo de commit bij je tag op en matcht op die commit, dus niets in een build kan aanspraak maken op een release-SBOM die het niet heeft verdiend.

Publiceer je een release voor een commit die nooit door een pull request is gegaan (een tag op een heel oude commit, of een repository waarvan de geschiedenis van vóór het scannen is), dan is er geen SBOM om te koppelen. Die release wordt dan als niet gedekt gemeld in plaats van stilzwijgend overgeslagen; voer een scan opnieuw uit op de commit om hem te dekken.

Een SBOM starten door een release te taggen

Vanaf de opdrachtregel:

git tag v1.2.3
git push origin v1.2.3

Vanuit de Forgejo-UI: open de repository → Publicaties → Nieuwe release, stel een tagnaam in die met v begint (bijvoorbeeld v1.2.3) en klik op Release publiceren.

Een eenmalige SBOM voor een willekeurige commit is ook beschikbaar via het tabblad Actions → SBOM (Syft) → Run workflow.

Waarom wordt alleen een release gekoppeld? Voor elke pull request wordt een SBOM gemaakt, maar alleen die van een gepubliceerde commit wordt een release-SBOM: auditors willen de SBOM “op het moment dat we release X uitbrachten”. Koppelen bij een release houdt het aantal release-SBOM’s in verhouding tot je werkelijke releaseritme.

Wat fremforge accepteert

fremforge genereert zowel CycloneDX 1.6- als SPDX 2.3-SBOM’s, en accepteert beide bij het inlezen:

  • CycloneDX JSON (1.6): de inventaris die elke functie van fremforge leest (koppeling aan releases, de controle op een lege inventaris, het overzicht). Het bredere ecosysteem van tools (Trivy, Syft, anchore) levert CycloneDX standaard.
  • SPDX JSON (2.3): bij elke PR-scan door dezelfde Syft-run ernaast gegenereerd en onder dezelfde build opgeslagen, zodat de SBOM-pagina voor één release beide downloads aanbiedt. Je eigen uploads mogen CycloneDX 1.5–1.7 of SPDX 2.x/3.x zijn; het inlezen controleert specVersion / spdxVersion voordat er iets wordt opgeslagen.

Het SPDX-document is een exportformaat dat naar beste vermogen wordt gegenereerd: voor een heel grote repository waarvan de twee documenten samen de leveringslimiet van 14 MiB zouden overschrijden, wordt alleen de CycloneDX-SBOM opgeslagen, zodat de inventaris nooit verloren gaat om plaats te maken voor het tweede formaat.

Elke SBOM wordt opgeslagen met:

  • De SHA-256-digest van het SBOM-bestand. De uploader stuurt hem mee en de server berekent hem opnieuw, zodat een afgekapte of gewijzigde upload wordt geweigerd.
  • Een optionele in-toto-attestatiebundel (JSONL), met Cosign ondertekend als je workflow de SBOM ondertekent. Het inlezen controleert de JSONL-vorm en de in-toto-velden per regel voordat er iets wordt opgeslagen.
  • De naam en versie van het artefact, precies zoals je workflow ze noemt. Gebruikt voor de deduplicatiesleutel (dezelfde digest + naam + versie = één rij, niet meerdere).

Harde limiet van 5 MiB per SBOM. Daarboven geeft het endpoint voor inlezen 413 payload-too-large; splits grote SBOM’s van monorepo’s per module als je daartegenaan loopt.

Een SBOM vanuit CI pushen

Het runnerimage van fremforge bevat Syft en Trivy, dus voor de meeste workflows volstaat een kort fragment:

- 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"

Het PAT heeft de scope sboms:write nodig; maak er een aan onder Organisatiebeheer → API-tokens met de scope voor het pushen van SBOM’s aangevinkt.

Twee optionele velden leggen vast waar het artefact draait en uit welke repository het is gebouwd:

  • environment: de omgevingsklasse waarin het artefact draait, een van sandbox, development, test of production. Al het andere wordt geweigerd met invalid-environment.
  • source_repo: de repository waaruit het artefact is gebouwd, als owner/repo. Al het andere wordt geweigerd met invalid-source-repo.
      -F "environment=production" \
      -F "source_repo=acme/payments-api" \

Geen van beide velden verandert de bewaartermijn of een gate. Een CycloneDX-SBOM met source_repo levert ook zijn afhankelijkheidsgraaf aan de afhankelijkheidspaden van die repository; zo krijgen Maven- en Gradle-repository’s ze.

Waar SBOM’s in de beheer-UI verschijnen

Beheer → Beveiliging › Componenten › SBOM’s toont elke ingelezen SBOM, gegroepeerd per artefact. Elke rij toont:

  • Naam en versie van het artefact + SHA-256-digest
  • Formaat (CycloneDX / SPDX) + grootte
  • Tijdstip van inlezen + de gebruiker of het PAT dat hem pushte
  • Een link “Verify signature” als er een attestatie aan hangt

Hoe SBOM’s samenwerken met andere beveiligingssignalen

  • Scorecard: bepaalt de scores voor Dependencies en Vulnerabilities in de berekening van de OpenSSF Scorecard.
  • OSV-aanbevelingen: als een OSV-advisory matcht met een component uit een SBOM, verschijnt de aanbeveling met de impact verankerd aan die SBOM (“dit raakt build myapp@v1.2.3 van 2026-05-12”).
  • Cosign: het ondertekenen van SBOM’s gebruikt dezelfde Cosign-vertrouwensbasis als het ondertekenen van images. Zie Cosign voor de verificatie.

Bewaring

Release-SBOM’s worden bewaard zolang je organisatie bestaat. SBOM’s van builds die niet zijn uitgebracht, worden verwijderd na je bewaartermijn voor sbom: standaard 14 dagen, 0 tot 3650 dagen. De SBOM van de laatste commit op de standaardbranch, de SBOM’s van huidige images en de SBOM’s van pakketbestanden blijven bewaard, ongeacht hun leeftijd. Zolang er een juridische bewaarplicht geldt, wordt niets verwijderd. (Tot 2026-10-08 stond in deze sectie dat SBOM’s de voorinstellingen voor het bewaren van het auditlog volgden; dat hebben ze nooit gedaan.)

Zie ook

  • Cosign: ondertekenen van images en SBOM’s.
  • OSV-aanbevelingen: kwetsbaarheden gematcht met componenten uit SBOM’s.
  • Scorecard: SBOM’s bepalen de scores voor afhankelijkheden en kwetsbaarheden.
  • API-referentie: het endpoint voor inlezen POST /_app/api/v1/orgs/{slug}/sboms.