Ein SBOM sagt dir, was in einem Artefakt steckt. Wirklich nützlich wird es aber selten beim einzelnen Stand, sondern beim Vergleich. Was hat sich zwischen Release 1.4.0 und 1.5.0 in der Lieferkette geändert? Welche Abhängigkeit ist dazugekommen, welche ist rausgeflogen, welche wurde still auf eine neue Version gehoben? Genau das beantwortet ein SBOM-Diff, und er lässt sich in wenigen Zeilen automatisieren.

Der Reiz liegt im Signal. Ein Changelog erzählt dir, was das Team bewusst geändert hat. Ein SBOM-Diff zeigt dir, was tatsächlich im Image gelandet ist, inklusive transitiver Abhängigkeiten und OS-Paketen, die niemand aktiv angefasst hat.

Zwei SBOMs erzeugen

Ich nehme Syft und lasse für beide Image-Tags ein CycloneDX-SBOM im JSON-Format schreiben. Wichtig ist, dass beide mit demselben Werkzeug und demselben Format erzeugt werden, sonst vergleichst du am Ende Formatunterschiede statt echter Änderungen.

syft scan ghcr.io/acme/api:1.4.0 -o cyclonedx-json=sbom-1.4.0.json
syft scan ghcr.io/acme/api:1.5.0 -o cyclonedx-json=sbom-1.5.0.json

Den Diff mit jq bilden

Der vendor-neutrale Weg braucht kein Spezialwerkzeug. Ich ziehe aus jedem SBOM die Menge aus Name und Version, sortiere sie und lasse comm die Differenz bilden.

jq -r '.components[] | "\(.name)@\(.version)"' sbom-1.4.0.json | sort > comps-1.4.0.txt
jq -r '.components[] | "\(.name)@\(.version)"' sbom-1.5.0.json | sort > comps-1.5.0.txt
# neu in 1.5.0
comm -13 comps-1.4.0.txt comps-1.5.0.txt
# entfernt in 1.5.0
comm -23 comps-1.4.0.txt comps-1.5.0.txt

Ein Versions-Bump taucht in beiden Listen auf, einmal die alte Zeile als entfernt und einmal die neue als hinzugekommen. Für einen Überblick reicht das. Wer sauber nach echten Upgrades gruppieren will, joint über den reinen Namen.

Der zweckgebaute Weg mit cyclonedx-cli

Wenn du ohnehin bei CycloneDX bleibst, nimmt dir die cyclonedx-cli die Gruppierung ab. Sie kennt das Schema und zeigt Versionsänderungen direkt als solche an.

cyclonedx diff sbom-1.4.0.json sbom-1.5.0.json --component-versions

Vom Komponenten-Diff zum Risiko-Diff

Interessanter als die reine Paketliste ist die Frage, ob sich das Risiko verschoben hat. Dafür lasse ich Grype beide SBOMs scannen und vergleiche die CVE-Mengen. So sehe ich, welche Schwachstellen neu dazugekommen sind und welche das Release geschlossen hat.

grype sbom:sbom-1.4.0.json -o json > vulns-1.4.0.json
grype sbom:sbom-1.5.0.json -o json > vulns-1.5.0.json
jq -r '.matches[].vulnerability.id' vulns-1.4.0.json | sort -u > cves-1.4.0.txt
jq -r '.matches[].vulnerability.id' vulns-1.5.0.json | sort -u > cves-1.5.0.txt
# neu eingeschleppt
comm -13 cves-1.4.0.txt cves-1.5.0.txt
# behoben
comm -23 cves-1.4.0.txt cves-1.5.0.txt

In die Pipeline einbauen

Der Diff entfaltet seinen Wert, wenn er bei jedem Release automatisch läuft. Ich hänge ihn an den Build, speichere beide SBOMs als Artefakt und lasse den Job eine Warnung ausgeben, sobald eine neue kritische Komponente oder ein neuer CVE auftaucht. Das gibt dem Review einen konkreten Anhaltspunkt statt eines diffusen Bauchgefühls.

NEU=$(comm -13 cves-1.4.0.txt cves-1.5.0.txt)
if [ -n "$NEU" ]; then
echo "Neue Schwachstellen in diesem Release:"
echo "$NEU"
fi

Ob das den Build bricht oder nur meldet, ist eine Policy-Entscheidung. Am Anfang reicht das Melden. Sobald das Team dem Signal vertraut, kann ein neuer kritischer CVE ohne Ausnahme den Merge blockieren.

Grenzen

Der Diff ist nur so gut wie das SBOM darunter. Wenn Syft eine transitive Abhängigkeit nicht sauber auflöst, fehlt sie in beiden Ständen und der Diff schweigt. Unterschiedliche Namensschemata zwischen Scannern oder Ökosystemen führen zu Phantom-Änderungen, deshalb immer dasselbe Werkzeug verwenden. Und ein Versions-Bump ohne funktionale Änderung erzeugt Rauschen, das man wegfiltern muss, bevor der Diff im Review ankommt.

Trotzdem ist das Verhältnis von Aufwand zu Erkenntnis kaum zu schlagen. Zwei Scans, ein paar Zeilen jq, und du weißt genau, was sich in der Lieferkette bewegt hat. Wie sich das mit Signaturen und Provenance zu einer belastbaren Lieferkette zusammensetzt, habe ich auf digital-business.blog ausführlicher beschrieben.

Hinterlasse einen Kommentar

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..