ops: Lokale Datenbank gegen fremde Testläufe absichern — DB_* nicht mehr als Container-Umgebung, Agenten-Regel, Testdatenbank-Pflicht im Baukasten

Am 07.10.2026 hat das RefreshDatabase eines frischen Demo-Projekts (Test der
Vorlagen aus dev/git-deploy-monitoring) die lokale Datenbank `pressekonto` auf
global-mysql vollständig geleert (Binärlog binlog.000009, Pos. 566161486).
Ursache: docker-compose.yml setzte DB_* als Container-Umgebungsvariablen, die
in Laravel Vorrang vor jeder .env haben; die phpunit.xml des Demo-Projekts
erzwang kein SQLite. Die eigene Suite war nicht beteiligt (force="true" und
Guard in tests/TestCase.php greifen; Gegenprobe mit MySQL-Variablen grün).

- docker-compose.yml: DB_* entfernt (Werte identisch in .env), wirksam nach
  Neuerstellen des Containers.
- Baukasten: „Testdatenbank absichern" (phpunit.xml mit force, Guard,
  Gegenprobe) als Pflicht vor RefreshDatabase.
- .ai/rules/general.md und CLAUDE.md: fremde/frische Laravel-Projekte nur mit
  SQLite :memory: testen; migrate hier erst nach migrate:status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-07 16:09:25 +00:00
parent 32e1349517
commit fd8dd74d5f
6 changed files with 81 additions and 9 deletions

View file

@ -150,6 +150,50 @@ glitchtip“), `ErrorSignalsTest.php`, `BrowserErrorReportingTest.php`,
Die Tests setzen `RefreshDatabase` voraus (in `tests/Pest.php` aktivieren) und
eine `User`-Factory.
### Testdatenbank absichern (vor `RefreshDatabase`!)
`RefreshDatabase` führt `migrate:fresh` aus und **löscht alle Tabellen** der
Datenbank, auf die die Tests zeigen. In einer frischen Laravel-Installation
sind die SQLite-Zeilen in `phpunit.xml` auskommentiert, und ohne `force="true"`
haben vorhandene Umgebungsvariablen (Docker-/Container-`environment`, CI) Vorrang
vor `phpunit.xml` und `.env`. So hat am 07.10.2026 das Testen dieser Vorlagen
in einem Demo-Projekt die lokale Datenbank eines anderen Projekts geleert, das
im selben Container lief.
`phpunit.xml`, im `<php>`-Block:
```xml
<env name="DB_CONNECTION" value="sqlite" force="true"/>
<env name="DB_DATABASE" value=":memory:" force="true"/>
<env name="DB_URL" value="" force="true"/>
<server name="DB_CONNECTION" value="sqlite" force="true"/>
<server name="DB_DATABASE" value=":memory:" force="true"/>
<server name="DB_URL" value="" force="true"/>
```
Guard in `tests/TestCase.php` — `setUpTraits()` läuft vor jedem
Datenbank-Trait und bricht ab, bevor etwas geleert wird (auch bei einem
gecachten `bootstrap/cache/config.php`):
```php
protected function setUpTraits(): array
{
$default = (string) \Illuminate\Support\Facades\DB::getDefaultConnection();
$connection = (array) config('database.connections.'.$default, []);
if (! empty($connection['url'])
|| ($connection['driver'] ?? null) !== 'sqlite'
|| ($connection['database'] ?? null) !== ':memory:') {
throw new \RuntimeException("Tests laufen nicht gegen SQLite :memory: ({$default}) — abgebrochen, bevor RefreshDatabase etwas leert.");
}
return parent::setUpTraits();
}
```
Wer Vorlagen in einem Wegwerf-Projekt ausprobiert, startet die Tests
zusätzlich explizit mit `DB_CONNECTION=sqlite DB_DATABASE=:memory: php artisan test`.
---
## 6. Regeln für den Code

View file

@ -32,7 +32,13 @@ Platzhalter: `meineapp` (Projektname), `meineapp.de` (Live-Domain),
- [ ] `AppServiceProvider::boot()`: `Queue::failing` → `OperationalAlert`, `AboutCommand::add`
- [ ] Vite-Eingang `resources/js/error-reporting.js`; `<x-monitoring.browser-errors build="build" area="…" />` in jedem Layout-`<head>`
- [ ] Basic Auth / `trustHosts`: `/health` ausgenommen bzw. erreichbar
- [ ] `phpunit.xml`: Sentry-DSNs leer (`force="true"`); `tests/Pest.php` mit `RefreshDatabase`
- [ ] **Vor** `RefreshDatabase`: Testdatenbank absichern (02 §5, „Testdatenbank absichern“):
`phpunit.xml` mit SQLite `:memory:` **und `force="true"`** (`DB_CONNECTION`, `DB_DATABASE`, `DB_URL` leer;
je als `<env>` und `<server>`), dazu der Guard in `tests/TestCase.php`. Eine frische Laravel-Installation
hat diese Zeilen nur auskommentiert — ohne `force` gewinnen vorhandene Umgebungsvariablen.
- [ ] Gegenprobe: `DB_CONNECTION=mysql DB_DATABASE=gibtsnicht php artisan test` muss trotzdem grün laufen
(bzw. der Guard laut abbrechen) — nie eine echte Datenbank leeren
- [ ] `phpunit.xml`: Sentry-DSNs leer (`force="true"`); danach `tests/Pest.php` mit `RefreshDatabase`
- [ ] `.env.example` um `vorlagen/env-beispiel.env` ergänzt
- [ ] Tests grün: `php artisan test --compact tests/Feature/Monitoring tests/Unit/Monitoring` (30 Tests)
- [ ] Datenschutzerklärung: Fehlerprotokollierung (Kategorien, Frist, Rechtsgrundlage)