Hoppa till huvudinnehållet

Transparenslogg för provenance

fremforge signerar en provenance-attestering för varje artefakt som byggs på plattformen. En signatur bevisar att attesteringen kom från oss. Den bevisar inte i sig att vi inte senare har ersatt den med en annan, eftersom samma nyckel skulle signera ersättningen lika övertygande.

Transparensloggen täpper till det. Varje attestering förs in i ett Merkle-träd som bara kan utökas och som publiceras på log.frem.sh, och loggen signerar regelbundet en checkpoint: ett påstående om trädets storlek och rothash vid en viss tidpunkt. Eftersom trädet bara kan utökas och varje checkpoint bevisligen måste bygga vidare på den föregående, kan vi inte ta bort eller ändra en attestering i efterhand utan att skapa en checkpoint som motsäger en som redan publicerats.

Vad som finns i loggen, och vad som inte gör det

Ett löv är en digest, inte en attestering. Varje post är SHA-256 av ett DSSE-kuvert, och ingenting annat.

Det är avsiktligt, och det är det som gör att loggen kan vara helt publik. Har du ditt eget kuvert kan du bevisa att det finns i loggen: hasha byten, hämta ett inkluderingsbevis och kontrollera det mot en checkpoint. Den som inte har ditt kuvert får bara veta att ett 32-bytevärde loggades vid något index. Repo-namn, commit-SHA:er, artefaktnamn och byggtider förblir privata.

Att publicera själva kuverten skulle inte tillföra ditt bevis något, men skulle göra varje bygge i varje tenant permanent uppräkningsbart, i en struktur som av konstruktion aldrig kan ta bort något.

Vad den bevisar i dag, och vad den inte bevisar

Läs det här innan du förlitar dig på den.

En checkpoint har fremforges signatur och en vittnes medsignatur.

Vår signatur gör loggen manipulationsevident: om du har ett bevis och vi senare skriver om historiken slutar ditt bevis att verifieras, och du kan påvisa motsägelsen.

Vittnets medsignatur är det som vår egen signatur aldrig kan vara: en tredje part som vägrar att medsignera två motstridiga checkpoints. Sedan den 16 september 2026 är varje checkpoint medsignerad av witness.stagemole.eu, som drivs av Mullvad VPN AB. Den har också en tidsstämpel, vilket en C2SP-checkpoint saknar fält för: utan den går en inaktuell men giltigt signerad checkpoint inte att skilja från en aktuell.

Ett vittne är inte ett kvorum, och vi säger hellre det än låter ordet “vittne” göra mer än det kan. En enda medsignerare höjer kostnaden för att visa dig ett annat träd än alla andra ser; den gör det inte omöjligt, eftersom den inte kan upptäcka samverkan mellan loggen och dess enda vittne. Operatören beskriver också den här instansen som staging snarare än produktion.

Bra att veta om du bedömer oberoende: de enda vittnen av produktionsklass i Europeiska unionen, Glasklar Teknik, Mullvad VPN och Tillitis, har samma moderbolag, Amagicom AB, vilket deras egna förvaltare publicerar. Att lägga till fler av dem skulle ge tillgänglighet, inte oberoende. Vi kommer inte att beskriva den gruppen som oberoende parter.

Förtroenderoten publicerar den aktuella listan i transparency_log.witnesses. fremforge attest-verify kontrollerar varje post och rapporterar hur många den verifierade.

En saknad medsignatur gör nu att verifieringen misslyckas.

Eftersom förtroenderoten anger ett vittne kräver attest-verify minst en medsignatur för att verifiera. Om vittnet inte går att nå när vi publicerar, skickas checkpointen ut med bara vår signatur och din kontroll misslyckas: vittneskontrollen rapporterar 0/1 verified.

Det är det avsedda beteendet: ett angivet vittne som tyst saknas är precis det fall du vill bli informerad om. Men det betyder att en misslyckad körning inte automatiskt är bevis på manipulation. Läs vilken kontroll som misslyckades innan du drar en slutsats, och se Endpoints för att hämta checkpointen själv.

Endpoints

SökvägInnehåll
https://log.frem.sh/checkpointDen aktuella signerade checkpointen
https://log.frem.sh/tile/<level>/<index>Tiles i Merkle-trädet
https://log.frem.sh/tile/entries/<index>Postbuntar (de loggade digesterna)

Formaten är C2SP-gemenskapens standarder tlog-checkpoint, signed-note och tlog-tiles, inte en fremforge-uppfinning, så befintliga verktyg från tredje part kan läsa dem.

Verifiera att din attestering är loggad

Ett kommando, och det kräver inget fremforge-konto:

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)

Det avslutar med en kod skild från noll om någon kontroll misslyckas, så det kan läggas in i CI som det är.

En nyss släppt artefakt kanske inte finns i loggen förrän efter några minuter. Loggen läser in i en cykel på femton minuter, så en attestering kan signeras och publiceras innan den syns i trädet. attest-verify rapporterar då NOT LOGGED och avslutar med en kod skild från noll under det fönstret, vilket är korrekt eftersom den inte finns där än. Kör igen om en stund. Om artefakten är äldre än ungefär femton minuter och fortfarande rapporterar NOT LOGGED är det ett verkligt fel som du bör ta upp med oss.

Varje hash och signatur beräknas om på din maskin. Vi ombeds bara om byte: förtroenderoten, checkpointen, tilesen. Ingenting i utdata är ett utlåtande som vi gav dig, och det är hela poängen: ett verifieringsverktyg som frågar den part som verifieras om allt är i sin ordning har inte verifierat någonting.

En .intoto.jsonl är JSON Lines: ett kuvert per artefakt, så en release-bunt innehåller ett per binärfil plus SBOM:en. Alla kontrolleras.

Behåll tillståndsfilen

attest-verify registrerar trädet den såg i ~/.config/fremforge/tlog-state.json (ändra med --state=<path>) och kontrollerar vid nästa körning att det nya trädet fortfarande innehåller det trädet oförändrat. Det här är kontrollen som inte kräver någon tredje part, och det är den som fångar en delad vy som riktas just mot dig. Kör den därför mer än en gång, från ett ställe du behåller, och ta inte bort filen för att bli av med ett fel. Den flyttar avsiktligt inte fram det registrerade trädet när kontrollen misslyckas, så en upptäckt omskrivning förblir upptäckt vid varje följande körning.

Eller gör det för hand

Kommandot är en bekvämlighet, inte ett beroende. Om du inte heller vill lita på vår binärfil, vilket är en rimlig hållning för det verktyg vars uppgift är att misstro oss, använder genomgången nedan inget annat än curl, jq och sha256sum, och formaten är gemenskapsstandarder som även tlog-tiles-klienter från tredje part läser.

Du behöver ditt kuvert <asset>.intoto.jsonl, som levereras tillsammans med artefakten.

# 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

Vkey har formen log.frem.sh+<keyhash>+<base64 key>. Dela den bara vid de två första +: det sista fältet är base64 och innehåller själv +.

# 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

En checkpoint består av ursprunget, trädets storlek, rothashen i base64, en tom rad och en eller flera signaturrader som börjar med ett tankstreck (—). Din digest finns i en av postbuntarna under tile/entries/; dess position är dess lövindex, och tilesen under tile/<level>/ ger inkluderingsbeviset från det lövet till den rothash som checkpointen binder sig till.

Vilken tlog-tiles-klient som helst kan göra den här genomgången åt dig. Om du hellre inte kör en sådan är den användbara egenskapen enklare och ändå värd att kontrollera: din digest måste finnas med, och checkpointens trädstorlek får bara växa.

Verifiera att loggen inte har skrivit om historiken

fremforge attest-verify gör det här åt dig mellan körningar, se Behåll tillståndsfilen ovan. För hand:

Behåll varje checkpoint du har sett. Hämta senare en nyare och be loggen om ett konsistensbevis mellan de två storlekarna. Om det nyare trädet inte bygger vidare på det äldre kan beviset inte tas fram, och en logg som inte kan ta fram det har skrivit om historiken.

Det är den här kontrollen som ett vittne utför kontinuerligt, och därför betyder vittnen mer än någon enskild verifiering du gör för hand.

Förhållande till de andra integritetsmekanismerna

fremforge kör tre separata saker som är lätta att blanda ihop:

MekanismOmfattarVar
GranskningskedjaAdministrativa åtgärder i din organisationHashkedja per tenant, WORM-förankrad
Nyckellös commit-signeringGit-commitsEgen Fulcio + RFC3161 TSA, ingen Rekor
Den här loggenProvenance-attesteringar för byggenlog.frem.sh

De är oberoende av varandra. I synnerhet använder nyckellös commit-signering fortfarande ingen transparenslogg; dess integritetsprimitiv är RFC3161-tidsstämpeln, som beskrivs i säkerhetsöversikten. Den här loggen omfattar endast provenance-attesteringar.

Suveränitet

Loggen körs på T Cloud Public i eu-de och signeras med en Ed25519-nyckel som fremforge innehar. Den är inte Rekor och är inte beroende av sigstore.dev, någon USA-driven logg eller ett publikt CDN utanför EU.

Vittnen är ett medvetet undantag under framväxt: värdet med ett vittne är att det inte är vi, så ett vittne kan mycket väl drivas någon annanstans. Ett vittne ser bara checkpoints, ett ursprung, en trädstorlek och en rothash, aldrig dina repon, dina artefakter eller dina byggen. Varje vittne vi lägger till listas i förtroenderoten, så att gruppen kan granskas i stället för att tas för given.