Naar de hoofdinhoud

Transparantielog voor herkomst

fremforge ondertekent een herkomstattestatie voor elk artefact dat op het platform wordt gebouwd. Een handtekening bewijst dat de attestatie van ons komt. Ze bewijst op zichzelf niet dat we haar sindsdien niet door een andere hebben vervangen: dezelfde sleutel zou de vervanging net zo overtuigend ondertekenen.

De transparantielog dicht dat gat. Elke attestatie komt in een append-only Merkle-boom die op log.frem.sh wordt gepubliceerd, en de log ondertekent periodiek een checkpoint: een verklaring van de grootte en de root-hash van de boom op een bepaald moment. Omdat de boom alleen kan groeien en elk checkpoint aantoonbaar het vorige moet uitbreiden, kunnen we achteraf geen attestatie verwijderen of wijzigen zonder een checkpoint te maken dat in tegenspraak is met een checkpoint dat al is gepubliceerd.

Wat er in de log staat, en wat niet

Een leaf is een digest, geen attestatie. Elk item is de SHA-256 van een DSSE-envelop, en verder niets.

Dat is bewust, en het is wat de log volledig openbaar maakt. Met je eigen envelop in handen kun je aantonen dat die in de log staat: hash de bytes, haal een inclusiebewijs op en controleer het tegen een checkpoint. Wie je envelop niet heeft, leert alleen dat er op een bepaalde index een waarde van 32 bytes is vastgelegd. Namen van repository’s, commit-SHA’s, namen van artefacten en buildtijden blijven privé.

De enveloppen zelf publiceren zou niets aan je bewijs toevoegen, maar wel elke build van elke tenant permanent opsombaar maken, in een structuur die per definitie nooit iets kan verwijderen.

Wat het vandaag bewijst, en wat niet

Lees dit voordat je erop vertrouwt.

Een checkpoint draagt de handtekening van fremforge en één cosignatuur van een witness.

Onze handtekening maakt de log tamper-evident: heb je een bewijs en herschrijven we later de geschiedenis, dan verifieert je bewijs niet meer en kun je de tegenspraak aantonen.

De cosignatuur van de witness is wat onze eigen handtekening nooit kan zijn: een derde partij die weigert twee inconsistente checkpoints mede te ondertekenen. Sinds 16 september 2026 wordt elk checkpoint medeondertekend door witness.stagemole.eu, beheerd door Mullvad VPN AB. Het bevat ook een tijdstempel, waarvoor een C2SP-checkpoint geen veld heeft: zonder tijdstempel is een verouderd maar geldig ondertekend checkpoint niet te onderscheiden van een actueel.

Eén witness is geen quorum, en dat zeggen we liever dan het woord “witness” meer te laten doen dan het kan. Eén medeondertekenaar maakt het duurder om jou een andere boom te tonen dan iedereen anders; onmogelijk maakt hij het niet, omdat hij geen samenspanning tussen de log en zijn enige witness kan detecteren. De beheerder noemt deze instantie bovendien staging en geen productie.

Goed om te weten als je onafhankelijkheid beoordeelt: de enige witnesses van productiekwaliteit in de Europese Unie, Glasklar Teknik, Mullvad VPN en Tillitis, hebben hetzelfde moederbedrijf, Amagicom AB, wat hun eigen beheerders publiceren. Meer van hen toevoegen levert beschikbaarheid op, geen onafhankelijkheid. We gaan die set niet als onafhankelijke partijen omschrijven.

De trust root publiceert de actuele lijst onder transparency_log.witnesses. fremforge attest-verify controleert elk item en meldt hoeveel het er heeft geverifieerd.

Een ontbrekende cosignatuur laat de verificatie nu mislukken.

Omdat de trust root een witness declareert, vereist attest-verify minstens één cosignatuur om te verifiëren. Is de witness onbereikbaar op het moment dat we publiceren, dan gaat het checkpoint uit met alleen onze handtekening en mislukt je controle: de witnesscontrole meldt 0/1 verified.

Dat is bedoeld gedrag: een gedeclareerde witness die stilletjes ontbreekt, is precies het geval waarover je geïnformeerd wilt worden. Maar het betekent dat een mislukte run niet automatisch bewijs van manipulatie is. Kijk welke controle mislukte voordat je een conclusie trekt, en zie Endpoints om het checkpoint zelf op te halen.

Endpoints

PadInhoud
https://log.frem.sh/checkpointHet huidige ondertekende checkpoint
https://log.frem.sh/tile/<level>/<index>Tiles van de Merkle-boom
https://log.frem.sh/tile/entries/<index>Entry bundles (de vastgelegde digests)

De formaten zijn de C2SP-communitystandaarden tlog-checkpoint, signed-note en tlog-tiles, geen uitvinding van fremforge, dus bestaande tooling van derden kan ze lezen.

Controleer dat je attestatie is vastgelegd

Eén commando, en je hebt er geen fremforge-account voor nodig:

fremforge attest-verify <asset>.intoto.jsonl --human
✓ envelope signatures        6/6 verify under fremforge-slsa-builder-v2
✓ checkpoint signature       signed by log.frem.sh
✓ tiles hash to the checkpoint root
✓ every attestation is in the log
                             6/6 at leaf indices: fremforge-linux-x64@255, …
✓ append-only since last run
✓ 7/7 checks passed (computed on this machine — the server was not asked
  for a verdict)

Het eindigt met een exitcode ongelijk aan nul als een controle mislukt, dus je kunt het zo in CI opnemen.

Een net uitgebracht artefact staat mogelijk een paar minuten nog niet in de log. De log neemt nieuwe items op in een cyclus van vijftien minuten, dus een attestatie kan al ondertekend en gepubliceerd zijn voordat ze in de boom verschijnt. attest-verify meldt in dat venster NOT LOGGED en eindigt met een exitcode ongelijk aan nul, terecht, want ze staat er nog niet in. Probeer het kort daarna opnieuw. Is het artefact ouder dan ongeveer vijftien minuten en meldt het nog steeds NOT LOGGED, dan is dat een echte fout en is het de moeite waard om het bij ons te melden.

Elke hash en handtekening wordt op je eigen machine opnieuw berekend. Aan ons worden alleen bytes gevraagd: de trust root, het checkpoint, de tiles. Niets in de uitvoer is een oordeel dat wij je hebben gegeven. Dat is precies de bedoeling, want een verificatietool die de partij die wordt geverifieerd vraagt of alles in orde is, heeft niets geverifieerd.

Een .intoto.jsonl is JSON Lines: één envelop per artefact, dus een releasebundel bevat er één per binary plus de SBOM. Ze worden allemaal gecontroleerd.

Bewaar het statusbestand

attest-verify legt de boom die het zag vast in ~/.config/fremforge/tlog-state.json (te overschrijven met --state=<path>) en controleert bij de volgende run of de nieuwe boom die ongewijzigd nog bevat. Dit is de controle waarvoor geen derde partij nodig is, en het is de controle die een split view vangt die specifiek op jou is gericht. Voer haar dus meer dan eens uit, vanaf een plek die je bewaart, en verwijder het bestand niet om een fout weg te werken. De vastgelegde boom wordt bewust niet bijgewerkt als de controle mislukt, zodat een ontdekte herschrijving bij elke volgende run ontdekt blijft.

Of doe het met de hand

Het commando is een gemak, geen afhankelijkheid. Wil je ook onze binary niet vertrouwen, een redelijk standpunt voor het ene hulpmiddel dat ons juist moet wantrouwen, dan gebruikt de doorloop hieronder alleen curl, jq en sha256sum, en zijn de formaten communitystandaarden die ook tlog-tiles-clients van derden lezen.

Je hebt je envelop <asset>.intoto.jsonl nodig, die naast het artefact wordt meegeleverd.

# 1. The log's public key, from the trust root.
curl -sSfL https://www.frem.sh/.well-known/slsa-trust-root.json -o trust-root.json
jq -r '.transparency_log.vkey' trust-root.json

De vkey heeft de vorm log.frem.sh+<keyhash>+<base64 key>. Splits hem alleen op de eerste twee +: het laatste veld is base64 en bevat zelf ook +.

# 2. The digest of YOUR envelope. This is the leaf content.
#
# ONE LINE AT A TIME, AND INCLUDING ITS TRAILING NEWLINE — that is the unit
# the log commits to. Hashing the bundle as a whole finds nothing, which
# looks exactly like "your attestation was never logged".
head -c $(( $(head -1 <asset>.intoto.jsonl | wc -c) )) <asset>.intoto.jsonl | sha256sum
# 3. The current checkpoint, and the entries the log has published.
curl -sSfL https://log.frem.sh/checkpoint

Een checkpoint bestaat uit de origin, de boomgrootte, de root-hash in base64, een lege regel, en een of meer handtekeningregels die met een em-streepje (—) beginnen. Je digest staat in een van de entry bundles onder tile/entries/; de positie ervan is de leaf-index, en de tiles onder tile/<level>/ geven het inclusiebewijs van die leaf naar de root-hash die het checkpoint vastlegt.

Elke tlog-tiles-client kan deze doorloop voor je doen. Wil je er geen draaien, dan is de nuttige eigenschap eenvoudiger en nog steeds het controleren waard: je digest moet erin voorkomen, en de boomgrootte van het checkpoint mag alleen maar groeien.

Controleer dat de log de geschiedenis niet heeft herschreven

fremforge attest-verify doet dit voor je over meerdere runs heen; zie Bewaar het statusbestand hierboven. Met de hand:

Bewaar elk checkpoint dat je hebt gezien. Haal later een nieuwer checkpoint op en vraag de log om een consistentiebewijs tussen de twee groottes. Breidt de nieuwere boom de oudere niet uit, dan kan het bewijs niet worden geleverd, en een log die het niet kan leveren, heeft de geschiedenis herschreven.

Dit is de controle die een witness doorlopend uitvoert, en daarom zijn witnesses belangrijker dan welke controle je ook met de hand doet.

Verhouding tot de andere integriteitsmechanismen

fremforge draait drie afzonderlijke mechanismen die makkelijk door elkaar worden gehaald:

MechanismeDektWaar
AuditketenBeheeracties in je organisatieHashketen per tenant, WORM-verankerd
Sleutelloos commits ondertekenenGit-commitsZelf gehoste Fulcio + RFC3161-TSA, geen Rekor
Deze logAttestaties van buildherkomstlog.frem.sh

Ze zijn onafhankelijk. Sleutelloos commits ondertekenen gebruikt in het bijzonder nog steeds geen transparantielog: het integriteitsmiddel daarvan is de RFC3161-tijdstempel, zoals beschreven in het beveiligingsoverzicht. Deze log dekt alleen herkomstattestaties.

Soevereiniteit

De log draait op T Cloud Public in eu-de en wordt ondertekend met een Ed25519-sleutel die fremforge zelf beheert. Het is geen Rekor en hangt niet af van sigstore.dev, een log die in de VS wordt beheerd of een publiek CDN buiten de EU.

Witnesses zijn een bewuste uitzondering in wording: de waarde van een witness is dat hij niet van ons is, dus een witness kan best elders worden beheerd. Een witness ziet alleen checkpoints, een origin, een boomgrootte en een root-hash, nooit je repository’s, je artefacten of je builds. Elke witness die we toevoegen, komt in de trust root te staan, zodat de set controleerbaar is in plaats van aangenomen.