syncova-backup/.github/workflows/ci.yml
Jerrit Fritzsche 9c48cb1c1c
Some checks failed
CI / Sicherheitsprüfungen (push) Waiting to run
CI / Backend (Go) (push) Failing after 1m47s
CI / Frontend (React/TypeScript) (push) Has been cancelled
CI: Loeschschutz messen statt annehmen, Datenbanktests wirklich fahren
Der Angriffstest auf ein gehaertetes Repository scheiterte in der CI: "rm -rf
auf ein geschuetztes Repository gelang vollstaendig". Der Befund ist richtig —
und der Fehler lag im Test, nicht im Produktivcode.

immutableFlagSupported() sagt nur, ob das Betriebssystem das
Unveraenderlich-Kennzeichen *kennt*; unter Linux gibt es immer "ja" zurueck. Ob
es auch *durchgesetzt* wird, haengt am Dateisystem und an CAP_LINUX_IMMUTABLE.
In einem Container auf overlayfs ist beides nicht gegeben: Das Setzen scheitert
still, und der Angriff gelingt.

Die Anlage selbst macht es richtig — sie ist beim Setzen nachsichtig (ein Backup
ohne technischen Loeschschutz ist besser als gar keines) und sagt die Wahrheit
ueber die gemessene Stufe. Der Test tut das jetzt auch: Er misst zuerst und
prueft nur dort, wo es etwas zu pruefen gibt. Nachgewiesen in beide Richtungen —
auf macOS laeuft der Angriff wirklich, im Container wird mit Begruendung
uebersprungen.

Zwei Luecken in der CI dabei gefunden:

- SYNCOVA_TEST_DATABASE_URL fehlte. Neun Testdateien uebersprangen ihre
  Datenbanktests still, darunter der Upgrade- und der Rollback-Test. Ein
  uebersprungener Test sieht in der Zusammenfassung aus wie ein bestandener.
- make cross-build lief nicht mit. Genau daran ist in Phase 5 monatelang
  unbemerkt geblieben, dass der Agent sich fuer Windows gar nicht uebersetzen
  liess.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:45:27 +02:00

177 lines
5.6 KiB
YAML

# Continuous Integration für Syncova.
#
# Die Pipeline muss jede Änderung prüfen, bevor sie in den Hauptzweig gelangt
# (SYNCOVA_IMPLEMENTATION_PLAN.md Phase 0).
name: CI
on:
push:
branches: [main]
pull_request:
# Ein laufender Durchlauf wird abgebrochen, sobald ein neuerer Commit erscheint.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Standardmäßig nur Lesezugriff: die Pipeline braucht keine Schreibrechte.
permissions:
contents: read
env:
GO_VERSION: '1.26'
NODE_VERSION: '22'
jobs:
backend:
name: Backend (Go)
runs-on: ubuntu-latest
services:
# Die Tests laufen gegen eine echte PostgreSQL-Instanz, nicht gegen eine Attrappe.
postgres:
image: postgres:17-alpine
env:
POSTGRES_DB: syncova_test
POSTGRES_USER: syncova_test
# Nur für diesen kurzlebigen CI-Container; die Datenbank ist von außen nicht erreichbar.
POSTGRES_PASSWORD: ci-only-ephemeral-password
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U syncova_test -d syncova_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Formatierung prüfen
run: |
UNFORMATTED_FILES="$(gofmt -l apps/api packages migrations)"
if [ -n "$UNFORMATTED_FILES" ]; then
echo "Nicht formatierte Dateien gefunden:"
echo "$UNFORMATTED_FILES"
exit 1
fi
- name: Statische Analyse
run: |
# node_modules ausschliessen: NPM-Pakete koennen eigenen Go-Code enthalten.
go vet $(go list ./... | grep -v '/node_modules/')
- name: Modulabhängigkeiten prüfen
run: |
go mod tidy
# Eine Änderung an go.mod/go.sum bedeutet: die Abhängigkeiten sind nicht eingecheckt.
git diff --exit-code go.mod go.sum
- name: Tests mit Race-Detector
env:
SYNCOVA_ENV: test
SYNCOVA_DB_HOST: 127.0.0.1
SYNCOVA_DB_PORT: '5432'
SYNCOVA_DB_NAME: syncova_test
SYNCOVA_DB_USER: syncova_test
SYNCOVA_DB_PASSWORD: ci-only-ephemeral-password
SYNCOVA_DB_SSLMODE: disable
# Nur für diesen CI-Lauf; schützt keine echten Daten.
SYNCOVA_ENCRYPTION_KEYS: 'v1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
# Ohne diese Variable überspringen neun Testdateien ihre Datenbanktests
# still — darunter der Upgrade- und der Rollback-Test. Ein übersprungener
# Test sieht in der Zusammenfassung aus wie ein bestandener.
SYNCOVA_TEST_DATABASE_URL: 'postgres://syncova_test:ci-only-ephemeral-password@127.0.0.1:5432/syncova_test?sslmode=disable'
run: go test -race -coverprofile=coverage.out $(go list ./... | grep -v '/node_modules/')
- name: Migrationen gegen echte Datenbank prüfen
env:
SYNCOVA_ENV: test
SYNCOVA_DB_HOST: 127.0.0.1
SYNCOVA_DB_PORT: '5432'
SYNCOVA_DB_NAME: syncova_test
SYNCOVA_DB_USER: syncova_test
SYNCOVA_DB_PASSWORD: ci-only-ephemeral-password
SYNCOVA_DB_SSLMODE: disable
# Nur für diesen CI-Lauf; schützt keine echten Daten.
SYNCOVA_ENCRYPTION_KEYS: 'v1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
run: |
# Der vollständige Zyklus belegt, dass Migrationen umkehrbar sind.
go run ./apps/api/cmd/syncova-migrate up
go run ./apps/api/cmd/syncova-migrate status
go run ./apps/api/cmd/syncova-migrate down
go run ./apps/api/cmd/syncova-migrate up
- name: Binaries bauen
run: go build $(go list ./... | grep -v '/node_modules/')
- name: Übersetzbarkeit aller Zielplattformen
# Der Agent liess sich in Phase 5 monatelang gar nicht für Windows
# übersetzen, ohne dass es jemandem auffiel: unix.Statfs gibt es dort
# nicht. Der Bau auf der eigenen Plattform bemerkt das nie.
run: make cross-build
frontend:
name: Frontend (React/TypeScript)
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/web
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: apps/web/package-lock.json
- name: Abhängigkeiten installieren
run: npm ci
- name: Statische Analyse
run: npm run lint
- name: Tests
run: npm run test
- name: Auslieferungs-Build
run: npm run build
security:
name: Sicherheitsprüfungen
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Bekannte Schwachstellen in Go-Abhängigkeiten
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck $(go list ./... | grep -v '/node_modules/')
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: apps/web/package-lock.json
- name: Bekannte Schwachstellen in NPM-Abhängigkeiten
working-directory: apps/web
run: |
npm ci
# Nur hohe und kritische Befunde brechen den Lauf ab.
npm audit --audit-level=high