Journal de transparence de la provenance
fremforge signe une attestation de provenance pour chaque artefact construit sur la plateforme. Une signature prouve que l’attestation vient de nous. Elle ne prouve pas, à elle seule, que nous ne l’avons pas remplacée depuis par une autre : la même clé signerait la remplaçante de façon tout aussi convaincante.
Le journal de transparence comble cette lacune. Chaque attestation est
inscrite dans un arbre de Merkle en ajout seul publié sur log.frem.sh, et le
journal signe périodiquement un checkpoint : une déclaration de la taille
de l’arbre et de son hachage racine à un instant donné. Comme l’arbre est en
ajout seul et que chaque checkpoint doit étendre le précédent de façon
prouvable, nous ne pouvons pas retirer ni modifier une attestation après coup
sans produire un checkpoint qui contredise un checkpoint déjà publié.
Ce que contient le journal, et ce qu’il ne contient pas
Une feuille est un condensat, pas une attestation. Chaque entrée est le SHA-256 d’une enveloppe DSSE, et rien d’autre.
C’est délibéré, et c’est ce qui permet au journal d’être entièrement public. Si vous détenez votre propre enveloppe, vous pouvez prouver qu’elle figure dans le journal : hachez les octets, récupérez une preuve d’inclusion et vérifiez-la par rapport à un checkpoint. Quiconque ne détient pas votre enveloppe apprend seulement qu’une valeur de 32 octets a été journalisée à un certain index. Les noms de dépôts, les SHA de commits, les noms d’artefacts et les heures de build restent privés.
Publier les enveloppes elles-mêmes n’ajouterait rien à votre preuve, tout en rendant chaque build de chaque client énumérable pour toujours, dans une structure qui, par construction, ne peut jamais rien supprimer.
Ce qu’il prouve aujourd’hui, et ce qu’il ne prouve pas
Lisez ceci avant de vous y fier.
Un checkpoint porte la signature de fremforge et une cosignature de témoin.
Notre signature rend le journal inviolable de façon détectable : si vous détenez une preuve et que nous réécrivons ensuite l’historique, votre preuve cesse d’être vérifiable et vous pouvez démontrer la contradiction.
La cosignature du témoin est ce que notre propre signature ne pourra jamais
être : un tiers qui refuse de cosigner deux checkpoints incohérents. Depuis le
16 septembre 2026, chaque checkpoint est cosigné par witness.stagemole.eu,
exploité par Mullvad VPN AB. Il porte aussi un horodatage, pour lequel un
checkpoint C2SP n’a pas de champ : sans lui, un checkpoint périmé mais
valablement signé ne se distingue pas d’un checkpoint actuel.
Un seul témoin ne constitue pas un quorum, et nous préférons le dire plutôt que de laisser le mot « témoin » en faire plus qu’il ne peut. Un cosignataire unique augmente le coût de vous montrer un arbre différent de celui de tous les autres ; il ne le rend pas impossible, car il ne peut pas détecter une collusion entre le journal et son seul témoin. L’exploitant décrit par ailleurs cette instance comme une instance de préproduction plutôt que de production.
À savoir si vous évaluez l’indépendance : les seuls témoins de niveau production dans l’Union européenne (Glasklar Teknik, Mullvad VPN et Tillitis) ont une société mère commune, Amagicom AB, ce que leurs propres responsables publient. En ajouter d’autres apporterait de la disponibilité, pas de l’indépendance. Nous ne présenterons pas cet ensemble comme des parties indépendantes.
La racine de confiance publie la liste actuelle sous
transparency_log.witnesses. fremforge attest-verify vérifie chaque entrée
et indique le nombre qu’il a vérifié.
Une cosignature manquante fait désormais échouer la vérification.
Comme la racine de confiance déclare un témoin, attest-verify exige au moins
une cosignature pour valider. Si le témoin est injoignable au moment où nous
publions, le checkpoint part avec notre seule signature et votre vérification
échoue : la vérification du témoin indique 0/1 verified.
C’est le comportement voulu : un témoin déclaré qui est silencieusement absent est précisément le cas dont vous voulez être averti. Mais cela signifie qu’une exécution en échec n’est pas automatiquement une preuve de falsification. Regardez quelle vérification a échoué avant d’en tirer une conclusion, et consultez Points de terminaison pour récupérer vous-même le checkpoint.
Points de terminaison
| Chemin | Contenu |
|---|---|
https://log.frem.sh/checkpoint | Le checkpoint signé actuel |
https://log.frem.sh/tile/<level>/<index> | Les tuiles de l’arbre de Merkle |
https://log.frem.sh/tile/entries/<index> | Les lots d’entrées (les condensats journalisés) |
Les formats sont les standards communautaires C2SP tlog-checkpoint, signed-note et tlog-tiles ; ce n’est pas une invention de fremforge, et les outils tiers existants savent donc les lire.
Vérifier que votre attestation est journalisée
Une seule commande, qui ne nécessite aucun compte fremforge :
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)Elle se termine avec un code non nul si une vérification échoue : elle s’intègre donc telle quelle à la CI.
attest-verify indiquera NOT LOGGED et se terminera
avec un code non nul, à juste titre, puisqu’elle n’y est pas encore. Relancez
un peu plus tard. Si l’artefact a plus d’environ quinze minutes et indique
toujours NOT LOGGED, il s’agit d’un véritable échec, qui mérite de nous être
signalé.Chaque hachage et chaque signature sont recalculés sur votre machine. On ne nous demande que des octets : la racine de confiance, le checkpoint, les tuiles. Rien dans le résultat n’est un verdict que nous vous aurions fourni, et c’est tout l’intérêt : un outil de vérification qui demande à la partie vérifiée si tout va bien n’a rien vérifié.
Un .intoto.jsonl est au format JSON Lines : une enveloppe par artefact, de
sorte qu’un lot de publication en contient une par binaire, plus le SBOM.
Toutes sont vérifiées.
Conservez le fichier d’état
attest-verify enregistre l’arbre qu’il a vu dans
~/.config/fremforge/tlog-state.json (modifiable avec --state=<path>) et,
lors de l’exécution suivante, vérifie que le nouvel arbre contient toujours
celui-ci, inchangé. C’est la vérification qui ne nécessite aucun tiers, et
c’est elle qui détecte une vue divergente qui vous viserait spécifiquement :
exécutez-la donc plus d’une fois, depuis un endroit que vous conservez, et ne
supprimez pas le fichier pour effacer un échec. Elle ne fait délibérément pas
avancer l’arbre enregistré lorsque la vérification échoue, de sorte qu’une
réécriture détectée reste détectée à chaque exécution suivante.
Ou faites-le à la main
La commande est une commodité, pas une dépendance. Si vous préférez ne pas
faire confiance à notre binaire non plus, ce qui est une position raisonnable
pour le seul outil dont le rôle est de se méfier de nous, la procédure
ci-dessous n’utilise que curl, jq et sha256sum, et les formats sont des
standards communautaires que les clients tlog-tiles tiers savent aussi lire.
Il vous faut votre enveloppe <asset>.intoto.jsonl, livrée avec l’artefact.
# 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.jsonLa vkey a la forme log.frem.sh+<keyhash>+<base64 key>. Ne la découpez que
sur les deux premiers + : le dernier champ est en base64 et contient
lui-même des +.
# 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/checkpointUn checkpoint se compose de l’origine, de la taille de l’arbre, du hachage
racine en base64, d’une ligne vide, puis d’une ou plusieurs lignes de
signature commençant par un tiret cadratin (—). Votre condensat apparaît dans
l’un des lots d’entrées sous tile/entries/ ; sa position est son index de
feuille, et les tuiles sous tile/<level>/ fournissent la preuve d’inclusion
de cette feuille jusqu’au hachage racine sur lequel le checkpoint s’engage.
N’importe quel client tlog-tiles peut faire ce parcours pour vous. Si vous préférez ne pas en exécuter un, la propriété utile est plus simple et mérite tout de même d’être vérifiée : votre condensat doit apparaître, et la taille de l’arbre du checkpoint ne doit jamais faire que croître.
Vérifier que le journal n’a pas réécrit l’historique
fremforge attest-verify le fait pour vous d’une exécution à l’autre ; voir
Conservez le fichier d’état ci-dessus. À la main :
Conservez tout checkpoint que vous avez vu. Plus tard, récupérez-en un plus récent et demandez au journal une preuve de cohérence entre les deux tailles. Si le nouvel arbre n’étend pas l’ancien, la preuve ne peut pas être produite, et un journal incapable de la produire a réécrit l’historique.
C’est la vérification qu’un témoin effectue en continu, et c’est pourquoi les témoins comptent davantage que toute vérification ponctuelle faite à la main.
Lien avec les autres mécanismes d’intégrité
fremforge exploite trois mécanismes distincts, faciles à confondre :
| Mécanisme | Couvre | Où |
|---|---|---|
| Chaîne d’audit | Les actions d’administration sur votre organisation | Chaîne de hachage par client, ancrée en WORM |
| Signature de commits sans clé | Les commits Git | Fulcio auto-hébergé + TSA RFC3161, sans Rekor |
| Ce journal | Les attestations de provenance de build | log.frem.sh |
Ils sont indépendants. En particulier, la signature de commits sans clé n’utilise toujours aucun journal de transparence : sa primitive d’intégrité est l’horodatage RFC3161, comme le décrit la vue d’ensemble de la sécurité. Ce journal ne couvre que les attestations de provenance.
Souveraineté
Le journal fonctionne sur T Cloud Public dans eu-de, signé avec une clé
Ed25519 détenue par fremforge. Ce n’est pas Rekor, et il ne dépend ni de
sigstore.dev, ni d’aucun journal exploité aux États-Unis, ni d’un CDN public
situé hors de l’UE.
Les témoins constituent une exception délibérée en devenir : la valeur d’un témoin tient à ce qu’il n’est pas nous, et un témoin peut donc tout à fait être exploité ailleurs. Un témoin ne voit que des checkpoints (une origine, une taille d’arbre et un hachage racine), jamais vos dépôts, vos artefacts ni vos builds. Tout témoin que nous ajouterons sera listé dans la racine de confiance, de sorte que l’ensemble est vérifiable plutôt que présumé.