Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
43 KiB
phase, plan, status, tasks_done, plan_head_before, plan_head_after, commits, actuals
| phase | plan | status | tasks_done | plan_head_before | plan_head_after | commits | actuals | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-261009-p0m | 01 | complete |
|
d15a470c5a |
b085889657 |
9 |
|
Quick 261009-p0m: Sicherheitsprotokoll + CI-Sicherheitspruefungen -- Summary
Task 1: Tracer -- Job security als reiner Bericht (erledigt)
Commit: 3d00be8 ci(quick-261009-p0m): Sicherheitspruefung als reiner Bericht in der Pipeline (nicht gepusht)
Dateien im Commit: .gitea/scripts/security-scan.sh (neu, ausfuehrbar), .gitleaks.toml (neu), .semgrepignore (neu), .gitignore, .dockerignore, .gitea/workflows/ci.yml (nur Anhaengen: Kopfzeile + Job security, keine andere Zeile geaendert), docs/ci-cd-setup.md (§4 fuenf Jobs, Unterabschnitt, §6-Eintrag).
Nicht eingecheckt (Vorgabe des Orchestrators, alles unter .planning/ bleibt unversioniert): baseline/.gitignore, baseline/SUMMARY.txt (Block "nach Ausnahmelisten"), checks/task1-runner-full.txt, diese Datei.
Gates (alle gruen, Sentinel task1 ok gedruckt)
- ci.yml per js-yaml geparst: Jobs
quality,test,desktop,publish,security;needs: publish,continue-on-error: true,timeout-minutes: 30(Auflage des Plan-Checkers, Gate erweitert), Bedingung main/Tags v*, keinsecrets.im Job, kein anderer Job haengt ansecurity, jederrunendet auf|| true,fetch-depth: 0,upload-artifact@v3mitcontinue-on-error. --print-plan: main ->api:beta/web:beta,v9.9.9->api:live, Zweiglive->scan-image keine .....gitleaks.tomlstrukturell (tomllib):useDefault, jede Liste mit Beschreibung; nur das Fixture-Verzeichnis als Ordner, alles andere einzelne verankerte Datei mittargetRules;de.jsonzusaetzlichcondition=AND+regexTarget=line+ Regex auf die eine Zeile"authMethodPassword": "Benutzer/Passwort".- gitleaks ueber die volle Historie (1369 Commits inkl. neuem Commit): 0 Treffer (vorher 20).
- Voller Lauf im echten Runner-Abbild
gitea/runner-images:ubuntu-latest(Netzgitea, Socket-Mount, frisches Werkzeug-Volume, Wegwerf-Klon mit Kanarienvogel-Token): rc=0, gitleaksfindings=1(nur Kanarienvogel, github-pat), trivy-fssecrets=1(nur Kanarienvogel), alle uebrigen Werkzeuge und beide Abbilder gezaehlt -> Annahme A1 bestaetigt (Job-Container scannt Abbilder des Host-Daemons). Semgrep per pipx im Container installiert und gelaufen. - Offline-Lauf (
--network none, schreibgeschuetzter Klon): rc=0, 12skipped reason=-Zeilen (>= 7 verlangt). - Host-Installation: gitleaks 8.30.1, trivy 0.75.0, osv-scanner 2.6.0 liegen in
~/.cache/tessera-security(Semgrep dort uebersprungen: kein pipx). pnpm 9.15.0 aus dem PATH. - Wegwerf-Klon, Volume und root-eigene Berichte entfernt; Token steht in keiner Datei ausserhalb des Klons (geprueft:
ghp_in der Nachweisdatei = 0 Treffer).
Zahlen nach Ausnahmelisten (Details in baseline/SUMMARY.txt)
gitleaks 0; pnpm audit --prod C5 H73 M68 L5; osv-scanner 56 (pnpm-lock + Cargo.lock; Grundlinie 43 nur pnpm-lock); Semgrep 34 Treffer (ERROR 2, WARNING 29, MEDIUM 3) / 4 Scanfehler (PartialParsing, 0 Zeitueberschreitungen), vorher 58/59; trivy-fs C5 H73 M70 L5, misconfig 2, secrets 0; trivy-image api C6 H116 M99 L7, web C2 H19 M22 L1.
Deviations from Plan
- [Orchestrator-Vorgabe] Nichts unter
.planning/eingecheckt. Der Plan nenntbaseline/.gitignore,baseline/SUMMARY.txtundchecks/task1-runner-full.txtals Commit-Dateien; sie liegen auf der Platte, bleiben aber unversioniert. Gates lesen sie von der Platte und sind gruen. - [Rule 2 / Plan-Checker]
timeout-minutes: 30am Job ergaenzt (im Plan nicht vorgesehen), Gate unddocs/ci-cd-setup.md(Unterabschnitt + §6) sind angepasst. - Trivy-Ausnahme fuer die Testschluessel liegt als zur Laufzeit erzeugte
trivy-secret.yaml(allow-rule auf den Fixture-Ordner) im Arbeitsordner des Skripts, nicht als Repository-Datei; wirkt nur auf den Secret-Scanner (trivy-fs secrets 7 -> 0, Kanarienvogel weiterhin gefunden). - Der Skript-Aufruf
allrechnet Semgrep-Zeitlimit pro Regel/Datei--timeout 20(Plan: "per-file timeout"); Semgrep kennt nur dieses eine Limit.
Hinweise fuer Task 2 (Protokoll)
- Zahlen "roh" aus
baseline/SUMMARY.txt(oberer Teil) und "nach Ausnahmelisten" (unterer Block "nach Ausnahmelisten (2026-10-09, Task 1)"). Unterschied osv: 43 (nur pnpm-lock) vs. 56 (mit Cargo.lock). Semgrep roh 58 -> 34; die 4 Scanfehler sind alle PartialParsing (ci.yml, beide Dockerfiles), keine Zeitueberschreitungen mehr. - Abbild-Zaehlung des Skripts summiert OS- und Node-Pakete (api M99, web M22; Forschung nannte M98/M21 nur Node + je 1 Alpine).
- Neue Dateien:
.gitleaks.toml(6 Ausnahmegruppen),.semgrepignore; ci-cd-setup.md beschreibt Version-Anheben-Rezept (Version + URL + SHA256 gemeinsam). - Hostwerkzeuge liegen bereit (Precondition von Task 2 erfuellt:
git log -- .gitea/scripts/security-scan.shzeigt 3d00be8;gitleaks version-> 8.30.1). - Erster echter CI-Lauf steht aus (Orchestrator/Nutzer-Checkliste nach dem Push): Job
securitymuss gelb/gruen laufen,SECURITY-SUMMARY-Zeilen erscheinen,upload-artifact@v3ist best effort (Annahme A4 ungeprueft). Der Skript-Lauf ist bis auf den Artefakt-Schritt im Runner-Abbild nachgestellt. - Plattenstand nach Task 1: 80 % (36 GB frei), unter der 85-%-Schwelle.
- Der Eintrag
semgrep ... skipped reason=kein-pipxauf dem Host ist erwartet.
Task 2: Sicherheitsprotokoll, Verweise, Pflegeregel, CHANGELOG (erledigt)
Commit: 5b36b9a docs(quick-261009-p0m): Sicherheitsprotokoll mit Bestandsaufnahme und erster Vollpruefung (nicht gepusht)
Dateien im Commit: docs/sicherheitsprotokoll.md (neu, 227 Zeilen), docs/README.md (Absatz "Ebenfalls dabei"), docs/anleitung-betrieb.md (Satz im Kopf + Absatz in Kapitel 8 "Automatische Sicherheitspruefung"), docs/anleitung-entwicklung.md (Inhaltsverzeichnis 9 = Sicherheitspruefungen, 10 = Konventionen; neuer Abschnitt mit "So pflegen Sie dieses Protokoll", "Die Pruefung in der Pipeline", "Pruefungen von Hand wiederholen", "Ausnahmelisten"), CHANGELOG.md (ein Bullet "Sicherheit: ..." unter Neu; keine vierte Gruppe).
Nicht eingecheckt (Vorgabe): checks/link-check.py (liegt auf der Platte), diese Datei.
Gates (Sentinel task2 ok gedruckt)
- Alle sieben Ueberschriften exakt, alle 20 Schluesselwoerter, keine Du-Form, kein "Lizenz", kein "Mandant" im Protokoll (strenger als verlangt), " Sie " vorhanden.
- gitleaks
dirauf das Protokoll: keine Funde. Link-Pruefer: 8 Links geprueft, 0 kaputt (Anker#sicherheitsprüfungenaufgeloest). - CHANGELOG: nur Neu/Geaendert/Behoben, Bullet "- Sicherheit: ... Sicherheitsprotokoll ...".
Inhalt des Protokolls (fuer die Folgeaufgaben wichtig)
- Abschnitte: Auf einen Blick, So lesen Sie, Wie die Pruefungen arbeiten (Unterabschnitte je Werkzeug), Bisherige Sicherheitspruefungen (Tabelle der acht Pruefungen, Haertung Adressschutz 09.10., Bedrohungsbetrachtungen 179 Plaene / 884 Kennungen frisch ausgezaehlt, Datentrennung als bestehender Schutz ohne Schaltzustand, Tabelle weiterer Auftraege, Fehlerregister, Tests, "Was es bisher nicht gab"), Erste vollstaendige Pruefung (Tabelle roh / nach Ausnahmelisten), Einordnung der Befunde (23 Zeilen, alle Abhaengigkeits-Zeilen noch "offen"), Verlauf (5 Eintraege, neueste oben).
- Task 3 muss ergaenzen: Unterabschnitt "Aussenpruefung (ZAP)" unter "Wie die Pruefungen arbeiten", Verlauf-Eintrag fuer den ersten ZAP-Lauf (oben), "Auf einen Blick", Kapitel 9 der Betriebsanleitung. Das Protokoll nennt den Alpha-Hostnamen bewusst noch nirgends.
- Tasks 4/5/6 muessen Stand-Spalte der Zeilen von "offen" auf "behoben (Datum)" setzen: Next.js, proxy-addr, handlebars (Paket entfernt), nodemailer, undici, multer, adm-zip 0.6.1, "Uebrige Bausteine", Entwicklungswerkzeuge im api-Abbild, npm im web-Abbild, rustls, AES-GCM-Tag; Zeilen xlsx, node-forge, glib bleiben offen; Abschnitt "Stand nach der Behebung" mit den Zahlen der Abschlussmessung; "Auf einen Blick" und Verlauf nachziehen. Die Zeile "Fehlende Gesundheitspruefung web" steht auf "offen".
- Wahrheitsgehalt der Bestandsaufnahme (aus den Dateien/Git nachgeprueft): Phase 08 Fix in
eebceb2(CR-01, CR-02, WR-01..05, IN-01 behoben; IN-02/IN-03 weiter offen, im Code bestaetigt); Phase 16 vier Warnungen behoben, IN-01/IN-02 offen (im Code bestaetigt); Phase 18 vier behoben, zwei Hinweise nicht bearbeitet; dts IN-01/IN-02/IN-04 uebersprungen (Datenbankaenderung/Entwurf noetig); dkv alle 11 inkl. EXTRA behoben; ikt alle 15 behoben. Summe 89 Befunde: 76 behoben, 13 Hinweise offen. Fehlerregister: 39 Eintraege, 25 behoben, 1 zurueckgestellt, 13 offene gehoeren alle zur Datentrennung zwischen Organisationen und werden im Protokoll nur in einem Satz erwaehnt (D-07). - Triage-Fakten, die ich gegen die Rohdaten geprueft habe: adm-zip-Meldung ohne Korrektur ist "Mittel" (Symlinks beim Entpacken); node-forge-Meldung betrifft die Pruefung von Unterschriften; xlsx: Prototype-Pollution und ReDoS;
trust proxywird im Quelltext nirgends gesetzt.
Deviations (Task 2)
Keine fachliche Abweichung. Kleine Anmerkung: Der Plan nennt .planning/ nicht als Commit-Ort fuer link-check.py; er bleibt gemaess Orchestrator-Vorgabe unversioniert und das Gate liest ihn von der Platte. Die Anhaengsel-Zeile der Anlage des Commits nutzt wie verlangt die Opus-Zeile als Trailer.
Hinweise fuer Task 3
- Hostwerkzeuge liegen bereit. Das Protokoll wartet auf den ZAP-Teil (siehe oben).
link-check.pykann nach jeder Aenderung der Dokumente wiederholt werden (python3 -I .planning/quick/261009-p0m-sicherheitsprotokoll-und-ci-sicherheitsp/checks/link-check.py). - Beim Ergaenzen von Kapitel 9 der Betriebsanleitung den Anker-Stil beibehalten: Querverweise im Protokoll zeigen auf
anleitung-entwicklung.md#sicherheitsprüfungen. - Wortregeln fuer das Protokoll beibehalten (Gate von Task 2 prueft sie nicht fuer Task 3): Sie-Form, kein "Lizenz", kein "Mandant", keine internen IPs.
Task 3: ZAP-Grundpruefung (erledigt, mit Abweichung beim Ziel)
Commit: 13571df ci(quick-261009-p0m): ZAP-Grundpruefung gegen alpha vor Freigaben, erster Lauf (nicht gepusht)
Dateien im Commit: .gitea/scripts/zap-baseline.sh (neu, ausfuehrbar), .gitea/scripts/zap-hooks.py (neu), docs/sicherheitsprotokoll.md, docs/anleitung-betrieb.md (Kapitel 9, Schritt 2 "Pruefung von aussen" vor "Zusammenfuehren und taggen"), docs/anleitung-entwicklung.md (Unterabschnitt "Pruefung von aussen (ZAP)"), CHANGELOG.md (Sicherheits-Bullet um die Aussenpruefung ergaenzt). Nicht eingecheckt (Vorgabe): checks/zap-testserver.py, checks/task3-zap-local.txt, checks/zap-alpha-2026-10-09.txt, baseline/SUMMARY.txt (ZAP-Zeile angehaengt), diese Datei. baseline/zap-hook-basic-auth.py geloescht.
Abweichung (Orchestrator-Entscheidung)
Die oeffentliche Adresse von alpha war vom Dev-Host nicht erreichbar (Zeitueberschreitung auf Port 443, 3 Versuche; allgemeines Internet ging). Auf Anweisung des Orchestrators wurde der erste Lauf direkt gegen die Anwendung auf alpha ohne Proxy ausgefuehrt (interne Adresse, Port 3000, /login = 200, Version per /api-proxy/health/version: v1.10.1-80-gd15a470, Kanal beta). Das Skript hat das Ziel als Parameter ZAP_TARGET (Standard weiter die oeffentliche Adresse). Im Protokoll steht nirgends die IP, nur "interne Adresse des Testservers"; das Protokoll sagt ausdruecklich, dass der Lauf ueber die oeffentliche Adresse noch folgt. Das Gate wurde angepasst (ZAP-SUMMARY-Zeile mit beliebigem Ziel statt festem Hostnamen; zusaetzliche Pruefungen: keine private IP in den Docs, keine Du-Form/Lizenz/Mandant, gitleaks auf dem Protokoll). Sentinel task3 ok gedruckt.
Lokaler Beweis (Passivitaet)
Testserver mit POST-Formular, ZAP ueber die Docker-Bruecke, ZAP_SPIDER_MINUTES=1: lauf-ohne-anmeldung POST=0 GET=8; lauf-mit-anmeldung POST=0 auth_ja=8 auth_nein=1 (die eine Anfrage ohne Kopf ist die Vorabpruefung des Skripts). Auch der Hakenweg fuer die Anmeldedatei funktioniert. Beim Test fiel auf und wurde behoben: bei vorzeitigem Abbruch (SIGPIPE) blieben die temporaeren Dateien mit dem Kopf liegen, deshalb wird die Umgebungsdatei jetzt sofort nach dem Container-Lauf entfernt und die Falle faengt auch HUP/PIPE ab (beide Reste von /tmp geloescht). Der Bericht enthaelt bei Nutzung der Anmeldedatei die gesendeten Kopfzeilen samt Zugangsdaten (in Skript-Kopf und Entwicklungsanleitung vermerkt; Berichte liegen nur in security-reports/, ignoriert).
Erster Lauf gegen alpha (2026-10-09 19:41, Ziel: Anwendung direkt, 28 URLs, 0 POST)
ZAP-SUMMARY: hoch 0, mittel 2, niedrig 6, info 3 (11 Meldungsarten).
- Mittel: fehlende Content-Security-Policy; fehlender Schutz gegen Einrahmen (Clickjacking) -- beide auf /login, /reset-password.
- Niedrig: Cross-Origin-Embedder-/Opener-/Resource-Policy fehlen; Permissions-Policy fehlt; X-Content-Type-Options fehlt; X-Powered-By (Next.js-Standard).
- Info: Content-Type fehlt (Umleitungen 307 fuer nicht angemeldete Besucher), nicht speicherbar, speicherbar.
- Einordnung im Protokoll: Kopfzeilen = offen ("Aufgabe des Proxys, beim oeffentlichen Lauf erneut pruefen; sonst in der Anwendung setzen";
next.config.tssetzt keine Kopfzeilen und keinpoweredByHeader: false), HTTPS/HSTS = nicht beurteilt, offen (Proxy), Infos = bewusst akzeptiert. Es wurde kein Tessera-Code und keine Proxy-Konfiguration geaendert.
Hinweise fuer Task 4 und folgende
- Protokoll: neue Tabelle "Pruefung von aussen gegen alpha" und fuenf neue Zeilen in "Einordnung der Befunde" (Kopfzeilen mittel/niedrig, X-Powered-By, HTTPS/Proxy, Infos); Verlaufseintrag steht oben. Task 6 soll "Auf einen Blick" (Bullet "Pruefung von aussen") und diese Zeilen nachziehen; ein spaeterer Lauf ueber die oeffentliche Adresse waere eine weitere Tabellenzeile + Verlaufseintrag.
- Angebot an den Nutzer (nicht ausgefuehrt, kein Auftrag):
poweredByHeader: falseund Sicherheits-Kopfzeilen inapps/web/next.config.tswaeren eine kleine, sichere Haertung; vorher klaeren, ob der Proxy sie schon setzt. link-check.pylaeuft gruen (11 Links). Hostwerkzeuge und das ZAP-Abbild (3.8 GB, per Digest) liegen lokal; Plattenstand 80 %.
Task 4: Abhaengigkeiten innerhalb der Hauptversionen (erledigt)
Commit: cf982e9 fix(quick-261009-p0m): Abhaengigkeiten innerhalb der Hauptversionen aktualisiert, zwei unbenutzte entfernt (nicht gepusht)
Dateien im Commit: package.json (neu: pnpm.overrides, 15 Eintraege), pnpm-lock.yaml, apps/api/package.json, apps/web/package.json, apps/api/src/mail/mail.module.ts und apps/api/src/calendar/providers/exchange.provider.ts (nur falsch gewordene Kommentare), apps/desktop/src-tauri/Cargo.lock, docs/sicherheitsprotokoll.md, docs/anleitung-entwicklung.md (neuer Abschnitt ### Abhängigkeiten aktualisieren), CHANGELOG.md (dritter "Sicherheit:"-Bullet unter Behoben). Nicht eingecheckt (Vorgabe): checks/mail-smoke.sh, checks/task4-audit.txt, diese Datei.
Audit vorher / nachher (checks/task4-audit.txt)
| critical | high | moderate | low | gesamt | |
|---|---|---|---|---|---|
| prod vorher | 5 | 73 | 68 | 5 | 151 |
| prod nachher | 0 | 9 | 3 | 0 | 12 |
| alle vorher | 7 | 85 | 74 | 5 | 171 |
| alle nachher | 2 | 9 | 5 | 0 | 16 |
Verbleibend prod (12): xlsx 2 hoch (keine Korrektur), node-forge 1 hoch (keine Korrektur), sharp 3 hoch (Korrektur erst 0.35 = andere 0.x-Minor), deepmerge-ts 1 hoch (Prisma-Werkzeugkette, Korrektur erst v8), nodemailer 2 hoch + 3 mittel (Korrektur erst in nodemailer 10 = neue Hauptversion). Verbleibend nur dev: tinypool 1.1.1 (2 kritisch) + vitest/@vitest/mocker 3.2.6 der API (2 mittel), Korrektur jeweils nur in neuer Hauptversion (vitest 4 / tinypool 2).
Was geaendert wurde
- Entfernt:
@nestjs-modules/mailer,ews-javascript-api(vorher per grep nachgewiesen: kein Import inapps/; Exchange bleibt httpntlm + rohes SOAP). 232 Paketnamen entfallen aus dem Lockfile. - Direkt angehoben: next ^15.5.27 (installiert 15.5.27); @nestjs/common/core/platform-express ^11.2.7 (multer 2.4.0); nodemailer ^9.1.1; undici exakt 7.30.0; adm-zip ^0.6.1; csv-parse ^7.0.3; vitest (web) ^4.1.11 (noetig, weil @vitest/mocker < 4.1.11 gemeldet).
- Overrides (alle innerhalb derselben Hauptversion, 15 Stueck): baseline-browser-mapping, brace-expansion (1.x und 5.x), browserslist 4, fast-uri 3, ip-address 10, js-yaml 4, nanoid 3, nodemailer 9, postcss 8, proxy-addr 2, qs 6, source-map-js 1, underscore 1, undici 7 (auf 7.30.0, damit nur eine undici-Kopie im Baum bleibt). Selektorform
name@>=N <N+1(bzw.<2fuer brace-expansion 1.x) wirkt; per Lockfile geprueft. - Prisma weiter 6.19.3, Next 15, NestJS 11, React 19.2.7.
- rustls 0.23.41 -> 0.23.45;
cargo update -p rustls --precisezog zusaetzlichrustls-webpki0.103.13 -> 0.103.15 mit.cargo checkundcargo clippyfehlerfrei, keine Warnungen. - Nichts musste zurueckgepinnt werden (kein Baustein als "offen wegen Bruch").
Neue-Namen-Pruefung (T-p0m-SC)
Vergleich der Paketnamen der packages:-Sektion vor/nach: 0 neue Namen, 232 entfallen. Kein Vater noetig. (Neue Versionen vorhandener Namen sind keine neuen Namen.)
Gates (Sentinel task4 ok gedruckt, Kette aus dem Plan wortgetreu)
frozen-Lockfile-Install, Versionspruefung (pakete ok), rustls 0.23.45, cargo check/clippy, pnpm type-check, pnpm lint, API-Tests 169 Dateien / 3573 Tests, Web-Tests 160 Dateien / 1945 Tests, Audit nachher (0 kritisch, 9 < 73 hoch), docker compose up -d --build --wait api web, /login = 200, e2e-changelog, e2e-preload-api, e2e-cert all, nc-test-setup, e2e-files, e2e-transfer, e2e-shares all, mail-smoke (mail ok), Anleitungs-Ueberschrift, >= 3 "Sicherheit:"-Bullets. Link-Pruefer: 11 Links, 0 kaputt.
Deviations (Task 4)
- [Rule 1]
checks/mail-smoke.shliest die E-Mail-Adresse ausGET /users, nicht aus/auth/me./auth/meliefert kein E-Mail-Feld (Plan-Annahme falsch);/users(als admin) liefert es. Der Test vorher auf dem unveraenderten Stack gruen (mail ok), danach ebenfalls; Mailhogtotalwaechst. - Rate-Limit beim Rerun: Ein zweiter Lauf von
e2e-shares.shinnerhalb weniger Minuten laeuft in das Anlegelimit (tooManyShares, 429, 320 s). Kein Fehler im Code; nach 5,5 Minuten Pause lief die Kette komplett gruen. Bei jedem Wiederholen: erst warten. - vitest (web) ^4.1.11 zusaetzlich zu den im Plan genannten Bumps (Audit meldete @vitest/mocker unter 4.1.11); Minor-Bump im selben Major, alle Web-Tests gruen.
- Protokoll in Task 4 laut Plan aktualisiert (Verlauf, Zeilen in "Einordnung der Befunde", "Auf einen Blick"); Zeile "Mailversand nodemailer" bleibt "offen" (Rest nur mit Hauptversion 10), Zeile "Übrige Bausteine" aufgeteilt in "behoben" und eine neue "offen"-Zeile fuer sharp und deepmerge-ts.
Hinweise fuer Task 5 und 6
- Stack laeuft aus Task 4 gebaut (api, web, db, mailhog healthy); Plattenstand 80 % nach
docker image prune -f(vorher kurzzeitig 84 %). - Protokoll-Zeilen noch zu schliessen: "Entwicklungswerkzeuge im Server-Abbild", "Paketverwalter npm im Node-Grundabbild" (Task 5), "Laenge der Echtheitspruefung bei AES-GCM" (Task 5); Task 6 muss "Stand nach der Behebung" mit den Abschlusszahlen, "Auf einen Blick" (Bullet "Was noch zu tun ist" nennt bereits Abbilder + AES-GCM) und Verlauf nachziehen. Offen bleiben: xlsx, node-forge, glib, nodemailer (Hauptversion 10), sharp, deepmerge-ts, Gesundheitspruefung web, Kopfzeilen/HTTPS.
- Die Abbild-Trivy-Zahlen im Protokoll ("Erste vollstaendige Pruefung") sind noch die Rohwerte; Task 6 misst die neuen.
- Der Rest der api-Abhaengigkeiten ist unveraendert; die alten Trivy-Abbild-Zaehlungen (api C6 H116) sinken durch Task 4 bereits deutlich -- erst die Abschlussmessung zeigt es.
- CLAUDE.md-Zeilen (D-26), die jetzt hinterherhinken (nicht angefasst): Next.js 15.5.19 -> 15.5.27; NestJS 11.1.27 -> 11.2.7; Vitest (apps/web) 4.1.9 -> 4.1.11. Express 5.2.1 und Prisma 6.19.3 unveraendert. Der Eintrag "Prisma: pin exactly" stimmt weiter (Lockfile 6.19.3;
package.jsonhat^6.0.0, das war schon vorher so). - Im Desktop-Lockfile hat sich
Cargo.lockgeaendert: der naechste CI-Push auf main baut die Desktop-Pakete neu (erwartet, D-24). - Die Dev-Bausteine tinypool/vitest 3 (API-Tests) sind nur mit einem vitest-4-Wechsel der API zu beheben (neue Hauptversion der Testwerkzeuge, nicht Teil dieses Auftrags); im Protokoll ist das als Verlaufsnotiz genannt, aber nicht als eigene Tabellenzeile.
- Orchestrator-Frage fuer spaeter: nodemailer 10 ist die groesste uebrige Produktionsposition (2 hoch, 3 mittel); ein Wechsel waere ein eigener kleiner Auftrag (Nutzung beschraenkt auf
createTransport/sendMail).
Task 5: AES-GCM-Tag, Laufzeitabbilder ohne Entwicklungswerkzeuge, Schutz-Kopfzeilen (erledigt)
Commits (nicht gepusht):
072f955fix(quick-261009-p0m): AES-GCM-Entschluesselung verlangt 16-Byte-Tag (Teil A, Tests zuerst rot)2a8a7d4build(quick-261009-p0m): Laufzeitabbilder ohne Entwicklungswerkzeuge (Teil B + Doku)fceec19fix(quick-261009-p0m): Schutz-Kopfzeilen in der Weboberflaeche, X-Powered-By abgeschaltet (Zusatzauftrag des Orchestrators)
Nicht eingecheckt (Vorgabe): checks/task5-image.txt, checks/fresh-db-start.sh, diese Datei.
Teil A (AES-GCM)
Tests zuerst: 5 neue Faelle in crypto.service.spec.ts (4 Byte, 17 Byte, leer, gekipptes Bit, Rundlauf inkl. leerem Text und Umlauten). Vor der Aenderung 3 rot (4 Byte, 17 Byte, leer); echt unsicher war nur der 4-Byte-Fall (Node akzeptierte ihn und entschluesselte), 17 Byte und leer warf Node schon, aber mit anderer Meldung als die neue 16 bytes-Pruefung (daher rot); das gekippte Bit wurde schon vorher abgelehnt. Danach 13/13 gruen. decrypt prueft authTag.length === 16 vor dem Decipher und uebergibt authTagLength: 16 (auch bei createCipheriv, Ausgabe unveraendert). biome format --write + biome check --write (sortierte die Imports und brach alte Zeilen im Spec auf 100 Zeichen um, das Format der Projektkonfiguration; daher groesserer Diff im Spec als nur die neuen Tests).
Teil B (Abbilder) -- umgesetzt, kein Rueckbau noetig
apps/api/Dockerfile: neue Stufeprod-deps(kopiert Manifeste, Lockfile, Workspace-Datei undapps/api/prisma/, dannpnpm install --frozen-lockfile --prod --filter=@tessera/api...; derpostinstallvon apps/api erzeugt den Prisma-Client dort, weilprismaindependenciesliegt). LaufzeitstufeFROM node:24-alpine, entfernt als Erstes/usr/local/lib/node_modules/{npm,corepack},/opt/yarn-v1.22.22,/usr/local/bin/{npm,npx,corepack,yarn,yarnpkg};node_moduleskommen ausprod-deps; die lange.prisma-COPY-Zeile mit festem Pfad entfaellt.apps/web/Dockerfile: nur dieselbe Entfernung in der Laufzeitstufe.- Groessen und Fundzahlen (
checks/task5-image.txt, Trivy 0.75.0--scanners vuln,--image-src docker, Betriebssystem + Node-Pakete):
| Abbild | Groesse vorher | nachher | critical | high | medium | low |
|---|---|---|---|---|---|---|
| api vorher (nach Task 4) | 1,59 GB (1592651888 B) | 3 | 45 | 41 | 2 | |
| api nachher | 1,12 GB | 0 | 6 | 4 | 0 | |
| web vorher (nach Task 4) | 359 MB | 0 | 11 | 13 | 1 | |
| web nachher | 359 MB | 0 | 3 | 1 | 0 |
Die Web-Groesse bleibt gleich: rm in einer spaeteren Schicht verkleinert das Abbild nicht (nur die Sicht von Trivy); das ist im Protokoll so erklaert und die Doku verspricht "kleiner" nur fuer das Server-Abbild. Die Rohwerte der ersten Messung im Protokoll (api C6 H116, web C2 H19) bleiben dort als "Erste vollstaendige Pruefung"; Task 6 misst neu.
- Gates (Sentinel
task5 ok, Kette aus dem Plan wortgetreu, Logscratchpad/task5-gate.log): Crypto-Tests, biome,authTagLengthvorhanden,tsc --noEmit, komplette API-Tests,docker compose up -d --build --wait api web,/login= 200,@prisma/clientloest aus/app/apps/apiauf,nodeim web-Container, keine Paketverwaltung in api und web, keine Entwicklungswerkzeuge in/app/node_modules/.pnpm(vitest, tinypool, turbo, biome, Nest-CLI, schematics: alle weg),@prisma+client@vorhanden,fresh-db-start.sh->migrationen=63,frische-datenbank ok, Fundzahl nachher < vorher, "keine Paketverwaltung" in der Betriebsanleitung, e2e-cert all, e2e-changelog, nc-test-setup, e2e-files, e2e-transfer, mail-smoke (mail ok), "Zugangsdaten"-Bullet, Link-Pruefer (12 Links, 0 kaputt). Zusaetzlich vorab ein eigener Lauf der e2e-Kette (E2E-ALL-OK). - apk (Paketverwaltung des Betriebssystems) bleibt im Abbild; die Vorgabe nannte nur npm, npx, corepack und yarn.
- Rueckbau/Fallback: nicht benutzt. Keine devDependency wird zur Laufzeit importiert (Start gegen frische DB und alle Rauchtests gruen).
Zusatzauftrag: Schutz-Kopfzeilen (eigener Commit fceec19)
apps/web/next.config.ts:poweredByHeader: falseundheaders()fuer/:path*:X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin,X-Frame-Options: SAMEORIGIN,Content-Security-Policy: frame-ancestors 'self'(nur diese Richtlinie),Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(),Cross-Origin-Opener-Policy: same-origin-allow-popups. Keine COEP/CORP (koennten eingebettete Bilder/Kacheln sperren, nichts zu schuetzen).- Vorpruefung im Code: Zwischenablage nur
clipboard.writeText(clipboard-write bleibt erlaubt, perfeaturePolicyim Browser bestaetigt: clipboard-write und fullscreen true, camera und geolocation false); Benachrichtigungen haben keine Permissions-Policy-Direktive; keine Nutzung von getUserMedia/Geolocation/Zahlung/USB. Allewindow.open/target=_blanktragennoopener; keinwindow.opener,postMessageoderBroadcastChannelim Web-Quelltext -> COOP sicher. Nextcloud Login Flow v2 ist ein einfacher<a target=_blank rel=noopener>(Abfrage laeuft serverseitig). Desktop: Tauri navigiert das Hauptfenster direkt auf die Server-Adresse (window.navigate), kein Rahmen. XFrame-Kacheln/eigene Module setzensandboxundallow=""und rahmen fremde Seiten ein -- die Kopfzeilen von Tessera betreffen nur das Einrahmen von Tessera. - API: Express sendete
X-Powered-By: Express(vorher percurl -Ibestaetigt).configureHttpruft jetztapp.disable('x-powered-by')(TypHttpAppaufNestExpressApplication,main.tserzeugtNestFactory.create<NestExpressApplication>); Test inhttp-setup.spec.ts(der Test "Anfragelog und Cookies kommen zuerst" ignoriert diedisable-Aufrufe). - Tests: neu
apps/web/src/next-config.test.ts(4 Faelle; eine Konfigurationsdatei-Test gab es vorher nicht). Web-Suite gesamt 161 Dateien / 1949 Tests,pnpm lint,pnpm type-checkgruen. - Pruefung am neu gebauten lokalen Stack:
curl -I /login,/(307) und 404-Seiten tragen alle Kopfzeilen, keinX-Powered-Bybei Web und API (auch nach dem Neubau auf HEAD erneut geprueft). Der Pfad/api-proxy/...(Umleitung zur API) traegt die Web-Kopfzeilen nicht, nur die Antwort der API; sie sind fuer JSON-Antworten nicht noetig, ZAP hat sie dort nicht beanstandet (nur auf/login,/reset-password). - Browser (Playwright-Kern, headless Chromium, Dunkelmodus,
scratchpad/smoke/*.cjs): Anmeldung und Dashboard, 0 Konsolenmeldungen (kein Hinweis auf unbekannte oder verletzte Richtlinien); Zertifikatsmanager laedt, Testzertifikat + Schluessel hochgeladen, "Fullchain herunterladen" liefertp0m-smoke.test-fullchain.pem; Dateien: "Im Browser anmelden" -> Link oeffnet neuen Tab auf.../login/v2/flow,window.opener === null; eigenes Modul (https://example.com/) im Rahmen geladen (Modul danach geloescht, API 200). Der MCP-Browser stand dem Agenten nicht zur Verfuegung, daher das Playwright-Paket aus dem npx-Cache. - Protokoll: Zeilen "Fehlender Schutz gegen Einrahmen", "Weitere fehlende Schutz-Kopfzeilen", "X-Powered-By" jetzt "behoben in der Anwendung, beim oeffentlichen Lauf erneut pruefen"; neue Zeile "Vollstaendige Inhaltsrichtlinie (Content Security Policy)" = offen mit Grund; "Auf einen Blick" (Bullet Pruefung von aussen) und Verlaufseintrag "Schutz-Kopfzeilen in der Anwendung". CHANGELOG: ein "Sicherheit:"-Bullet unter "Geaendert". Entwicklungsanleitung: Absatz "Schutz-Kopfzeilen der Weboberflaeche" unter "Konventionen und Fallstricke" (inkl. Warnung: clipboard-write nie sperren;
noopenerbeibehalten).
Abweichungen (Task 5)
- [Rule 3] Dokumentation getrennt committet: Die Doku von Teil B und die des Zusatzauftrags liegen in denselben Dateien; fuer zwei saubere Commits wurden die Zusatz-Hunks fuer den ersten Commit voruebergehend herausgenommen und danach wiederhergestellt (kein Inhaltsverlust, beide Commits einzeln pruefbar).
- Teil A:
biome check --writesortierte die Imports incrypto.service.tsum (Biome-RegelorganizeImports), undbiome formatbrach alte Zeilen im Spec um. Verhalten unveraendert. - Die CHANGELOG-Aenderung kam nach dem ersten Bau; deshalb wurde der Stack nach dem letzten Commit nochmals mit
--buildneu gebaut (Voraussetzung von Task 6).
Hinweise fuer Task 6
- Stack laeuft gebaut aus HEAD
fceec19(docker compose up -d --build --wait api webnach dem letzten Commit, alle healthy). Lokale Abbilder:tessera-ctl-api:latest1,12 GB,tessera-ctl-web:latest359 MB; fuer den AbschlusslaufSCAN_IMAGES="tessera-ctl-api:latest tessera-ctl-web:latest"verwenden. Erwartung der Skriptzaehlung (OS + Node, nicht--scanners vuln-identisch, kann abweichen): api ~C0 H6, web ~H3. - Protokoll noch zu schliessen in Task 6: "Stand nach der Behebung" mit Abschlusszahlen; die Tabelle "Erste vollstaendige Pruefung" behaelt die Rohwerte. Alle Zeilen "Einordnung der Befunde" haben jetzt einen Status; "offen" bleiben xlsx, node-forge, glib, nodemailer 10, sharp/deepmerge-ts, Gesundheitspruefung web, Vollstaendige Inhaltsrichtlinie, HTTPS/Proxy, Pnpm-Arbeitsbereichseinstellungen u. a.; die drei neuen Statuswoerter "behoben in der Anwendung, beim oeffentlichen Lauf erneut pruefen" enthalten das Wort "behoben" und passen auf die Task-6-Zeilenpruefung (Status + letzte Spalte nicht leer). Task-6-Gate:
grep -qx "semgrep-regel gcm-no-tag-length=0": die Regel sollte jetzt nichts mehr finden. - Der Beweisdateiname
checks/task5-image.txtenthaelt die Zeileergebnis umgesetzt. - Platte: 55 % belegt (78 GB frei) nach den Arbeiten;
docker image prune -fhat nichts mehr zu entfernen. - CLAUDE.md-Tabelle (D-26) unveraendert; zusaetzlich hinkt jetzt nichts Neues nach.
- Orchestrator-Hinweis: der naechste ZAP-Lauf (oeffentliche Adresse, nach dem naechsten alpha-Pull) sollte die Zeilen der Kopfzeilen auf "behoben" setzen oder pruefen, ob der Proxy sie doppelt sendet; die Anwendung sendet sie jetzt selbst.
Task 6: Abschlusslauf, Protokoll-Abschluss, CLAUDE.md, Aufraeumen (erledigt)
Commits (nicht gepusht):
bc7fffedocs(quick-261009-p0m): Technology-Stack-Zeilen auf den Stand der Lockdatei gebracht (CLAUDE.md, Zusatzauftrag, ueberschreibt D-26)b085889docs(quick-261009-p0m): Sicherheitsprotokoll mit Stand nach der Behebung
Nicht eingecheckt (Vorgabe): checks/final-run.txt, baseline/SUMMARY.txt (Block "nach Behebung"), diese Datei. Gate-Sentinel task6 ok gedruckt (Kette aus dem Plan wortgetreu).
Abschlusslauf (checks/final-run.txt)
Frischer Klon (git clone --no-local) von HEAD fceec19, Container gitea/runner-images:ubuntu-latest (Netz gitea, Docker-Socket, frisches Werkzeug-Volume, GITHUB_REF=refs/heads/main, kein Kanarienvogel), Skript all: rc=0.
gitleaks findings=0
pnpm-audit-prod critical=0 high=9 moderate=3 low=0
osv-scanner packages=20
semgrep findings=33 errors=4
trivy-fs critical=0 high=9 medium=4 low=0 misconfig=2 secrets=0
trivy-image-api critical=0 high=6 medium=4 low=0
trivy-image-web critical=0 high=3 medium=1 low=0
semgrep-regel gcm-no-tag-length=0
- Die Zeilen der Abbilder heissen
trivy-image-api/-web, weil das Skript den Namen aus dem Abbildnamen ableitet. Mit den lokalen Compose-Namen (tessera-ctl-api:latest) hiessen sietrivy-image-tessera-ctl-api(erster Versuch, gleiche Zahlen) und haetten das Plan-Gate nicht getroffen. Loesung ohne Skriptaenderung: der gesamte Lauf wurde wiederholt mit den lokalen Abbildern kurz alsapi:p0m-final/web:p0m-finalgetaggt (kein Registry-Name; Tags danach entfernt). Die Zeilen der Datei stammen aus diesem zweiten Lauf; er war der erste Lauf mit wiederverwendetem Werkzeug-Volume (semgrep ... bereit (vorhanden)), also ein lokaler Beleg fuer Annahme A2. - Reste der Abbild-Funde (per Trivy am lokalen Abbild nachgemessen): api = deepmerge-ts, node-forge, nodemailer, xlsx (je HIGH, alle ohne Korrektur in der Versionslinie); web = nur sharp.
- osv 20 = 8 npm (xlsx, node-forge, nodemailer, sharp, deepmerge-ts, vitest 3.2.6, @vitest/mocker 3.2.6, tinypool) + 12 crates (glib, anyhow, event-listener, h2, quick-xml x2, proc-macro-error, unic-* x5).
- Semgrep Rest: 14 mutable Aktions-Tags (+1 curl|sh), 9 non-literal-regexp, 4 TLS-Umgehungen (bewusst), 1 open-redirect, 1 prototype-pollution-loop, 3 pnpm-Haertungsschluessel; die GCM-Regel ist weg.
Protokoll-Abschluss
- Neuer Abschnitt
## Stand nach der Behebung(Vorher/Nachher-Tabelle je Werkzeug, Liste des Offenen in Alltagssprache) und Verlaufseintrag### 2026-10-09 — Stand nach der Behebung(Kurzfassung mit Verweis; Tabelle steht aus Wartungsgruenden nur im Abschnitt). "Auf einen Blick" (Bausteine, automatische Pruefung, Was noch zu tun ist) auf den Endstand gebracht. - "Einordnung der Befunde": 33 Zeilen, alle mit Stand und Begruendung. Neu: Zeile "Weitere Hinweise zu Bausteinen der Desktop-App" (11 Rust-Bausteine, offen; Patch-Fassungen fuer anyhow 1.0.103, event-listener 5.4.2, h2 0.4.16 existieren) und Zeile "Testwerkzeuge vitest 3 / tinypool" (offen). Pipeline-Zeile auf 14 mutable Tags aktualisiert, GCM-Zeile um "Semgrep meldet nicht mehr" ergaenzt.
- Wortregeln geprueft: kein "Lizenz", "Mandant", keine Du-Form, keine IP-Adressen; Link-Pruefer 12 Links 0 kaputt; gitleaks auf Protokoll und volle Historie (1377 Commits) 0 Funde.
CLAUDE.md (Zusatzauftrag, ueberschreibt D-26)
Zeilen angepasst nach pnpm-lock.yaml (importers:): Next.js 15.5.27, NestJS 11.2.7, Vitest (apps/web) 4.1.11, dazu der Satz unter "Recommended But Not Adopted" (Next 15.5.27). Express 5.2.1, Prisma 6.19.3, React 19.2.7, Tailwind 4.3.1, TypeScript 5.9.3, Biome 2.5.0, Turborepo 2.9.18, Vitest (apps/api) 3.2.6, next-intl, Zustand und die uebrigen Zeilen stimmen unveraendert. Kopfhinweis ergaenzt: Stand 2026-09-09; die drei Zeilen am 2026-10-09 gegen die Lockdatei neu geprueft (Docker-Zeilen bleiben bewusst mit ihrem Messdatum). nodemailer und undici stehen nicht in der Tabelle.
Aufraeumen
Entfernt (Name fuer Name): semgrep/semgrep:1.180.0, aquasec/trivy:0.75.0, ghcr.io/aquasecurity/trivy:0.75.0, ghcr.io/google/osv-scanner:v2.6.0, ghcr.io/gitleaks/gitleaks:latest und :v8.30.1, curlimages/curl:latest; docker image prune -f hatte danach nichts zu entfernen (nie -a). Behalten: ZAP-Abbild (Digest geprueft), gitea/runner-images:ubuntu-latest. Wegwerf-Klon, Werkzeug-Volume p0m-final-tools und die Zwischentags geloescht, root-eigene Berichte per Container entfernt; in security-reports/ bleibt nur der ZAP-Ordner von alpha. Platte: 54 % belegt (80 GB frei), weit unter 85 %.
Abweichungen (Task 6)
- Abbildnamen im Abschlusslauf: siehe oben, Lauf mit
api:p0m-final/web:p0m-finalstatttessera-ctl-*:latest(Plan-Gate verlangttrivy-image-api/-web; kein Skripteingriff noetig). - Zusatz: CLAUDE.md-Aktualisierung (Orchestrator-Auftrag) als eigener Commit
bc7fffe. - Protokoll: Die Vorher/Nachher-Tabelle steht im Abschnitt "Stand nach der Behebung"; der Verlaufseintrag mit dem vom Plan verlangten Titel ist eine Kurzfassung mit Verweis (kein doppelt gepflegtes Zahlenwerk).
- Zwei Zeilen in "Einordnung der Befunde" ergaenzt (Desktop-Hinweise, Testwerkzeuge): sie fehlten bisher, obwohl osv-scanner sie zaehlt (Plan: jede Zahl braucht Stand und Grund).
Gesamtergebnis: vorher / nachher
| Werkzeug | Grundlinie (roh) | nach Ausnahmelisten (Task 1) | nach Behebung (Task 6) |
|---|---|---|---|
| gitleaks (Historie) | 20 (0 echt) | 0 | 0 |
| pnpm audit --prod | C5 H73 M68 L5 (151) | unveraendert | C0 H9 M3 L0 (12) |
| pnpm audit (alle) | C7 H85 M74 L5 (171) | -- | C2 H9 M5 L0 (16) (Task 4) |
| osv-scanner | 43 (nur pnpm-lock) | 56 (mit Cargo.lock) | 20 |
| Semgrep | 58 / 59 Scanfehler | 34 (ERROR 2) / 4 | 33 (ERROR 1) / 4; GCM-Regel 0 |
| Trivy fs | C5 H73 M68 L5, secrets 7, misconfig 2 | C5 H73 M70 L5, secrets 0 | C0 H9 M4 L0, secrets 0, misconfig 2 |
| Abbild api | C6 H116 M98 L7, 1,66 GB | C6 H116 M99 L7 | C0 H6 M4 L0, 1,12 GB |
| Abbild web | C2 H19 M21 L1, 359 MB | C2 H19 M22 L1 | C0 H3 M1 L0, 359 MB |
| ZAP alpha (direkt, ohne Proxy) | -- | -- | 0 / 2 / 6 / 3 (Task 3, vor den Kopfzeilen; nicht neu gemessen) |
Offene Punkte (alle im Protokoll mit Grund)
- xlsx 0.18.5, node-forge 1.4.0: keine bereinigte Fassung (Ersatz von xlsx waere ein eigener Auftrag).
- nodemailer (2 H, 3 M), sharp (3 H), deepmerge-ts (1 H): Korrektur nur mit neuer Haupt-/Null-Minor-Version (nodemailer 10 ist die groesste Restposition).
- vitest/@vitest/mocker 3.2.6, tinypool 1.1.1 (API-Tests): nur Entwicklung, Korrektur braucht vitest 4 in apps/api (nicht im Abbild).
- Desktop: glib 0.18.5 plus 11 weitere Rust-Hinweise; anyhow 1.0.103, event-listener 5.4.2, h2 0.4.16 sind Patch-Updates in der Versionslinie (
cargo update -p ... --precise) und koennten als kleiner Folgeauftrag eingespielt werden (waere ein Cargo.lock-Commit). - Web-Abbild ohne Gesundheitspruefung (weder Dockerfile noch Compose).
- Vollstaendige Inhaltsrichtlinie (CSP): bewusst nicht gesetzt, eigener Auftrag.
- Pipeline-Haertung: 14 bewegliche Aktions-Tags, ein curl|sh, drei pnpm-Arbeitsbereichsschluessel (niedrig).
- Ausstehender oeffentlicher ZAP-Lauf (siehe unten).
- Nicht gebaut: woechentlicher geplanter Lauf der Pruefung (Forschung: jetzt nicht noetig); Anheben der Aktions-Tags.
Ausstehender oeffentlicher ZAP-Lauf
Der erste Lauf ging direkt gegen die Anwendung auf alpha, weil die oeffentliche Adresse vom Dev-Host nicht erreichbar war (Zeitueberschreitung Port 443). Nach dem naechsten alpha-Pull (mit den Kopfzeilen aus fceec19): sh .gitea/scripts/zap-baseline.sh (Standardziel = oeffentliche Adresse; falls Basic Auth 401 liefert: ZAP_BASIC_AUTH_FILE mit benutzer:passwort ausserhalb des Repos). Danach im Protokoll: neue Zeile in "Pruefung von aussen gegen alpha", Verlaufseintrag, und die drei Zeilen "behoben in der Anwendung, beim oeffentlichen Lauf erneut pruefen" sowie HTTPS/Proxy auf ihren Endstand setzen.
Checkliste erster CI-Lauf nach dem Push (Nutzer/Orchestrator)
- Job
securityerscheint nachpublish(nur main und Tagsv*), publish und Freigaben unveraendert. - Jobfarbe: gelb/gruen trotz Funden (Annahme A3:
continue-on-errorauf Job-Ebene), kein anderer Job haengt daran. - Im Lauf-Protokoll stehen alle
SECURITY-SUMMARY-Zeilen (gitleaks, pnpm-audit-prod, osv-scanner, semgrep, trivy-fs, trivy-image-api, trivy-image-web,fertig); Zahlen etwa wie oben (Abbild-Zahlen mit Registry-Abbildern von publish). - Artefakt
sicherheitsberichteherunterladbar? (Annahme A4,upload-artifact@v3; best effort, Ausfall ist kein Fehler.) - Zweiter Lauf: Werkzeuge aus dem
act-toolcache-Volume wiederverwendet (Zeile "bereit (vorhanden)"; Annahme A2; lokal mit Volume bestaetigt). - Dauer des Jobs (Limit 30 min) und Plattenstand des Runners.
- Der Desktop-Job baut die Pakete neu, weil
Cargo.locksich geaendert hat (erwartet).
Hinweise an den Orchestrator
- CHANGELOG: "Sicherheit:"-Bullets liegen innerhalb der bestehenden Gruppen Neu/Geaendert/Behoben (D-21: die "Was ist neu"-Anzeige liest nur diese drei).
- Entfernte Pakete:
@nestjs-modules/mailer,ews-javascript-api(D-22); keine neuen Paketnamen, 232 entfallen. - Overrides (15) und Gruende stehen in Task 4; Prisma 6.19.3, Next 15, NestJS 11 unveraendert.
- Keine Modulversion geaendert, nichts gepusht, nichts deployed.
- CLAUDE.md-Tabelle ist jetzt aktuell (siehe oben).
Self-Check: PASSED
Gefunden: docs/sicherheitsprotokoll.md, checks/final-run.txt, baseline/SUMMARY.txt (Block "nach Behebung"), Commits bc7fffe und b085889 sind Vorfahren von HEAD, git status ausserhalb von .planning/ sauber; Gate-Sentinel task6 ok.
Review fixes
Review findings WR-01, WR-02, WR-04, WR-05 and IN-01 to IN-04 fixed; commits bf632d9 (scripts, Dockerfiles, next.config comment) and 8a1218a (docs). Not pushed. Details per finding: "Fix status" in 261009-p0m-REVIEW.md.
- Image start proof is now versioned:
bash .gitea/scripts/image-start-check.sh [Abbild](replaceschecks/fresh-db-start.sh, which stays here as history). Rebuilt stack (docker compose up -d --build api web): api healthy; proof printedmigrationen=63,frische-datenbank ok. - Build fails when it must: broken
schema.prismain a throwaway Dockerfile fails at the explicitprisma generatestep (rc 1); a runner stage that keeps npm fails at the absence check. Both throwaway images removed; real Dockerfiles unchanged by the experiment. - security-scan.sh in
gitea/runner-images:ubuntu-latest(fresh throwaway clone, socket, fresh tool volume,GITHUB_REF=refs/heads/main, both local images): rc 0, 63 s, per-tool lines (gitleaks 0, pnpm-audit-prod critical 0 high 9, osv 20, semgrep 33/4, trivy-fs secrets 0, images api C0 H6, web C0 H3). Also: shallow clone ->unvollstaendig; forced limits ->zeitgrenze, forced tiny budget ->gesamtbudget; offline run rc 0 with 12 skipped lines (Task 1 gate needs >= 7); no semgrep container left behind. - ZAP: local passive proof (POST=0, header only to the target, never to a second host or a prefix-port lookalike); special-character password works; handover path for uid != 1000 exercised.
- Gates:
ci.ymlnode check from PLAN Task 1 printsci.yml ok(file unchanged);sh -non all.gitea/scripts/*.sh,bash -non the new script, shellcheck (via container image, removed afterwards) shows only SC2329 info for trap handlers; link-check 12 links, 0 broken; protocol table gate 34 rows ok; gitleaksdiron the changed docs/scripts clean. - Environment notes: semgrep image (1.5 GB) now stays cached on the dev host and will on the runner host after the first CI run (needed for the digest-pinned scan; documented in
docs/ci-cd-setup.md). Disk 57 % after cleanup (docker image prune -fonly). No shellcheck installed on the host; it was run fromkoalaman/shellcheck:stable. - Docs updated:
docs/sicherheitsprotokoll.md(Verlauf entry "Codeprüfung des Sicherheitsauftrags", table row, sums 9 reviews / 98 findings / 84 fixed, new open row for WR-03),docs/ci-cd-setup.md,docs/anleitung-entwicklung.md,docs/anleitung-betrieb.md.
Checklist after the first real CI run (WR-03)
- Job
securityends green or neutral, not red (red would mean the Gitea version ignores job-levelcontinue-on-error). timeout-minutes: 30is honoured; first run duration (semgrep image pull of about 1.5 GB and Trivy DB included) stays below 25 minutes; theSECURITY-SUMMARY dauer=...line shows it.- The next push's
quality/testis not noticeably delayed by the single runner; if it is, move the scan to a nightly schedule plus tagsv*. SECURITY-SUMMARY semgrep findings=... errors=...appears (container path works inside the real job container with the host socket) and artifactsicherheitsberichteis best effort.