Anleitungen · Teil 7 von 8
Releases aus der CI verankern
Jedes Release, das Sie ausliefern, ist eine Menge von Bytes: Tarballs, Wheels, Container-Images, ein Bereich von Commits. Einen Label-309-Existenznachweis (engl. Proof of Existence, PoE) für diese Bytes zu verankern, verwandelt „Vertrauen Sie unserem Wort, dass dieser Build das ist, was wir veröffentlicht haben" in „Hier ist eine Cardano-Transaktion, die es bezeugt." Sie hashen jedes Artefakt zu einem Blatt, falten die Blätter zu einer einzigen Merkle-Wurzel zusammen und veröffentlichen diese eine Wurzel auf der Blockchain unter dem Metadaten-Label 309. Von da an kann jede und jeder mit der Transaktionsreferenz beweisen, dass ein Artefakt zum Zeitpunkt seiner Blockzeit oder davor existierte, allein anhand der öffentlichen Blockchain, ohne Konto und ohne Vertrauen in Ihre Pipeline oder Ihren Anbieter.
Die Artefakt-Bytes verlassen den Runner niemals. Das CLI hasht lokal und veröffentlicht nur Digests, daher ist dies auch für private Repositorys und Closed-Source-Builds sicher: Was auf die Blockchain gelangt, ist ein Hash fester Länge, niemals Ihr Code.
Das zentrale Werkzeug: cardanowall attest
Alles auf dieser Seite läuft über einen einzigen Befehl des Gateway-unabhängigen
cardanowall-CLI (Crate cardanowall-cli auf crates.io, mit vorgefertigten
Binärdateien auf den label-309-cli-Releases).
attest ist der auf CI zugeschnittene Einstiegspunkt: Es hasht Ihre Eingaben,
holt ein Preisangebot ein, veröffentlicht einen Datensatz über ein Gateway und
wartet auf den Lebenszyklus-Zustand, den Sie angeben.
Richten Sie es mit einer Basis-URL und einem auf Veröffentlichung beschränkten API-Schlüssel auf ein beliebiges Label-309-Gateway und geben Sie ihm dann etwas zu hashen:
export CARDANOWALL_API_KEY="…" # a publish-scoped key from your gateway
cardanowall attest \
--paths 'dist/*' \
--base-url https://your-gateway.example/api/v1 \
--wait confirmed \
--receipt-out poe-receipt.json--base-url und --api-key lesen auch aus CARDANOWALL_BASE_URL und
CARDANOWALL_API_KEY, sodass beide in der CI aus dem Befehl herausfallen, wo
diese aus Ihrem Secret-Store gesetzt werden.
Drei Wege, um zu wählen, was Sie verankern
Setzen Sie genau eine Eingabe; der Modus ergibt sich daraus.
Dateien. --paths nimmt einen konkreten Pfad oder ein Glob-Muster entgegen,
wiederholbar. Jedes Blatt ist der SHA-256 der Bytes einer Datei. Die Auswahl wird
dedupliziert und byteweise nach normalisiertem relativem Pfad sortiert, sodass
derselbe Arbeitsbaum immer dieselbe Wurzel erzeugt, unabhängig von der
Reihenfolge, in der die Shell ein Glob auflösen würde. Setzen Sie das Glob in
Anführungszeichen, damit Ihre Shell es nicht vorab auflöst:
cardanowall attest --paths 'dist/**/*.tar.gz' --paths 'dist/**/*.whl'Commits. --commits nimmt einen git-rev-list-Bereich entgegen; jedes Blatt
ist der SHA-256 eines rohen Commit-Objekts, das älteste zuerst. Dies verankert die
Provenienz der Historie selbst. Es benötigt die vollständige git-Historie auf dem
Runner, da ein flacher Klon den Bereich nicht auflösen kann:
cardanowall attest --commits v1.0.0..v1.1.0Vorgehashte Digests. --leaf nimmt einen 64-stelligen Hex-Digest entgegen,
den Sie anderswo berechnet haben, wiederholbar und in der Argumentreihenfolge
beibehalten. Verwenden Sie es, um etwas zu verankern, das das CLI nie als Datei
sieht, etwa einen OCI-Image-Digest:
cardanowall attest --leaf 9f86d0818840…0a08 # a 64-hex digest, e.g. an image digestEin einzelnes Blatt veröffentlicht einen Datensatz mit einem einzigen Element; mehrere Blätter veröffentlichen einen Merkle-Datensatz, dessen Wurzel auf der Blockchain verankert wird, wobei die Blattliste hochgeladen wird, sodass jedes Element später ein Inklusionszertifikat erhalten kann.
Das Manifest und die Quittung
Im Dateimodus schreibt attest eine deterministische poe-manifest.json neben
seine Ausgabe (mit --manifest-out umbenennen). Das Manifest hält die Zuordnung
von Name zu Hash für jede verankerte Datei fest, und dieselben Eingaben erzeugen
immer byteidentische Manifest-Bytes. Fügen Sie --anchor-manifest hinzu, um den
SHA-256 des Manifests als letztes Blatt einzufalten, sodass die Bindung zwischen
Dateinamen und Hashes selbst Teil dessen wird, worauf sich die Wurzel festlegt.
--receipt-out schreibt eine versionierte JSON-Quittung, die den Datensatz, das
Preisangebot, die Transaktion und den Warte-Schnappschuss trägt. Bewahren Sie sie
als Nachweis Ihres Builds auf: Sie ist alles, was ein späteres verify braucht,
um den Anker zu finden und zu prüfen. Speichern Sie sie als Workflow-Artefakt,
hängen Sie sie an das Release an oder committen Sie sie neben dem Changelog.
Warten, Ausstehen und erneute Läufe
Standardmäßig wartet attest, bis die Transaktion die Bestätigungsschwelle
überschreitet (--wait confirmed); --wait submitted kehrt zurück, sobald sie
das Netzwerk erreicht. Das Warten hat eine Frist (--timeout, standardmäßig 600
Sekunden). Läuft die Frist ab, werden die Ausgaben und die Quittung dennoch
geschrieben und der Prozess beendet sich mit 3 (ausstehend): Die Veröffentlichung
geht nicht verloren, sie läuft auf dem Gateway weiter, und Sie können später mit
der Quittung erneut nachsehen. Eine --max-usd-Obergrenze verweigert die
Veröffentlichung (Exit-Code 1, vor jedem Upload), wenn das Angebot über Ihrem
Limit liegt, sodass eine Preisspitze eine Pipeline niemals überraschend belasten
kann.
Erneute Läufe sind von Grund auf sicher. attest sendet standardmäßig keinen
Idempotenz-Header; stattdessen dedupliziert das Gateway byteidentische Datensätze,
sodass ein erneuter Lauf desselben Builds nie ein zweites Mal verankert und nie
doppelt abgerechnet wird. Verankern Sie dasselbe dist/ erneut, und der zweite
Lauf wiederholt den ersten Datensatz kostenlos.
GitHub Actions
Die Action cardanowall/poe-attest umschließt dasselbe CLI für GitHub-Workflows.
Sie ist quelloffen und über die Lieferkette gepinnt: Sie bettet die
SHA-256-Digests des von ihr ausgeführten CLI-Releases ein und verifiziert vor
jedem Lauf sowohl das heruntergeladene Archiv als auch die extrahierte
Binärdatei, sodass ein ausgetauschtes Release-Asset nicht durchrutschen kann.
Hinterlegen Sie zwei Secrets im Repository, GATEWAY_URL (die Basis-URL der
Datenebene Ihres Gateways, die auf /api/v1 endet) und GATEWAY_API_KEY (einen
auf Veröffentlichung beschränkten Schlüssel), und verankern Sie dann Ihre
Release-Assets beim Veröffentlichen:
name: anchor-release
on:
release:
types: [published]
permissions:
contents: read
jobs:
attest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: cardanowall/poe-attest@v1
with:
gateway-url: ${{ secrets.GATEWAY_URL }}
api-key: ${{ secrets.GATEWAY_API_KEY }}
paths: |
dist/**/*.tar.gz
dist/**/*.whlDer Schritt schreibt die Quittung, gibt eine Zusammenfassung mit der Transaktion
und einem Verifizierungslink aus und stellt Ausgaben (tx, record-id,
verify-url und weitere) für spätere Schritte bereit.
Den Datenstrom mit einer dedizierten CI-Identität signieren
Um die Anker einer Pipeline zurechenbar und auffindbar zu machen, signieren Sie
jeden Datensatz mit einem Identitäts-Seed. Das Gateway indiziert den Datensatz
dann nach seinem Signierer-Public-Key, sodass jede und jeder die gesamte Historie
einer Pipeline über den Datensatz-Feed des Gateways mit ?signer=<public-key>
auflisten kann. Das Signieren bleibt optional, und Verifizierer verlangen es nie.
Verwenden Sie eine dedizierte, wegwerfbare Identität pro Pipeline, niemals einen persönlichen Seed. Hinterlegen Sie ihn als umgebungsgeschütztes Secret, sodass nur Läufe aus dieser Umgebung ihn lesen können:
jobs:
attest:
runs-on: ubuntu-latest
environment: release-signing
steps:
- uses: actions/checkout@v7
- uses: cardanowall/poe-attest@v1
with:
gateway-url: ${{ secrets.GATEWAY_URL }}
api-key: ${{ secrets.GATEWAY_API_KEY }}
seed: ${{ secrets.CI_SIGNING_SEED }}
paths: dist/**/*.tar.gzDer Seed wird in Logs maskiert und nur über stdin an das CLI übergeben, niemals auf der Befehlszeile, und kein Secret erreicht jemals das Gateway: Hashen und Signieren geschehen lokal, und nur der Datensatz und öffentliche Daten werden veröffentlicht.
Niemals aus pull_request_target verankern
Dieser Trigger legt Ihre Repository-Secrets gegenüber Code aus geforkten Pull Requests offen.
Verankern Sie nur aus Ereignissen, die Sie kontrollieren, etwa release, push oder
workflow_dispatch. Der minimale Job oben benötigt nur contents: read; fügen Sie contents: write nur hinzu, wenn Sie die Quittung zusätzlich an das Release anhängen.
Die Action trägt mehr Eingaben, als hier gezeigt werden, darunter ein Inklusionszertifikat pro Blatt, das Anhängen von Release-Assets, eine Preisobergrenze und die Timeout-Richtlinie. Den vollständigen Satz finden Sie im Action-README.
GitLab CI/CD
Auf GitLab kommt derselbe Wrapper als CI/CD-Komponente. Der Job läuft im eigenen Container-Image des CLI, festgepinnt auf Version und Digest, sodass zur Laufzeit nichts installiert wird — und wie überall auf dieser Seite funktioniert jedes Label-309-Gateway, gehostet oder selbst betrieben:
include:
- component: gitlab.com/cardanowall/poe-attest/attest@1
inputs:
gateway-url: https://your-gateway.example/api/v1
paths: |
dist/**/*.tar.gz
dist/**/*.whlHinterlegen Sie die Secrets als CI/CD-Variablen unter Settings → CI/CD →
Variables, maskiert und geschützt: CARDANOWALL_API_KEY (der Schlüssel mit
Publish-Scope) und, nur wenn Sie signieren, CARDANOWALL_SEED — gesetzt am
Projekt selbst, niemals an einer Gruppe: Vererbung würde die Anker jedes
Unterprojekts stillschweigend mit einer einzigen Identität signieren.
Standardmäßig läuft der Job nur in Pipelines geschützter Tags, sodass ein
ungeschützter Ref niemals Ihr Guthaben ausgeben kann; überschreiben Sie die
Eingabe rules, um bei anderen Ereignissen zu verankern.
Die Ergebnisse kommen als dotenv-Report zurück: Ein nachgelagerter Job, der den
Attest-Job per needs: referenziert, liest die Transaktion, den Verify-Link
und die übrigen der achtzehn POE_*-Variablen direkt:
announce:
needs: [poe-attest]
script:
- echo "anchored in $POE_TX"
- echo "verify at $POE_VERIFY_URL"Die Komponente trägt mehr Eingaben, als hier gezeigt werden, darunter Inklusionszertifikate, eine Preisobergrenze, Runner-Tags und die Timeout-Richtlinie. Den vollständigen Satz finden Sie im Komponenten-README.
Andere CI-Systeme
Dasselbe CLI läuft überall. Verwenden Sie das Container-Image
ghcr.io/cardanowall/label-309-cli (dessen Entrypoint cardanowall ist) oder
eine vorgefertigte Binärdatei von der Releases-Seite.
Jeder andere Runner, mit der Binärdatei auf PATH:
export CARDANOWALL_BASE_URL="https://your-gateway.example/api/v1"
export CARDANOWALL_API_KEY="$YOUR_CI_SECRET"
cardanowall attest \
--paths 'dist/*' \
--wait confirmed \
--receipt-out poe-receipt.json
# exit 0 = reached the wait target; 3 = pending (publish continues on the gateway);
# 1 = refused (for example over --max-usd) or failed.Was Sie von einem Gateway brauchen
Das Veröffentlichen bringt eine Transaktion auf Cardano, und das kostet eine
Gebühr, daher braucht attest ein Gateway, über das es übermittelt. Jedes
Label-309-Gateway funktioniert: ein gehosteter Betreiber oder Ihr eigenes
selbst gehostetes Gateway (das quelloffene
label-309-gateway, eine
Rust-Binärdatei plus Postgres). Aus der CI brauchen Sie nur zwei Dinge davon: eine
Basis-URL der Datenebene und einen auf Veröffentlichung beschränkten API-Schlüssel
(poe:create), gedeckt durch ein vorausbezahltes Guthaben.
Das Gateway besitzt die finanzierte Cardano-Wallet und zahlt die Gebühr aus seinem eigenen Guthabenmodell. Ihre CI hält keinen Wallet-Schlüssel und keine Blockchain-Mittel. Das Schlimmste, was ein durchgesickerter API-Schlüssel anrichten kann, ist, das vorausbezahlte Guthaben dieses Kontos für weitere Anker auszugeben; er kann keine Mittel bewegen, Ihre Inhalte lesen oder in Ihrem Namen signieren. Rotieren oder widerrufen Sie ihn jederzeit.
Den Anker verifizieren
Diese Verankerung ist nur deshalb etwas wert, weil jede und jeder sie ohne Sie prüfen kann. Mit der Transaktionsreferenz aus der Quittung läuft die Verifizierung eigenständig gegen die öffentliche Blockchain und einen Explorer Ihrer Wahl, ohne Konto und ohne Gateway:
cardanowall verify <tx-hash>Es löst die Transaktion auf, validiert den Datensatz strukturell, prüft eine
etwaige Signatur, bestätigt, dass der Datensatz abgeschlossen ist, und gibt ein
Ergebnis als Exit-Code zurück, sodass es sich ebenso sauber in eine nachgelagerte
Prüfung einfügt, wie attest auf die Veröffentlichungsseite passt. Um ein
einzelnes Artefakt gegen seinen Anker zu bestätigen, hashen Sie die Datei und
vergleichen Sie, oder erstellen Sie für einen Merkle-Datensatz ein
Inklusionszertifikat, das ein Artefakt an die
veröffentlichte Wurzel bindet. Das vollständige Verifizierer-Modell finden Sie
unter Verifizierung.
Der Nachweis überdauert die Pipeline
Ein Label-309-Anker ist schlichte Metadaten unter Label 309, keine Anbieter-Quittung. Lange nachdem der Runner verschwunden ist, die Registry rotiert wurde und das CI-System nur noch Erinnerung ist, bezeugt die Transaktion weiterhin, dass Ihre Artefakte zu ihrer Blockzeit existierten. Jede und jeder kann sie verifizieren über die öffentliche Blockchain, ohne Konto und ohne Vertrauen in denjenigen, der sie veröffentlicht hat.