Naar de hoofdinhoud

Beveiliging en supply chain

fremforge levert een gelaagde supply-chain-beveiliging die in elk abonnement per gebruiker is inbegrepen. De maatregelen werken op vier knelpunten: de push (secret-scanning), de PR (scannen van afhankelijkheden, SAST), het artefact (scannen van containers, SBOM, SLSA-provenance) en de commit (ondertekenen met een SSH-sleutel of GPG).

Voor de contractuele positie (BSI C5, ISO 27001/27017/27018, TISAX, AVG, de analyse van Schrems II en de CLOUD Act), zie frem.sh/trust.

Waar bevindingen staan

Beveiliging › Bevindingen opent op Alle: elke openstaande bevinding van elke scanner in één lijst, de belangrijkste eerst (bekend misbruikt, dan ernst, dan de oudste). Filter op type en ernst; elke chip toont hoeveel bevindingen hij zou tonen. Een rij linkt naar de bevinding op haar eigen tabblad (SAST, Secrets, Afhankelijkheden, Containerimages, Licenties, Malware), waar haar details en acties staan. Dezelfde lijst staat in de API als GET /orgs/{org}/security/findings; zie Findings-API.

Secret-scanning (push-bescherming)

Gitleaks draait als pre-receive-hook bij elke push, voordat de commit in de repository wordt opgenomen, vanaf de allereerste push naar een nieuwe repository. Push-bescherming staat altijd aan: geen organisatie of repository kan de scan uitzetten. De enige instelling is de Faalmodus van de scanner onder Beveiliging › Beleid › Push-bescherming: als de scanner zelf niet beschikbaar is, wordt een push ofwel geweigerd (de standaard) ofwel doorgelaten en in het auditspoor vastgelegd als een allow-on-error-gebeurtenis; secrets die in dat venster doorglippen, worden later gevonden door de wekelijkse scan van de geschiedenis. Zie Push-bescherming.

Wat wordt tegengehouden

Gitleaks herkent meer dan 120 patronen met hoge betrouwbaarheid, waaronder:

CategorieVoorbeeldpatronen
Inloggegevens van cloudprovidersAWS access/secret keys, JSON van GCP-serviceaccounts, connection strings van Azure Storage
Tokens voor broncodebeheerPAT’s van GitHub en GitLab, app-wachtwoorden van Bitbucket
BetaalsleutelsSecret keys van Stripe, signing secrets van Stripe-webhooks
CommunicatietokensBottokens van Slack, webhook-URL’s van Slack, auth tokens van Twilio
PrivésleutelsPrivésleutels voor RSA/EC/Ed25519, PEM-gecodeerde certificaten
Algemene secretsStrings met hoge entropie die passen op het patroon generic-api-key, signing secrets voor JWT
Database-URL’sConnection strings voor PostgreSQL, MySQL, MongoDB en Redis met ingebedde inloggegevens

Als een push wordt tegengehouden

De push wordt op de remote geweigerd met een foutmelding die het type van het gevonden patroon en het bestand en regelnummer bevat. De commit wordt niet geaccepteerd.

Verwijder niet gewoon het bestand om daarna opnieuw te committen. Het secret staat in de git-geschiedenis en wordt opnieuw tegengehouden. De juiste aanpak:

  1. Roteer het secret onmiddellijk bij de dienst die het heeft uitgegeven (AWS IAM, het Stripe-dashboard enzovoort). Ga ervan uit dat het gecompromitteerd is.
  2. Herschrijf de geschiedenis om het secret uit elke betrokken commit te verwijderen:
# Install git-filter-repo (https://github.com/newren/git-filter-repo)
pip install git-filter-repo

# Create a replacements file
echo '<secret-value>==>REDACTED' > replacements.txt

# Rewrite history
git filter-repo --replace-text replacements.txt

# Force-push the cleaned branch
git push --force-with-lease origin <branch>
  1. Breng iedereen op de hoogte die de repository vóór het herschrijven gekloond kan hebben.

Uitzonderingen toevoegen

Is een tegengehouden secret bewust aanwezig (een token voor interne tooling, een gepubliceerd testgegeven), dan kan een eigenaar van de organisatie een afgebakende uitzondering toevoegen:

  1. Ga naar Beveiliging › Beleid › Push-bescherming › Actieve uitzonderingen → Nieuwe uitzondering.
  2. Geef op: Repository (of kies “All repos”), secretpatroon (uit de regel-ID van Gitleaks) en motivering (vrije tekst, vastgelegd in het auditspoor).
  3. Sla op. De uitzondering geldt vanaf de volgende push.

Alle uitzonderingen zijn zichtbaar voor de andere eigenaren van de organisatie en staan in het auditlog met de uitvoerder, het tijdstip en de motivering. Uitzonderingen kun je op elk moment op dezelfde pagina intrekken.

Een uitzondering op een geweigerde push

Wordt een push door de secret-scanning geweigerd, dan ziet de ontwikkelaar in de terminaluitvoer de reden van de weigering, het type van het gevonden patroon, het bestandspad en het regelnummer.

Een eigenaar van de organisatie kan een uitzondering goedkeuren onder Beveiliging › Beleid › Push-bescherming › Recente weigeringen. Elke weigering toont: de repository, de committer, het tijdstip, het gevonden type secret en het betrokken bestandspad.

Bereik van de uitzondering (te kiezen bij het goedkeuren):

  • Alleen deze commit: keurt de specifieke commit-SHA goed. Hetzelfde secret in een latere commit wordt opnieuw geweigerd.
  • Dit bestandspad: keurt het secret op dat pad goed in elke latere commit. Gebruik dit voor testfixtures of bewust niet-gevoelige placeholders.
  • Deze repository: keurt elk voorkomen van dit type secret in de repository goed. Gebruik dit spaarzaam.
  • Hele organisatie: keurt het type secret in alle repository’s goed. Alleen voor vastgestelde valse positieven (bijvoorbeeld een eigen tokenformaat dat op een regelpatroon lijkt maar geen echt secret is).

Een reden is verplicht (vrije tekst). Die wordt in het auditlog geschreven.

De ontwikkelaar moet opnieuw pushen nadat de uitzondering is verleend. De uitzondering accepteert de geweigerde push niet alsnog met terugwerkende kracht.

Eigen allowlist

Om bekende valse positieven in een bepaalde repository stil te zetten (testfixtures, voorbeeldsleutels in documentatie, bewust openbare inloggegevens), voeg je een .gitleaks.toml toe in de root van de repository:

[extend]
useDefault = true

[[allowlists]]
description = "Test fixture AWS keys"
paths = ["tests/fixtures/.*", "docs/examples/.*"]

[[allowlists]]
description = "Example key in README"
regexes = ["AKIAIOSFODNN7EXAMPLE"]

De allowlist wordt per repository geëvalueerd tijdens de pre-receive-hook. Hij heft de push-bescherming van de organisatie niet op voor patronen die niet in de allowlist staan.

Controles op pull requests: alleen nieuwe bevindingen blokkeren

De controles voor afhankelijkheden (fremforge/dep-scan), SAST (fremforge/sast), licenties (fremforge/license-scan), secrets (fremforge/secret-scan) en images (fremforge/image-scan) scannen de hele repository, maar laten een pull request alleen falen op bevindingen die de pull request zelf introduceert. Een bevinding die de doelbranch al heeft, blokkeert niet, dus een pull request die niets kwetsbaars verandert, kan worden samengevoegd in een repository met openstaande bevindingen. De status luidt dan bijvoorbeeld No new findings at or above critical; 8 already on main.

fremforge vergelijkt de bevindingen van de pull request met de laatste scan van die branch door dezelfde scanner. Een bevinding is dezelfde als:

ControleDezelfde bevinding als
Afhankelijkhedenhet ecosysteem, het pakket en de advisory overeenkomen. Een pakket ophogen naar een versie die nog dezelfde advisory heeft, is niet nieuw; een nieuwe advisory wel
SASTde regel, het bestand en de gevonden code overeenkomen. Een bevinding die alleen naar een andere regel is verschoven, is niet nieuw
Licentieshet ecosysteem, het pakket en de licentie overeenkomen
Secretsde regel en de gevonden regels overeenkomen, vergeleken via een keyed hash die de scanner berekent. Het secret zelf wordt nooit opgeslagen of verstuurd. Een secret dat alleen naar een andere regel is verschoven, is niet nieuw
Imagesde advisory, het pakket en het bestand overeenkomen
  • Kopieën tellen: een tweede voorkomen van een bevinding die de branch één keer heeft, is nieuw.
  • Alles wat nu al bepaalt of een bevinding blokkeert, geldt eerst: de blokkeerernst, afwijzingen, uitzonderingen en het licentiebeleid. Een nieuw kwaadaardig pakket of een nieuwe bekend misbruikte kwetsbaarheid blokkeert altijd, ook als je organisatie heeft gekozen dat onbereikbare bevindingen niet blokkeren.
  • Bestaande bevindingen worden niet verborgen. Ze staan in het commentaar op de pull request en onder Beveiliging › Bevindingen, tellen mee voor je SLA en geven meldingen zoals voorheen.

De branch wordt gescand na een push naar je standaardbranch, hoogstens één keer per uur, waarbij de nieuwste push wint. Een bevinding die sinds de laatste scan op de branch is beland, telt daarom tot de volgende scan nog als bevinding van de pull request; een nieuwe bevinding wordt nooit voor een bestaande aangezien. Is er nog geen scan van de branch, dan blokkeert elke bevinding, zoals voorheen, en vraagt de scan van de pull request er een aan. Zodra de eerste scan van de branch is vastgelegd, scant fremforge uit zichzelf opnieuw de openstaande pull requests naar die branch waarvan de controle intussen faalde (hoogstens 20 per repository, de meest recent bijgewerkte, per controle), zodat ze groen worden, of alleen rood blijven op wat ze toevoegen, zonder nieuwe run of nieuwe push. Een pull request naar een andere branch dan je standaardbranch telt altijd elke bevinding.

Scannen van afhankelijkheden

osv-scanner controleert elke pull request, en de standaardbranch na elke push, tegen de OSV-advisorydatabase. Hij leest lockbestanden en manifesten offline, zonder afhankelijkheden op te lossen, en plaatst de commitstatus fremforge/dep-scan en een commentaar op de pull request. Bevindingen staan onder Beveiliging › Bevindingen › Afhankelijkheden.

Instellingen en wat een merge blokkeert

Onder Beveiliging › Bevindingen › Afhankelijkheden kan een eigenaar het scannen van afhankelijkheden voor de organisatie uitzetten en de blokkeerernst instellen: de laagste ernst waarop fremforge/dep-scan faalt. De standaard is critical. Op een pull request blokkeren alleen de bevindingen die de pull request introduceert. Of een falende controle de merge echt blokkeert, hangt af van de modus van de controle (afdwingen, audit of uit) onder Beveiliging › Prioriteren › Pull request-controles, en van de vraag of branchbescherming de controle vereist.

Om te voorkomen dat een bevinding blokkeert, los je haar op of leg je een uitzondering vast. Een organisatie kan ook kiezen dat bevindingen die niet bereikbaar zijn niet blokkeren. Die keuze geldt nooit voor kwaadaardige pakketten of bekend misbruikte kwetsbaarheden.

Fix-pull requests

Twee dingen openen fix-pull requests voor kwetsbare afhankelijkheden:

  • Beveiligingsfixes: Fix-PR openen op een bevinding (of het automatische beleid) opent per pakket één pull request naar de laagste versie die elke openstaande advisory oplost. Zie Beveiligingsfixes.
  • Updates van afhankelijkheden: de eigen kwetsbaarheidsmeldingen van Renovate, voor organisaties die zijn ingeschreven bij Updates van afhankelijkheden. De repository’s van elke ingeschreven organisatie worden elke nacht verwerkt, en Nu uitvoeren start buiten de cyclus een run.

Ondersteunde manifesten

Welke lockbestanden en manifesten worden gelezen, en welke ecosystemen fix-pull requests en bereikbaarheid krijgen, staat op één plek: Ondersteunde ecosystemen.

Scannen van containerimages

Trivy scant elk OCI-image dat naar het pakketregister van fremforge wordt gepusht. De resultaten staan onder Beveiliging › Bevindingen › Containerimages.

Trivy draait centraal, zonder dat je iets hoeft te installeren: trivy fs op elke pull request (de status fremforge/image-scan, die alleen blokkeert op bevindingen die de pull request introduceert), trivy config als eigen controle (fremforge/iac-scan), en trivy image op elk image in je register en elk image dat via de dependency proxy wordt opgehaald, en dat regelmatig opnieuw wordt gescand. Bevindingen over misconfiguratie uit trivy config hebben een eigen tabblad, Beveiliging › Bevindingen › IaC; zie IaC-scanning.

Elke bevinding bevat:

VeldBeschrijving
CVE-IDbijvoorbeeld CVE-2024-12345, met een link naar NVD
ErnstCRITICAL / HIGH / MEDIUM / LOW / UNKNOWN
Getroffen pakketPakketnaam en geïnstalleerde versie
FixversieEerste versie die de CVE oplost, indien beschikbaar
EPSS-scoreKans volgens het Exploit Prediction Scoring System

Scannen in je eigen workflow (optioneel)

Er is niets in te schakelen: de scans hierboven draaien zonder workflowbestand. Wil je daarnaast dat je eigen build faalt voordat hij een image pusht, dan kun je Trivy zelf in een workflow draaien, bijvoorbeeld:

name: Image scan
on:
  push:
    branches: [main]
  pull_request:

jobs:
  trivy:
    runs-on: fremforge
    steps:
      - uses: actions/checkout@<full-40-char-sha>   # pin by SHA, never a tag or branch
      - name: Build image
        run: docker build -t ${{ github.repository }}:${{ github.sha }} .
      - name: Scan image
        run: |
          docker run --rm \
            -v /var/run/docker.sock:/var/run/docker.sock \
            aquasec/trivy:0.74.0@sha256:<digest> \
            image --exit-code 1 --severity HIGH,CRITICAL \
            ${{ github.repository }}:${{ github.sha }}

Stel --severity in op de drempel waarop de build moet falen.

Waarom dit voorbeeld op SHA en op digest vastpint

Een eerdere versie van deze pagina gebruikte aquasecurity/trivy-action@master en actions/checkout@v4. Beide zijn veranderlijke verwijzingen, en op 19 maart 2026 bleef dat onderscheid niet langer theoretisch: een aanvaller herschreef de tag v0.69.4 van trivy-action zodat die naar een kwaadaardige release wees. Pipelines die de action via een tag of branch aanriepen, haalden bij hun volgende run de code van de aanvaller op, en de inloggegevens die daarmee werden buitgemaakt, zijn gebruikt om twee releases met een achterdeur van een ander project op PyPI te publiceren.

Een tag is een verwijzing die iemand anders kan verplaatsen. Een commit-SHA en een image-digest niet.

  • Actions: verwijs naar de volledige commit-SHA van 40 tekens, niet naar @v4 en nooit naar @master. Renovate stelt nog steeds upgrades voor; het herschrijft de SHA en het bijbehorende commentaar samen.
  • Scanners: kies liever het containerimage van de tool, vastgepind op digest, dan een wrapper-action. Minder bewegende delen, en wat je vastpint, is wat er draait.
  • Spiegel waar je van afhankelijk bent: fremforge benadert vanuit een productiepad geen enkel upstream-register; elk image komt uit ons eigen register, vastgepind op digest.

Dat incident vereiste aan de kant van fremforge geen actie: we hebben trivy-action nooit gebruikt, en onze eigen Trivy is een op digest vastgepind image. Het project dat werd gecompromitteerd, installeerde Trivy via apt zonder vastgepinde versie. Vastpinnen is weinig spectaculair, en het is precies de maatregel die het had tegengehouden.

SBOM-generatie

Syft genereert CycloneDX 1.6-SBOM’s voor elk containerimage dat naar het register wordt gepusht en voor elke releasetag, met een SPDX 2.3-tweeling uit dezelfde run (best effort; zie SBOM’s). Uploads worden geaccepteerd als CycloneDX 1.5–1.7 of SPDX 2.x/3.x. SBOM-generatie staat standaard aan voor elke organisatie; er is niets in te schakelen.

Downloaden

Vanuit de interface van het pakketregister: open het image → tabblad Attestations → Download SBOM.

Via de API:

curl -H "Authorization: token <your-pat>" \
  https://frem.sh/_app/api/v1/orgs/<org>/findings/attestations \
  -o sbom.json

De SBOM is CycloneDX-JSON en bevat alle transitieve afhankelijkheden met hun PURL-identifiers, licentie-expressies en versiebereiken.

SAST

OpenGrep voert centraal statische analyse uit op elke pull request en op de standaardbranch. Het staat standaard aan voor elke organisatie. Bevindingen plaatsen een status fremforge/sast en een commentaar op de pull request, en staan onder Beveiliging › Bevindingen › SAST. Talen, regels en instellingen staan op de pagina SAST. Eigen regels worden niet ondersteund.

Ondertekende commits

fremforge ondersteunt twee manieren om commits te ondertekenen, en Forgejo verifieert ze allebei zelf met de badge “Verified” in de webinterface:

  • Ondertekenen met een SSH-sleutel (aanbevolen standaard): hergebruikt de SSH-sleutel die je al hebt geregistreerd voor git push. Geen nieuw sleutelmateriaal om te beheren, geen subverwerker van derden, geen afhankelijkheid van een transparantielog, geen doorvoer via Amerikaanse jurisdictie. Dit is de standaardroute van fremforge. (Voor nieuwe organisaties die na 2026-05-22 zijn aangemaakt, staat SSH-transport standaard uit; ondertekenen met een SSH-sleutel werkt toch, of je nu SSH of HTTPS gebruikt voor git push.)
  • Ondertekenen met GPG: een klassieke OpenPGP-sleutel. Gebruik dit als je organisatie al een beleid voor GPG-sleutelbeheer heeft (smartcard, HSM, centrale keyserver).

Keyless ondertekenen van commits IS beschikbaar bij fremforge via een zelf gehoste Sigstore-stack: een Fulcio-CA op sign.frem.sh en een TSA op tsa.frem.sh, die allebei op T Cloud Public in eu-de draaien, met de root-CA in DEW KMS. De publieke Sigstore-instantie van de Linux Foundation wordt NIET gebruikt: fremforge stuurt geen onderteken- of verificatieverkeer via sigstore.dev / rekor.sigstore.dev, dus de positie zonder Amerikaanse subverwerkers blijft overeind. Er is bewust geen Rekor of transparantielog voor het ondertekenen van commits; tijdstempels verankerd via de TSA zijn in plaats daarvan het integriteitsmechanisme. (fremforge heeft wel een transparantielog, op log.frem.sh, maar dat dekt alleen attestaties van build-provenance en is geen Rekor; zie transparantielog. De twee staan los van elkaar: een ondertekende commit wordt er niet in opgenomen.) Zie keyless ondertekenen van commits voor het instellen van gitsign aan jouw kant. (Let op: build- en release-provenance is een aparte route. De SLSA-provenance van fremforge wordt ondertekend met een Ed25519-sleutel van het platform, NIET via Fulcio. Zie de SLSA-sectie hieronder.)

Ondertekenen met een SSH-sleutel instellen

# Tell Git to use SSH for signing (Git ≥ 2.34)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true

# (Optional) point Git at your local allowedSignersFile for verify
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers

Voeg de bijbehorende SSH-sleutel toe aan je fremforge-gebruikersprofiel onder Instellingen → SSH / GPG sleutels → Sleutel toevoegen (Forgejo accepteert dezelfde sleutel voor zowel pushen als ondertekenen, of een aparte sleutel alleen voor ondertekenen).

Bij de volgende git commit ondertekent Git met je SSH-sleutel. Forgejo verifieert de handtekening tegen de allowedSignersFile van de organisatie (automatisch afgeleid van de geregistreerde ondertekensleutels van de leden) en toont de badge “Verified” in de webinterface.

Verifiëren

git log --show-signature HEAD~5..HEAD

Elke commit toont een regel Good "git" signature for <user>@<org>. De webinterface van Forgejo toont een groene badge “Verified” naast de commit-hash.

Ondertekenen met GPG instellen

Werk je liever met GPG, dan werkt de standaardaanpak met git config --global commit.gpgsign true + user.signingkey <gpg-key-id> ongewijzigd; upload je publieke sleutel onder Instellingen → SSH / GPG sleutels → Sleutel toevoegen. Forgejo verifieert en toont de badge “Verified”.

Ondertekende commits vereisen (beleid van de organisatie)

Dwing ondertekende commits af op beschermde branches met Commit-ondertekening onder Beveiliging › Beleid › Repositoryregels (zie Branchbescherming), of per repository onder Repository → Instellingen → Branches → <branch> → Ondertekende commits vereisen. Niet-ondertekende commits worden bij het pushen geweigerd. Zowel SSH- als GPG-handtekeningen voldoen aan de eis.

SLSA-provenance

Build- en release-provenance wordt door fremforge aan de serverkant gegenereerd: er staat geen workflowbestand in je repository’s en er worden geen runnerminuten verbruikt. Bij elke Forgejo-gebeurtenis release.published en package berekent de fremforge-api de hash van elk gepubliceerd asset, bouwt een in-toto Statement verpakt in een DSSE-envelop, ondertekent die met de builder-sleutel van het platform, slaat de attestatie op in opslag binnen de EU die tot jouw tenant is beperkt, en uploadt de envelop terug naast het asset als <asset>.intoto.jsonl. Ze staat ook in de console onder Beveiliging › Componenten › Build-attestaties.

De losse workflowtemplate slsa-provenance.yaml die klanten vroeger vanuit hun build-pipelines moesten aanroepen, is op 2026-06-16 uitgefaseerd: een audit over de hele vloot vond geen enkele aanroeper, en provenance wordt nu automatisch aan de serverkant aangemaakt, zonder dat de klant iets hoeft te koppelen.

EU-soeverein door ontwerp. De ondertekensleutels, de trust root, de certificaatautoriteit en de opslag staan allemaal in het T Cloud Public-account van fremforge (eu-de). Er is geen publieke Sigstore, geen Rekor en geen opvraging bij tuf-repo-cdn.sigstore.dev waar dan ook in het verificatiepad.

Twee handtekeningen, allebei op elke attestatie. De primaire is een Ed25519-sleutel die het platform beheert, en dat is de handtekening die het recept Verifiëren hieronder controleert: gewoon curl / jq / openssl / python3, verder niets. Daarnaast wordt elke attestatie keyless ondertekend tegen de zelf gehoste Sigstore van fremforge: een kortlevend Fulcio-certificaat waarvan de SAN de identiteit van de buildbron is, voorzien van een tijdstempel door de RFC3161-TSA van fremforge. Beide staan beschreven in de trust root, die fulcio_root_ca_pem, tsa_cert_chain_pem, certificate_oidc_issuer en certificate_identity_pattern bevat, zodat ook de keyless handtekening offline te verifiëren is.

Er is nog steeds geen transparantielog voor deze handtekening (de trust root vermeldt "transparency_log": "none"), dus de keyless handtekening wordt gevalideerd tegen het RFC3161-tijdstempel in plaats van tegen Rekor (cosign --use-signed-timestamps --insecure-ignore-tlog). Wat dat je wel en niet oplevert, staat in §Onafhankelijke verifieerbaarheid.

(Het ondertekenen van commits bij fremforge is een aparte route op dezelfde zelf gehoste CA; zie keyless ondertekenen van commits.)

Trust root: https://www.frem.sh/.well-known/slsa-trust-root.json, een klein JSON-bestand met de publieke sleutels van de builder. De vorm is specifiek voor fremforge:

{
  "trusted_keys": [
    {
      "kid": "fremforge-slsa-builder-v1",
      "alg": "ed25519",
      "pem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
      "valid_from": "2026-05-17T00:00:00Z",
      "valid_to": "2026-09-12T00:00:00Z",
      "builder_id": "https://frem.sh/runner-controller/v1"
    },
    {
      "kid": "fremforge-slsa-builder-v2",
      "alg": "ed25519",
      "pem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
      "valid_from": "2026-09-12T00:00:00Z",
      "builder_id": "https://frem.sh/runner-controller/v1"
    }
  ]
}

fremforge-slsa-builder-v2 is sinds de sleutelwissel van 2026-09-12 de actieve ondertekensleutel. fremforge-slsa-builder-v1 ondertekende alles daarvóór en blijft alleen voor verificatie behouden: zijn valid_to is het moment waarop hij stopte met ondertekenen, geen vervaldatum voor de handtekeningen die hij heeft gezet. Verifieer altijd tegen de sleutel die de keyid noemt in de envelop die je hebt, nooit tegen een vaste naam.

Pin het bestand (of een kopie ervan) in je CI om het vertrouwen over de verificatieperiode vast te leggen. Sleutelrotaties worden 30 dagen van tevoren aangekondigd volgens de meldingsregel voor subverwerkers op de trustpagina; een handtekening verifieert pas niet meer als haar sleutel uit trusted_keys wordt verwijderd.

Vorm van envelop en statement (DSSE-envelop rond een in-toto Statement):

VeldWaarde
envelop payloadTypeapplication/vnd.in-toto+json
envelop signatures[0].keyidfremforge-slsa-builder-v2 voor alles wat sinds 2026-09-12 is ondertekend, daarvóór fremforge-slsa-builder-v1 (komt overeen met een trusted_keys[].kid in de trust root)
Statement _typehttps://in-toto.io/Statement/v1
Statement predicateTypehttps://slsa.dev/provenance/v1
predicate.buildDefinition.buildTypeWelke route het statement heeft gemaakt; zie §Wat elk buildType betekent. Een van …/buildtypes/forgejo-action-run/v1, …/container-image/v1, …/forgejo-release/v1, …/forgejo-package/v1
predicate.buildDefinition.internalParameters.run_idDe Actions-run die het artefact heeft gemaakt. Aanwezig bij build-provenance; ontbreekt bij een publicatiestatement
predicate.buildDefinition.internalParameters.attestation_kindpublication als het statement gepubliceerde bytes waarneemt in plaats van een build. Ontbreekt bij build-provenance
predicate.buildDefinition.externalParameters.repository<org>/<repo>
predicate.buildDefinition.externalParameters.refDe git-ref (bijvoorbeeld refs/tags/v1.2.3)
predicate.runDetails.builder.idhttps://frem.sh/runner-controller/v1 (door de server bepaald en bij het ondertekenen geforceerd overschreven: een gecompromitteerde runner kan dit niet vervalsen)
subject[].name / subject[].digest.sha256De bestandsnaam van het asset en de SHA-256 die fremforge ervoor heeft berekend

Wat dit precies is. Tot 2026-09-11 claimde deze sectie SLSA Build L2. We hebben dat opnieuw afgeleid tegen de v1.0-specificatie, de claim hield geen stand, en we hebben hem ingetrokken. Het gat dat hem onwaar maakte, provenance die geen build beschreef, is op 2026-09-12 gedicht. We noemen nog steeds geen niveau, om een reden die aan het eind van deze sectie staat.

Er worden nu twee verschillende statements met dezelfde sleutel ondertekend, en je kunt ze alleen al aan de envelop van elkaar onderscheiden.

Wat elk buildType betekent

buildType eindigt opWat het beweertNoemt een build-run?
forgejo-action-run/v1Het control plane van fremforge las de geüploade artefacten van deze run uit de eigen registratie van het buildplatform, haalde de bytes op en berekende hun hashJa: run_id
container-image/v1Een image dat door een run is gepusht, geattesteerd met de run-identiteit uit een kortlevend OIDC-token dat fremforge voor die job heeft aangemaaktJa: run_id, cryptografisch gebonden
forgejo-release/v1Een gepubliceerd release-asset. Erft de commit van een build als dezelfde digest al als gebouwd was geattesteerd; zie hieronderAlleen bij een koppeling
forgejo-package/v1Een pakketversie die in het register verscheenNee

Build-provenance (de eerste twee) beschrijft hoe het artefact is gemaakt: ze noemt de run, de workflow en de commit, en de run-identiteit komt van het platform in plaats van van iets wat de build over zichzelf beweerde.

Publicatie-attestatie (de laatste twee, zonder koppeling) zegt iets beperkters en zegt dat expliciet: attestation_kind: publication. Ze betekent fremforge heeft gezien dat deze byte-exacte inhoud hier is gepubliceerd, en ondertekent die waarneming met een sleutel waar de build niet bij kan. Dat is een echte, controleerbare eigenschap. Het is geen uitspraak over hoe het artefact is gebouwd, en ze doet ook niet meer alsof: als er geen broncommit bekend is, is commit_sha letterlijk no-source-commit in plaats van een waarde die op een git-commit lijkt. Staan daar 40 hexadecimale tekens, dan is het een echte commit.

De koppeling via de digest. Een release-asset waarvan de sha256 al een build-attestatie heeft, erft de commit van die build, en het statement verwijst ernaar (source_commit_from: digest-join, plus de id en de object key van de build-attestatie). De koppeling is de digest van het artefact, dus “dezelfde bytes” is een cryptografisch feit en geen naamgevingsconventie: een artefact later publiceren verandert niets aan wat het heeft gemaakt. Een expliciete target_commitish op de release gaat altijd vóór de afleiding.

De platformeigenschappen achter dit alles:

  • Runs kunnen elkaar niet beïnvloeden. Eén tijdelijke ECS-VM per job, vernietigd zodra de job eindigt, met een ENI per VM en inloggegevens per runner die met de job verdwijnen; zie §Isolatiemodel van de kernel.
  • De ondertekensleutel is buiten bereik van de build. Hij staat in de api, nooit op een runner, en de builder-identiteit wordt bij het ondertekenen aan de serverkant overschreven, dus een gecompromitteerde build kan hem niet vervalsen.
  • Niets te koppelen voor de routes die door webhooks worden aangestuurd. Niets aan te roepen vanuit een workflow, en geen runnerminuten verbruikt.

Waarom we nog steeds geen SLSA-niveau noemen. Die twee isolatie-eigenschappen zijn wat SLSA v1.0 Build L3 vraagt, en build-provenance beschrijft nu een echte build. We hebben liever dat je de tabel hierboven leest en zelf beslist wat die waard is, dan dat je een getal aanneemt van de partij die wordt geaudit. (Hermetische builds, reproduceerbare artefacten en transparantielogs worden soms als eisen voor L3 genoemd. Dat zijn ze niet: dat waren concepten van SLSA v0.1 L4, en ze komen in v1.0 op geen enkel niveau voor; daar staan ze onder toekomstige richtingen.)

Wat nog ontbreekt is een transparantielog, en dat is een andere as dan welk niveau ook; zie §Onafhankelijke verifieerbaarheid.

Verifiëren

Gebruik niet upstream slsa-verifier verify-artifact --trusted-root. Die tool heeft geen vlag --trusted-root op verify-artifact en kan de eigen trust-root-JSON van fremforge of een kale Ed25519-DSSE-envelop niet verwerken: hij verwacht een bundel in Sigstore-stijl. De provenance van fremforge is een gewone DSSE-envelop ondertekend met Ed25519, dus je verifieert hem direct met curl / jq / openssl / python3, allemaal standaard in elke distributie, zonder tooling van fremforge.

De verificatie bestaat uit drie onafhankelijke controles: de DSSE-handtekening is geldig voor de gepubliceerde builder-sleutel, de SHA-256 van het asset komt overeen met wat is ondertekend, en het statement noemt de juiste repository en builder.

1. Haal de trust root op en haal de publieke sleutel van de builder eruit

curl -sSfL https://www.frem.sh/.well-known/slsa-trust-root.json -o trust-root.json
jq -r '.trusted_keys[] | select(.kid=="fremforge-slsa-builder-v2") | .pem' \
  trust-root.json > builder.pub

Voor een attestatie die vóór 2026-09-12 is ondertekend, kies je in plaats daarvan fremforge-slsa-builder-v1. jq -r '.signatures[0].keyid' <asset>.intoto.jsonl vertelt je welke.

2. Verifieer de DSSE-handtekening, de digest van het asset en de velden van het statement

Voer dit uit in een map met het gedownloade asset en de bijbehorende envelop <asset>.intoto.jsonl. Zet ASSET op de bestandsnaam van het asset:

ASSET=myapp python3 - <<'PY'
import base64, json, hashlib, os, subprocess, sys, pathlib

asset = os.environ["ASSET"]
env = json.loads(pathlib.Path(f"{asset}.intoto.jsonl").read_text().strip())

payload_type = env["payloadType"]                 # application/vnd.in-toto+json
payload      = base64.b64decode(env["payload"])

# Reconstruct the DSSE pre-authentication encoding (DSSEv1):
#   "DSSEv1 " + LEN(type) + " " + type + " " + LEN(payload) + " " + payload
# where LEN is the utf-8 byte length and separators are single ASCII spaces.
pae = (
    b"DSSEv1 "
    + str(len(payload_type.encode())).encode() + b" "
    + payload_type.encode() + b" "
    + str(len(payload)).encode() + b" "
    + payload
)
pathlib.Path("pae.bin").write_bytes(pae)
pathlib.Path("sig.bin").write_bytes(base64.b64decode(env["signatures"][0]["sig"]))

# Ed25519 ("pure" EdDSA — no pre-hash) verify with openssl. Feed the raw PAE.
r = subprocess.run(
    ["openssl", "pkeyutl", "-verify", "-pubin", "-inkey", "builder.pub",
     "-rawin", "-in", "pae.bin", "-sigfile", "sig.bin"],
    capture_output=True, text=True,
)
if r.returncode != 0 or "Signature Verified Successfully" not in r.stdout:
    print("DSSE signature FAILED:", r.stdout, r.stderr, file=sys.stderr); sys.exit(1)
print("DSSE signature: OK")

stmt = json.loads(payload)

# The signed subject digest must match the asset bytes on disk.
want = next((s["digest"]["sha256"] for s in stmt["subject"] if s["name"] == asset), None)
got  = hashlib.sha256(pathlib.Path(asset).read_bytes()).hexdigest()
if want is None:
    print(f"asset {asset} not found among signed subjects", file=sys.stderr); sys.exit(1)
if want != got:
    print(f"digest mismatch: signed={want} actual={got}", file=sys.stderr); sys.exit(1)
print(f"asset digest: OK ({got})")

# Sanity-check the builder identity and predicate type.
builder = stmt["predicate"]["runDetails"]["builder"]["id"]
if builder != "https://frem.sh/runner-controller/v1":
    print(f"unexpected builder.id: {builder}", file=sys.stderr); sys.exit(1)
if stmt["predicateType"] != "https://slsa.dev/provenance/v1":
    print(f"unexpected predicateType: {stmt['predicateType']}", file=sys.stderr); sys.exit(1)
print("builder.id + predicateType: OK")
PY

Drukken alle drie de controles OK af, dan is het asset precies de bytes die fremforge heeft geattesteerd, is de envelop ondertekend met de gepubliceerde builder-sleutel en noemt het statement de builder van fremforge. De verificatie faalt (exitcode ongelijk aan nul) als de handtekening niet geldig is tegen builder.pub (gemanipuleerde envelop of verkeerde/geroteerde sleutel), als de SHA-256 van het asset niet overeenkomt met het ondertekende subject (gemanipuleerd asset), of als builder.id / predicateType niet overeenkomen.

De keyid in de envelop (fremforge-slsa-builder-v2 voor alles wat sinds 2026-09-12 is ondertekend) moet overeenkomen met de kid die je uit de trust root hebt gekozen; een envelop die tegen de andere sleutel wordt gecontroleerd, faalt met DSSE signature FAILED. Roteert fremforge de ondertekensleutel, haal dan de trust root opnieuw op en kies de kid die de envelop noemt.

Waarom geen Sigstore bij de lancering

De publieke stack van Sigstore met Fulcio, Rekor en Trillian wordt beheerd door de OpenSSF (Linux Foundation), een in de VS opgerichte organisatie. Die gebruiken zou de metadata van elke build naar in de VS gehoste infrastructuur sturen, wat niet te verenigen is met de toezegging van fremforge om alleen EU-subverwerkers te gebruiken in DPA Annex B. fremforge draait zijn eigen zelf gehoste Fulcio en TSA op sign.frem.sh / tsa.frem.sh op T Cloud Public eu-de, gebruikt voor zowel het ondertekenen van commits (zie keyless ondertekenen van commits) als, sinds 2026-06-21, de tweede handtekening op build-provenance. Wat bewust ontbreekt, is de publieke Sigstore-omgeving en Rekor.

De SHA-256 van elke attestatie wordt ook in de hashketen van het auditlog van het platform opgenomen, waarvan de ankers in een OBS Object Lock in COMPLIANCE-modus van 3 jaar staan. Dat is een nuttige interne maatregel en het is geen vervanging voor een transparantielog, dus we beschrijven het niet langer als gelijkwaardige manipulatiebestendigheid. Twee redenen, allebei concreet: het anker is voor jou niet leesbaar, dus het kan geen deel uitmaken van jouw verificatie; en OBS Object Lock beschermt elke versie van een object. Gemeten op 2026-08-14: een nieuwere versie kan een vergrendelde sleutel overschaduwen en een delete marker verbergt hem voor gewone leesacties, en beide zijn acties die de beheerder kan uitvoeren. Zie §Onafhankelijke verifieerbaarheid voor wat het vertrouwensmodel je wel en niet geeft.

Onveranderlijke releases

Eigenaren van een organisatie kunnen elke release bij publicatie bevriezen: de tag, de doelcommit en de assets kunnen dan nooit meer veranderen (titel en notities blijven bewerkbaar), de tagnaam van een verwijderde release kan nooit opnieuw worden gebruikt, en ook containertags kunnen worden bevroren (tags in de stijl v1.2.3, of alle behalve een lijst). Elke onveranderlijke release krijgt één ondertekend in-toto-releasestatement dat elk asset op SHA-256 en de tag op commit noemt, te controleren met fremforge release verify. Zie Onveranderlijke releases en release-attestatie.

Onafhankelijke verifieerbaarheid

Een repository, een runner en een artefactopslag naar Duitsland verhuizen beantwoordt waar de gegevens staan. Het beantwoordt op zichzelf niet of het auditspoor te vertrouwen is zonder de beheerder te vertrouwen die het heeft gemaakt. Dat zijn verschillende eigenschappen, en we zijn liever expliciet over welke we vandaag leveren.

Wat je krijgt zonder ons te hoeven vertrouwen op het moment van verificatie. De attestatie reist mee met het artefact (<asset>.intoto.jsonl, en daarnaast <asset>.sigstore.json), dus je hebt beide helften in handen. De publieke sleutel van de builder, de Fulcio-root-CA en de TSA-keten staan allemaal in een statische trust root, waarvan we je aanraden een kopie vast te pinnen in je eigen CI. De verificatie berekent de digest van het artefact opnieuw en controleert handtekeningen lokaal, met curl / jq / openssl / python3. Er wordt geen enkele fremforge-API benaderd en er is geen tooling van fremforge nodig. Zodra je de root hebt vastgepind, kan een latere wijziging aan onze kant niet met terugwerkende kracht veranderen wat je pipeline accepteert.

Wat je niet krijgt, ronduit gezegd. Er is nu een append-only transparantielog voor provenance-attestaties op log.frem.sh, maar het geeft je nog niet de eigenschap die mensen meestal met dat woord bedoelen. Concreet:

  • Het log maakt het ons onmogelijk om de geschiedenis stilletjes te herschrijven: heb je een inclusion proof en wijzigen of verwijderen we later je attestatie, dan verifieert je proof niet meer en kun je de tegenstrijdigheid aantonen. Dat is echt, en het is nieuw.
  • Het is sinds 16 september 2026 deels bestand tegen split views. Eén onafhankelijke witness, witness.stagemole.eu, beheerd door Mullvad VPN AB, ondertekent elk checkpoint mee, dus er is nu een derde partij die zou merken dat we iets ongebruikelijks ondertekenen. Om die eigenschap ging dit punt altijd, en ze ontbreekt niet langer. Eén witness is geen quorum: het maakt het duurder om jou een andere boom te laten zien dan iedereen, maar kan samenspanning tussen het log en zijn enige witness niet detecteren, en de beheerder noemt de instantie zelf staging. Let er ook op dat de enige EU-witnesses van productiekwaliteit, Glasklar Teknik, Mullvad VPN en Tillitis, hetzelfde moederbedrijf hebben, Amagicom AB; meer van hen zou beschikbaarheid opleveren, geen onafhankelijkheid.
  • Het RFC3161-tijdstempel dat deels een log vervangt, wordt uitgegeven door onze TSA, en de trust root wordt verspreid vanaf ons domein. Vastpinnen lost het tweede op voor iedereen die bij de onboarding vastpint; het lost het vertrouwen bij het eerste contact niet op.
  • Ons interne anker van de auditketen is voor jou niet leesbaar, dus het kan geen deel uitmaken van jouw verificatie.

Is de beheerder de partij die je ter verantwoording moet kunnen roepen, en dat is de juiste vraag voor defensie en kritieke infrastructuur, dan wordt het gat gedicht door een transparantielog met externe witnesses, een onafhankelijke tijdstempelautoriteit en reproduceerbare builds die je zonder onze betrokkenheid opnieuw kunt bouwen en vergelijken. De eerste van die drie bestaat nu en is hierboven beschreven, met haar beperkingen; de tijdstempelautoriteit en reproduceerbare builds bestaan niet. Let op: een zelf gehost log zou het gat niet dichten: een log dat wij beheren, is een log dat wij controleren. Onafhankelijke verifieerbaarheid vraagt om een externe partij, en de eerlijke afweging is dat het via het publieke Sigstore-log doen digests van artefacten, identiteiten van repository’s en de timing van releases buiten de EU zou publiceren.

Dat stemmen we liever af op een echte eis dan dat we er een raden. Is dit voor jou een voorwaarde bij een aanbesteding, vertel ons dan welke van die eigenschappen je nodig hebt en op welke termijn, en we komen terug met een gedateerd plan in plaats van een bewering.

Isolatiemodel van de kernel

Elke job krijgt een eigen tijdelijke virtuele ECS-machine op T Cloud Public in eu-de, die wordt vernietigd zodra die job klaar is. VM’s zijn single-task: de runner wordt na zijn ene taak verwijderd en zijn inloggegevens per runner verdwijnen met de job, dus een VM kan geen tweede job uitvoeren, ook niet binnen dezelfde workflow-run. (Vóór 2026-07-30 konden opeenvolgende jobs voor één commit een VM delen; dat kan niet meer.) De isolatie-eigenschappen:

EigenschapDetail
Gedeelde kernelEr wordt geen kernel gedeeld tussen commits of tussen organisaties: elke commit krijgt een eigen VM. Jobs van dezelfde commit kunnen die VM delen, dus behandel een pipeline als één vertrouwensdomein
PersistentieDe VM wordt vernietigd zodra de jobs van de commit klaar zijn; er blijft geen bestandssysteemstatus over voor een andere commit of een andere organisatie. Status kan wel tussen jobs van dezelfde commit worden doorgegeven: een buildstap die afhankelijkheidscode van derden uitvoert, deelt de machine met een latere deploystap, dus beperk alle inloggegevens die een deploy nodig heeft tot die pipeline
Toegang tot de platform-APIAan de VM is geen IAM-agency gekoppeld; de identiteit uit de metadata heeft geen rollen, dus de OTC-API is van binnenuit onbereikbaar
NetwerkSecurity Group per VM met een allowlist alleen voor uitgaand verkeer; runners kunnen geen inkomende verbindingen ontvangen
Metadata van T Cloud PublicGeblokkeerd door de SSRF-proxy voor uitgaand verkeer; runnercode kan het metadata-endpoint van de instantie niet met geprivilegieerde scope bereiken

Zie CI-runners voor de volledige isolatiespecificatie en het registreren van eigen runners (BYO).

Isolatie tussen tenants

Elke fremforge-tenant is een aparte namespace met een eigen sleutel in het platform. De isolatieketen loopt van de URL via middleware, de querylaag van de database en de opslaglaag tot aan de auditketen.

LaagMechanismeWat toegang tussen tenants tegenhoudt
URL-routeringMiddleware voor /<slug>/_admin/* laadt de tenant bij elk verzoek opnieuw uit de slugEen gebruiker met een sessie voor organisatie A die de URL van organisatie B plakt, wordt geweigerd bij de lidmaatschapscontrole, niet bij een verouderde cookie
LidmaatschapscontroleOpzoeking in het Owners-team van Forgejo tegen de slug, bij elk verzoek geverifieerdDe api vertrouwt nooit een inkomende bewering over tot welke organisaties de gebruiker behoort
DatabaseElke tabel met een tenant-sleutel heeft een foreign key tenant_id; elke leesactie EN elke schrijfactie filtert daaropSELECT / UPDATE / DELETE zonder tenant_id is structureel onmogelijk in de paden die de audit heeft gemarkeerd
Ondertekende tokensElke kortlevende ondertekende URL (magische link voor facturering, opzegging ongedaan maken, OIDC-state) draagt de tenant-id in de payload; de verificatiekant vergelijkt die met de slug in de URLEen token dat voor tenant A is aangemaakt, wordt geweigerd als het tegen de URL van tenant B wordt hergebruikt
Opslag (OBS)SBOM’s, attestaties en auditlogobjecten hebben allemaal de sleutel <artifact>/<tenant_id>/...; bij het aanmaken van een ondertekende URL wordt tenant.id === row.tenant_id opnieuw gevalideerd vóór uitgifteEen direct vooraf ondertekende OBS-URL die aan tenant A is gebonden, kan niet worden herschreven om tenant B te lezen
AuditketenManipulatiebestendige hashketen per tenant; toevoegingen van de ene tenant wijzigen nooit de kop van de keten van een andereEen breuk in de keten van tenant A (bijvoorbeeld een poging tot verwijderen met terugwerkende kracht) heeft geen invloed op de integriteit van de keten van tenant B
Toegang door de beheerderAls medewerkers (fremverk) klantgegevens bekijken, wordt dat als beheerdersactie in de auditketen van de klant vastgelegd; beheerders van de tenant zien die bezoeken in hun eigen auditlogGeen stille toegang tot klantgegevens door medewerkers

Vertraging bij intrekken uit het Owners-team

De api cachet het lidmaatschap van een klant van het Owners-team in Forgejo tot 5 minuten, om het laden van pagina’s onder de 50 ms te houden (het alternatief is bij elk verzoek een rondgang naar de Forgejo-API, wat per pagina 100-200 ms trager zou zijn). De afweging:

  • Voeg je iemand aan de kant van Forgejo toe aan Owners, dan krijgt die binnen 5 minuten beheertoegang.
  • Verwijder je iemand aan de kant van Forgejo uit Owners, dan verliest die de beheertoegang binnen 5 minuten, niet direct.

Voor de meeste handelingen is die vertraging acceptabel: een voormalige eigenaar kan geen nieuwe Forgejo-resources aanmaken (de eigen controle van Forgejo is direct), en elke geprivilegieerde actie via de beheerinterface van fremforge wordt in het auditlog van de tenant vastgelegd met de gebruikersnaam van de uitvoerder, zodat activiteit na het intrekken toerekenbaar blijft.

Heb je onmiddellijke intrekking nodig (bijvoorbeeld als onderdeel van de reactie op een incident na gecompromitteerde inloggegevens), dan kan de dienstdoende beheerder op verzoek de cache voor je tenant op een TTL van nul zetten: open een ticket via support@frem.sh met het voorvoegsel [urgent-revocation] in het onderwerp en de gebruikersnaam en de slug van de tenant. Standaard-SLA: binnen 15 minuten tijdens kantooruren, binnen 60 minuten daarbuiten. Hetzelfde effect bereik je door de Forgejo-sessie van de gebruiker in te trekken (Forgejo Owner → User profile → Sign out), wat de sessiecookie ongeldig maakt die de api leest; daarvoor is geen actie aan de kant van fremforge nodig.

Beveiligingstoezeggingen van het platform

Ernst van de CVEPatch-SLA (vanaf de upstream release met de fix)
Critical (CVSS ≥ 9.0)48 uur
High (7.0-8.9)72 uur
Medium (4.0-6.9)7 dagen
LowVolgende geplande onderhoudsvenster

De patch-SLA is contractueel gepubliceerd en wordt letterlijk aangehaald in de beveiligingsbijlage van de DPA.

Integriteit van het auditlog: een manipulatiebestendige hashketen die elke 2 minuten wordt verankerd in WORM-opslag van T Cloud Public OBS; elk uur een integriteitscontrole via FunctionGraph; een breuk in de keten alarmeert de dienstdoende.

Probleemoplossing

De push wordt tegengehouden, maar ik kan het secret niet in de diff vinden.

Het secret staat misschien in een bestand dat is gewijzigd, maar waarvan de volledige inhoud niet in de standaard-diff te zien is. Draai Gitleaks lokaal om de exacte plek te vinden:

pip install gitleaks   # or brew install gitleaks
gitleaks detect --source . --verbose

Geen fix-pull request voor een bekende CVE.

Controleer of het ecosysteem en het manifest van het pakket fix-pull requests krijgen (Ondersteunde ecosystemen) en of de advisory een versie met een fix heeft. Renovate draait elke nacht voor een ingeschreven organisatie; Beveiliging › Herstellen › Updates van afhankelijkheden → Nu uitvoeren start er buiten de cyclus een, en Fix-PR openen op de bevinding vraagt direct een beveiligingsfix aan. Zie Als er geen pull request wordt geopend.

Het downloaden van een SBOM geeft 404.

SBOM’s worden alleen gegenereerd voor images die zijn gepusht nadat SBOM-generatie was ingeschakeld. Images die daarvóór zijn gepusht, hebben geen SBOM. Push een nieuwe tag om er een te genereren.

Ondertekenen met SSH faalt met ssh-keygen: gpg failed to sign the data.

Zorg dat git config gpg.format op ssh staat (niet op de standaard openpgp) en dat user.signingkey naar een bestand met een publieke sleutel wijst. Controleer op macOS ook dat ssh-keygen in je $PATH staat (de ssh-keygen die Apple meelevert, werkt; heb je OpenSSH via Homebrew geïnstalleerd, zorg dan dat die correct voorrang krijgt).

Kruisverwijzingen