dev: Vorgehen bei sensiblen Daten in der Historie dokumentiert, Roadmap 1.1/1.2 erledigt

- git-deploy.md Abschnitt G: Rotieren, Sichern, Umschreiben, Prüfen,
  Hash-Zuordnung, Push, Server, Forgejo/NAS, lokales Aufräumen
- Protokoll: Speicherbereinigung in Forgejo und auf dem NAS erledigt,
  keine weiteren Klone, Live-Schlüssel bereits rotiert
- Agenten-Regel: keine personenbezogenen Daten oder Schlüssel ins Repository
- Roadmap: 1.1 und 1.2 erledigt, Context7 und lokales MySQL-Root unter 1.3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-09 12:53:24 +00:00
parent 919b753f54
commit 53e3b270e0
3 changed files with 62 additions and 24 deletions

View file

@ -216,6 +216,58 @@ Was bei der Umwandlung (B) auftrat, für den Fall, dass ein weiterer Server so u
Aufräumen nach ein paar stabilen Tagen: `~/deploy-v1.1.0.tgz`,
`~/backup-vor-v1.1.0.tgz`, `~/backup-vor-git.tgz`, `~/vor-git/`.
## G — Sensible Daten aus der Historie entfernen
Wurden Kundendaten, Dumps, Logs oder Schlüssel committet, reicht Löschen oder
Enttracken nicht: Die Datei bleibt in jedem Klon und auf jedem Remote
abrufbar. Vorgehen, erprobt am 09.10.2026 (Protokoll unten):
1. **Schlüssel zuerst rotieren.** Was einmal gepusht war, gilt als bekannt,
auch nach der Bereinigung.
2. **Sichern:** Branches, die nur auf einem Remote liegen, als lokale Branches
anlegen, dann `git bundle create <scratchpad>/vor-filter.bundle --all`. Das
Bundle enthält die Daten noch und wird am Ende gelöscht.
3. **Umschreiben** aller Branches und Tags (`git filter-repo` ist besser, fehlt
aber im Dev-Container):
```bash
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f \
--index-filter 'git rm -r --cached --ignore-unmatch --quiet "<pfad>"' \
--tag-name-filter cat -- --branches --tags
```
4. **Prüfen:** Dateibaum (`git rev-parse <ref>^{tree}`) und Commitzahl
(`git rev-list --count <ref>`) je Branch und Tag vorher und nachher gleich;
`git rev-list --objects --branches --tags | grep '<pfad>'` ist leer.
5. **Hash-Zuordnung** alt → neu ins Archiv legen, solange die alten Commits
lokal noch vorhanden sind (Abgleich über Autor- und Committerzeit, Autor,
Betreff). Doku und Commit-Nachrichten nennen weiter die alten Hashes.
6. **Push vom Host** (der Dev-Container hat keinen SSH-Schlüssel), je Remote:
`git push --force-with-lease <remote> <branches…>` und
`git push --force --tags <remote>`. Lehnt Forgejo ab, kurz den Branch-Schutz
lösen.
7. **Server:** `deploy.sh` holt Tags ohne `--force` und scheitert an neu
gesetzten Tags („would clobber existing tag“). Einmal von Hand:
```bash
cd ~/pressekonto.com
git status --porcelain # muss leer sein
git fetch --force --tags --prune origin
git checkout --quiet --detach <aktueller Tag> # gleicher Inhalt, neuer Hash
git reflog expire --expire=now --all && git gc --prune=now
git count-objects -vH # size-pack prüfen
```
`RELEASE` bleibt unverändert, ein Deploy ist nicht nötig.
8. **Forgejo und NAS:** Speicherbereinigung des Repositorys anstoßen. Weitere
Klone löschen und neu klonen.
9. **Lokal aufräumen:** `refs/original/*`, verwaiste Remote-Refs und Refs
anderer Werkzeuge (z. B. `refs/codex/…`, sie hielten am 09.10. die alten
Objekte fest) löschen, dann
`git reflog expire --expire=now --all && git gc --prune=now`. Mit
`git cat-file -e <blob-hash>` nachweisen, dass die Objekte weg sind, dann
das Bundle löschen.
## Betrieb: PHP-FPM beim Deploy
Jeder Reload bricht Anfragen ab, die in dieser Sekunde laufen. Im Nginx-Fehlerlog
@ -266,24 +318,4 @@ Ausfall des Anbieters keinen Deploy abbricht.
| 08.10.2026 | `v1.6.0` | Mit Migration (`users.sessions_revoked_at_ms`, Batch 22). Härtung aus Phase 4 des Sicherheitsaudits: „Andere Geräte abmelden“, IP-weites Login-Limit (20 Fehlversuche in 15 Minuten), dauerhafte Session-Sperrmarke, Passwörter ab 12 Zeichen mit Leak-Abgleich, CSP im Melde-Modus (`storage/logs/csp-*.log`), npm `shell-quote`/`source-map-js`. Nach dem Deploy: Header `content-security-policy-report-only` vorhanden, Umami- und GlitchTip-Host in `script-src`/`connect-src`. CSP-Log in einigen Tagen auswerten. |
| 08.10.2026 | `v1.6.1` | Vorher auf dem Server `php8.4-imagick` installiert und FPM neu geladen: Die Erweiterung fehlte auf Live, Herkunftsprüfung und KI-Vorab-Check der Bilder liefen seitdem ins Leere. Release: Zeile „PHP-Erweiterung Imagick“ in der Betriebsüberwachung, gebaute Livewire-Anfragen von Scannern (GlitchTip 38, 39) als 400 statt 500/419, Browser-Filter für abgebrochene Alpine-Übergänge (GlitchTip 18). Keine Migration. Nach dem Deploy: Betriebsüberwachung „Imagick ist geladen“. |
| 09.10.2026 | `v1.7.0` | Spamschutz für Kontakt-Widget und Registrierung (Cloudflare Turnstile, Inhaltsfilter mit Spam-Quarantäne, Namensregel bei der Registrierung). Bei nicht erreichbarem Cloudflare wird durchgelassen und markiert. Keine Migration. Vorher: Turnstile-Keys in der `.env`, Widget im Cloudflare-Dashboard mit allen drei Live-Hostnamen. Nach dem Deploy: Kontakt-Widget im Browser getestet, Betriebsüberwachung „Spamschutz (Cloudflare Turnstile)“ grün. `contact-messages:quarantine-spam`: 152 Anliegen in die Quarantäne, 130 offen (Rest per Sammelaktion), echte Korrekturanfragen blieben offen. `users:prune-bot-registrations` nach freigegebenem Probelauf ausgeführt, danach `USERS_PRUNE_BOT_REGISTRATIONS=true` und `config:cache`. |
| 09.10.2026 | Historie bereinigt | Die Produktiv-SQL-Dumps vom 23.04. (`dev/migration 2026/sql`, ~290 MB, Kundendaten) lagen seit `5b8bdf4` in der Historie und auf beiden Remotes. Mit `git filter-branch` aus allen Branches und Tags entfernt; Dateibäume und Commitzahlen aller 21 Refs unverändert, **alle Hashes neu** (Zuordnung alt → neu: [`commit-map-2026-10-09.txt`](../archive/commit-map-2026-10-09.txt)). Tags `v1.0.0`–`v1.7.0` neu gesetzt, gleicher Inhalt. Force-Push auf `origin` und `NAS`, danach einmalig der Server-Abgleich unten — ausgeführt, Server `size-pack` 33,4 MiB. Lokal zusätzlich drei Codex-Checkpoint-Refs (`refs/codex/…`) entfernt, die noch auf die alte Historie zeigten. |
### Einmalig nach der Historienbereinigung (09.10.2026)
`deploy.sh` holt Tags ohne `--force` und würde an den neu gesetzten Tags
scheitern („would clobber existing tag“). Auf dem Server einmal:
```bash
cd ~/pressekonto.com
git status --porcelain # muss leer sein
git fetch --force --tags --prune origin
git checkout --quiet --detach v1.7.0 # gleicher Inhalt, neuer Hash — keine Dateiänderung
git reflog expire --expire=now --all && git gc --prune=now
git count-objects -vH # size-pack deutlich unter 300 MB
```
`RELEASE` bleibt `v1.7.0`, ein Deploy ist nicht nötig. Danach läuft
`deploy.sh` wie gewohnt. Jeder andere Klon (weitere Rechner) wird neu geklont.
In Forgejo und auf dem NAS die Speicherbereinigung des Repositorys anstoßen,
sonst bleiben die alten Objekte dort bis zur nächsten automatischen
Bereinigung liegen.
| 09.10.2026 | Historie bereinigt | Die Produktiv-SQL-Dumps vom 23.04. (`dev/migration 2026/sql`, ~290 MB, Kundendaten) lagen seit `5b8bdf4` in der Historie und auf beiden Remotes. Mit `git filter-branch` aus allen Branches und Tags entfernt; Dateibäume und Commitzahlen aller 21 Refs unverändert, **alle Hashes neu** (Zuordnung alt → neu: [`commit-map-2026-10-09.txt`](../archive/commit-map-2026-10-09.txt)). Tags `v1.0.0`–`v1.7.0` neu gesetzt, gleicher Inhalt. Force-Push auf `origin` und `NAS`, Server-Abgleich nach G.7 (Server `size-pack` 33,4 MiB), Speicherbereinigung in Forgejo und auf dem NAS, keine weiteren Klone. Lokal zusätzlich drei Codex-Checkpoint-Refs entfernt, die noch auf die alte Historie zeigten; danach 33,5 MiB, beide Dump-Blobs nicht mehr vorhanden. Die betroffenen Live-Schlüssel waren bereits rotiert (Betreiber). Vorgehen allgemein in Abschnitt G. |

View file

@ -55,9 +55,9 @@ oder Release versehen.
| # | Punkt | Quelle | Aufwand |
|---|---|---|---|
| ~~1.1~~ | ~~**Produktiv-SQL-Dumps in der Git-Historie.**~~ **Lokal bereinigt 09.10.2026** (`git filter-branch`, alle Branches und Tags, Inhalt unverändert, Hashes neu, Zuordnung in [`commit-map-2026-10-09.txt`](archive/commit-map-2026-10-09.txt)). Force-Push auf `origin` und `NAS` und Server-Abgleich erledigt 09.10.2026 (Server und lokal je 33 MiB statt 313 MiB, Dump-Blobs nicht mehr vorhanden). **Offen:** Speicherbereinigung in Forgejo und auf dem NAS anstoßen, andere Klone neu klonen. | [Release-Plan R6.2](archive/release/entwicklungsplan-release.md) | S [LIVE] |
| 1.2 | **Schlüssel rotieren**, deren Rotation nirgends belegt ist: OpenAI, Google OAuth, Mail-Zugang (K2 vom 14.07.), Context7 (stand in `.mcp.json`, Git-Historie), Connektar-API-Keys (Legacy-Keys liefen über Test-Kanäle), MySQL-Root lokal (Git-Historie). | [optimize 14.07. K2](archive/optimize/optimize-14-07-2026.md), [Deploy v1.1.0 F](archive/betrieb/deploy-v1.1.0.md), [Sicherheitsplan](sicherheit/ENTWICKLUNGSPLAN-SICHERHEIT-2026-10-07.md) | S [EXTERN] |
| 1.3 | **Dev-Container neu erstellen.** `docker-compose.yml` ist bereinigt, im laufenden Container sind `DB_CONNECTION` … `DB_PASSWORD` aber weiter als Umgebungsvariablen gesetzt — genau die Ursache des Datenverlusts vom 07.10. Danach lokalen `APP_KEY` reparieren (33 statt 44 Zeichen, ungültig) und Cloudflare-Testkeys in die lokale `.env`. | [Sicherheitsplan](sicherheit/ENTWICKLUNGSPLAN-SICHERHEIT-2026-10-07.md), [Spamschutz](sicherheit/ENTWICKLUNGSPLAN-SPAMSCHUTZ-2026-10-09.md) | S |
| ~~1.1~~ | ~~**Produktiv-SQL-Dumps in der Git-Historie.**~~ **Erledigt 09.10.2026:** aus allen Branches und Tags entfernt (Inhalt unverändert, Hashes neu, Zuordnung in [`commit-map-2026-10-09.txt`](archive/commit-map-2026-10-09.txt)), Force-Push auf `origin` und `NAS`, Server abgeglichen, Speicherbereinigung in Forgejo und auf dem NAS, keine weiteren Klone. Vorgehen für künftige Fälle: [git-deploy.md, Abschnitt G](betrieb/git-deploy.md). | [Release-Plan R6.2](archive/release/entwicklungsplan-release.md) | — |
| ~~1.2~~ | ~~**Schlüssel rotieren**~~ — **Live-Schlüssel bereits rotiert** (OpenAI, Google OAuth, Mail-Zugang, Connektar; Betreiber, bestätigt 09.10.2026). Offen bleiben nur die Entwicklungsschlüssel unter 1.3: Context7 (stand in `.mcp.json`, Git-Historie) und das lokale MySQL-Root-Passwort (Git-Historie). | [optimize 14.07. K2](archive/optimize/optimize-14-07-2026.md), [Sicherheitsplan](sicherheit/ENTWICKLUNGSPLAN-SICHERHEIT-2026-10-07.md) | — |
| 1.3 | **Dev-Container neu erstellen.** `docker-compose.yml` ist bereinigt, im laufenden Container sind `DB_CONNECTION` … `DB_PASSWORD` aber weiter als Umgebungsvariablen gesetzt — genau die Ursache des Datenverlusts vom 07.10. Danach lokalen `APP_KEY` reparieren (33 statt 44 Zeichen, ungültig) und Cloudflare-Testkeys in die lokale `.env`. Context7-Schlüssel und lokales MySQL-Root-Passwort rotieren (beide in der Git-Historie). | [Sicherheitsplan](sicherheit/ENTWICKLUNGSPLAN-SICHERHEIT-2026-10-07.md), [Spamschutz](sicherheit/ENTWICKLUNGSPLAN-SPAMSCHUTZ-2026-10-09.md) | S |
| ~~1.4~~ | ~~**Lokale Dateien mit Personenbezug**~~ — **gelöscht 09.10.2026:** `dev/migration/` (7,4 GB), `dev/archive/migration-2026/sql/` (905 MB), `dev/api/`, `dev/newsletter/`, `dev/2026-10/`, `storage/app/private/restore-company-user-auto-2026-10-07.sql`. | [dev/README](README.md) | — |
| 1.5 | **Alte Backups auf dem Server löschen:** `~/deploy-v1.1.0.tgz`, `~/backup-vor-v1.1.0.tgz`, `~/backup-vor-git.tgz`, `~/vor-git/`. | [git-deploy.md](betrieb/git-deploy.md) | S [LIVE] |