diff --git a/.gitea/workflows/govulncheck.yml b/.gitea/workflows/govulncheck.yml new file mode 100644 index 0000000..21e0e97 --- /dev/null +++ b/.gitea/workflows/govulncheck.yml @@ -0,0 +1,38 @@ +name: Supply-Chain-Scan (Go) + +on: + push: + paths: + - "**/*.go" + - "go.mod" + - "go.sum" + pull_request: {} + +jobs: + govulncheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.22" + - name: govulncheck installieren + # @latest kann eine govulncheck-Version verlangen, die neuer ist als + # die hier verwendete Go-Toolchain (z.B. "requires go >= 1.25.0") — + # feste, bekannt kompatible Version statt @latest (siehe + # scripts/verify-supply-chain-gate.sh, Fund vom 2026-08-28 auf dem Testhost). + run: go install golang.org/x/vuln/cmd/govulncheck@v1.1.3 + - name: Go-Module auf bekannte Schwachstellen pruefen + shell: bash + run: | + # pipefail ist Pflicht: sonst liefert "govulncheck | tee" den Exit-Code + # von tee (immer 0) statt den von govulncheck zurueck — der Gate-Zweck + # (Akzeptanzkriterium 3: Fund blockiert den Merge) waere sonst wirkungslos. + set -o pipefail + govulncheck ./... | tee govulncheck-report.txt + - name: Scan-Bericht als Artefakt ablegen + if: always() + uses: actions/upload-artifact@v4 + with: + name: govulncheck-report + path: govulncheck-report.txt diff --git a/.gitea/workflows/npm-audit.yml b/.gitea/workflows/npm-audit.yml new file mode 100644 index 0000000..e6d4665 --- /dev/null +++ b/.gitea/workflows/npm-audit.yml @@ -0,0 +1,32 @@ +name: Supply-Chain-Scan (npm) + +on: + push: + paths: + - "web/**/package.json" + - "web/**/package-lock.json" + pull_request: {} + +jobs: + npm-audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22" + - name: Alle Next.js-Frontends auf bekannte Schwachstellen pruefen + shell: bash + run: | + set -o pipefail + status=0 + for pkg in $(find web -maxdepth 2 -name package.json); do + dir=$(dirname "$pkg") + echo "=== npm audit: $dir ===" + (cd "$dir" && npm install --package-lock-only --no-audit --no-fund \ + && npm audit --audit-level=high) || status=1 + done + # Erst nach Durchlauf ALLER Frontends fehlschlagen (Akzeptanzkriterium 2/3): + # ein einzelner Fund darf nicht verhindern, dass die uebrigen Frontends + # ebenfalls geprueft und im Bericht sichtbar werden. + exit $status diff --git a/DEVLOG.md b/DEVLOG.md index 3159869..ae451ef 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -97,6 +97,50 @@ Keine Commits in dieser Session. - internal/db/db.go | 11 +++++++++++ - migrations/0001_tenant_registry.sql | 10 ++++++++++ +--- +## 2026-08-28 23:00 – 23:01 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** nexarch + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- .gitea/workflows/govulncheck.yml | 32 ++++++++++++++++++++++++++++++++ +- .gitea/workflows/npm-audit.yml | 28 ++++++++++++++++++++++++++++ +- scripts/verify-supply-chain-gate.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +- testdata/vulnfixture-go/go.mod | 8 ++++++++ +- testdata/vulnfixture-go/main.go | 12 ++++++++++++ +- testdata/vulnfixture-npm/package.json | 10 ++++++++++ + +--- +## 2026-08-28 23:02 – 23:03 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** code + +### Commits +- ab7a033 OPS-06: fix — fixture ruft tatsaechlich verwundbaren symbolpfad auf (ParseAcceptLanguage statt Parse, GO-2022-1059 statt falscher advisory-id) +- 77ecf42 OPS-06: fix — verify-supply-chain-gate.sh unterscheidet jetzt echten Fund von Werkzeugfehler (pruefte vorher nur exit-code, 'command not found' galt faelschlich als bestanden) + +### Geänderte Dateien +- testdata/vulnfixture-go/go.mod | 8 +++++--- +- testdata/vulnfixture-go/main.go | 7 +++++-- +- DEVLOG.md | 12 ++++++++++++ +- scripts/verify-supply-chain-gate.sh | 52 +++++++++++++++++++++++++++++++++++++--------------- + +--- +## 2026-08-28 23:04 – 23:05 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** code + +### Commits +- 9de84f6 OPS-06: fix — fehlendes fail=1 im govulncheck-unavailable-zweig, govulncheck-version gepinnt statt @latest (Go-Versionskonflikt auf 131 gefunden) + +### Geänderte Dateien +- .gitea/workflows/govulncheck.yml | 6 +++++- +- DEVLOG.md | 12 ++++++++++++ +- scripts/verify-supply-chain-gate.sh | 13 +++++++++++-- + --- ## 2026-08-27 17:36 – 17:36 (0m) **Beschreibung:** Claude Code Session diff --git a/scripts/verify-supply-chain-gate.sh b/scripts/verify-supply-chain-gate.sh new file mode 100755 index 0000000..6d95bcd --- /dev/null +++ b/scripts/verify-supply-chain-gate.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# OPS-06 Pruefung 1: beweist, dass govulncheck und npm audit eine absichtlich +# verwundbare Testabhaengigkeit tatsaechlich ERKENNEN (nicht nur irgendeinen +# Fehler werfen) und mit Exit-Code != 0 enden (= wuerden den Merge blockieren). +# Laeuft auf dem Testhost (Go/npm noetig), nicht auf der Entwicklungsmaschine. +# +# Wichtig: ein Exit-Code != 0 allein ist KEIN Beweis — ein fehlendes Tool +# ("command not found", exit 127) sieht fuer ein reines Exit-Code-Gate genauso +# aus wie ein echter Fund. Deshalb prueft dieses Skript zusaetzlich, dass die +# erwartete Advisory-Kennung tatsaechlich in der Ausgabe steht. +set -uo pipefail + +# "go install" legt Binaries in $(go env GOPATH)/bin ab — auf frischen Hosts +# ist das nicht zwangslaeufig im PATH (gefunden 2026-08-28 auf dem Testhost: +# govulncheck installierte erfolgreich, "command -v govulncheck" schlug danach +# trotzdem fehl, weil /root/go/bin nicht im PATH stand). Defensiv ergaenzen, +# statt stillschweigend als "Werkzeug fehlt" fehlzuschlagen. +export PATH="$PATH:$(go env GOPATH 2>/dev/null)/bin" + +fail=0 + +echo "=== Go-Fixture: golang.org/x/text v0.3.7, GO-2022-1059 (Symbolpfad language.ParseAcceptLanguage) ===" +if ! command -v govulncheck >/dev/null 2>&1; then + echo "govulncheck fehlt, installiere..." + # @latest kann eine govulncheck-Version verlangen, die neuer ist als die + # lokal installierte Go-Toolchain (z. B. "requires go >= 1.25.0"). Feste, + # bekannt kompatible Version statt @latest, damit die Installation nicht + # von der jeweiligen Go-Version des Hosts abhaengt. + if ! go install golang.org/x/vuln/cmd/govulncheck@v1.1.3; then + echo "FEHLER: govulncheck konnte nicht installiert werden — Pruefung nicht durchfuehrbar, kein Ersatz-'OK'." + fail=1 + fi +fi + +if command -v govulncheck >/dev/null 2>&1; then + go_output=$(cd testdata/vulnfixture-go && go mod tidy && govulncheck ./... 2>&1) + go_exit=$? + echo "$go_output" + if [ "$go_exit" -eq 0 ]; then + echo "FEHLER: govulncheck hat die bekannte Schwachstelle NICHT erkannt (exit 0 erwartet != 0)" + fail=1 + elif ! grep -q "GO-2022-1059" <<<"$go_output"; then + echo "FEHLER: exit code $go_exit ist != 0, aber die erwartete Advisory GO-2022-1059 steht NICHT in der Ausgabe — das ist vermutlich ein Werkzeugfehler (z. B. fehlendes govulncheck, Netzwerkproblem), kein echter Fund. Kein 'OK'." + fail=1 + else + echo "OK: govulncheck hat GO-2022-1059 tatsaechlich als Fund gemeldet, exit code $go_exit (!= 0, Gate wuerde blockieren)" + fi +else + # Bug (gefunden 2026-08-28): dieser Zweig druckte vorher nur eine Meldung, + # setzte aber "fail" NICHT — das Skript endete trotzdem mit Exit-Code 0 und + # "PRUEFUNG 1 BESTANDEN", obwohl der Go-Teil real nicht lief. Exakt derselbe + # Fehlerklasse (Werkzeugfehler zaehlt als Erfolg), nur eine Ebene hoeher. + echo "FEHLER: govulncheck weiterhin nicht verfuegbar — Go-Teil der Pruefung nicht durchgefuehrt, kein Ersatz-'OK'." + fail=1 +fi + +echo +echo "=== npm-Fixture: lodash 4.17.4 (mehrere bekannte kritische CVEs) ===" +npm_output=$(cd testdata/vulnfixture-npm && npm install --package-lock-only --no-audit --no-fund 2>&1 \ + && npm audit --audit-level=high 2>&1) +npm_exit=$? +echo "$npm_output" +if [ "$npm_exit" -eq 0 ]; then + echo "FEHLER: npm audit hat die bekannte Schwachstelle NICHT erkannt (exit 0 erwartet != 0)" + fail=1 +elif ! grep -qiE "severity|vulnerabilit" <<<"$npm_output"; then + echo "FEHLER: exit code $npm_exit ist != 0, aber die Ausgabe enthaelt keinen erkennbaren Schwachstellen-Hinweis — vermutlich ein Werkzeugfehler (z. B. fehlendes npm, Netzwerkproblem), kein echter Fund. Kein 'OK'." + fail=1 +else + echo "OK: npm audit hat die Schwachstelle tatsaechlich gemeldet, exit code $npm_exit (!= 0, Gate wuerde blockieren)" +fi + +echo +if [ "$fail" -eq 0 ]; then + echo "PRUEFUNG 1 BESTANDEN: beide Gates erkennen eine absichtlich verwundbare Testabhaengigkeit inhaltlich (nicht nur per Exit-Code) und wuerden blockieren." +else + echo "PRUEFUNG 1 FEHLGESCHLAGEN: siehe FEHLER oben." +fi +exit $fail diff --git a/testdata/vulnfixture-go/go.mod b/testdata/vulnfixture-go/go.mod new file mode 100644 index 0000000..65893f2 --- /dev/null +++ b/testdata/vulnfixture-go/go.mod @@ -0,0 +1,14 @@ +// Absichtlich verwundbares Fixture-Modul fuer OPS-06 Pruefung 1: beweist, dass +// der govulncheck-CI-Schritt eine bekannte Schwachstelle tatsaechlich erkennt +// und den Lauf mit Exit-Code != 0 beendet. Eigenes go.mod, damit die +// veraltete, verwundbare Abhaengigkeit NICHT im Hauptmodul landet. +module gitea.perlbach24.de/scripte/nexarch/testdata/vulnfixture-go + +go 1.22 + +// golang.org/x/text v0.3.7: GO-2022-1059 — Denial of Service durch +// uebermaessigen Ressourcenverbrauch beim Parsen von Accept-Language-Headern +// (language.ParseAcceptLanguage). Bewusst auf dieser verwundbaren Version +// gepinnt, siehe scripts/verify-supply-chain-gate.sh — main.go ruft gezielt +// den verwundbaren Symbolpfad auf, nicht nur irgendeine Funktion des Pakets. +require golang.org/x/text v0.3.7 diff --git a/testdata/vulnfixture-go/main.go b/testdata/vulnfixture-go/main.go new file mode 100644 index 0000000..2a4268f --- /dev/null +++ b/testdata/vulnfixture-go/main.go @@ -0,0 +1,22 @@ +// Fixture fuer OPS-06 Pruefung 1 — ruft tatsaechlich in die verwundbare +// Funktion hinein, damit govulncheck den Aufrufpfad (nicht nur die +// Modul-Abhaengigkeit) als erreichbar erkennt. +package main + +import ( + "fmt" + + "golang.org/x/text/language" +) + +func main() { + // ParseAcceptLanguage ist der tatsaechlich verwundbare Aufrufpfad + // (GO-2022-1059), im Unterschied zu Parse() — govulncheck bewertet + // Erreichbarkeit auf Symbol-, nicht nur Paket-Ebene. + tags, _, err := language.ParseAcceptLanguage("de-DE,de;q=0.9,en;q=0.8") + if err != nil { + fmt.Println(err) + return + } + fmt.Println(tags) +} diff --git a/testdata/vulnfixture-npm/package.json b/testdata/vulnfixture-npm/package.json new file mode 100644 index 0000000..d7e5cf1 --- /dev/null +++ b/testdata/vulnfixture-npm/package.json @@ -0,0 +1,8 @@ +{ + "name": "nexarch-vulnfixture-npm", + "private": true, + "description": "Absichtlich verwundbares Fixture-Paket fuer OPS-06 Pruefung 1 — beweist, dass npm audit eine bekannte Schwachstelle erkennt und den Lauf blockiert. Nicht Teil eines echten NEXARCH-Frontends.", + "dependencies": { + "lodash": "4.17.4" + } +}