Files
Metamorph/tasks/testing-m0.md

248 lines
11 KiB
Markdown
Raw Normal View History

2026-05-11 06:16:00 +02:00
---
type: testing
project: Metamorph
milestone: M0
date: "2026-05-10"
---
# Comment tester M0 (bootstrap)
> Procédure de validation manuelle + automatisée pour le milestone M0. Toutes les commandes se lancent depuis la racine du repo.
## 0. Prérequis
Au choix entre Docker **ou** Podman — le Makefile détecte automatiquement (override `ENGINE=docker` ou `ENGINE=podman` si les deux sont installés).
| Outil | Version min | Vérifier |
|--------------------------------|-------------------|-------------------------------------------|
| **Docker Engine** *(option A)* | 24+ | `docker --version` + `docker compose version` |
| **Podman** *(option B)* | 4.0+ avec plugin compose, ou podman-compose 1.0.6+ | `podman --version` + `podman compose version` (ou `podman-compose --version`) |
| GNU make | 4+ | `make --version` |
| curl, jq | n'importe | `curl --version` |
| Node.js (pour les e2e) | 20+ | `node --version` |
Vérifier le moteur que le Makefile utilisera :
```bash
make engine
# ENGINE=podman
# COMPOSE=podman compose
```
Override possible : `make up ENGINE=docker COMPOSE="docker compose"`.
## 1. Bootstrap de l'environnement
```bash
make env # crée .env depuis .env.example
$EDITOR .env # vérifie : APP_ENV=dev OK pour la machine, sinon set des secrets forts
```
Variables critiques de `.env` :
- `APP_ENV``dev` autorise les placeholders ; `prod` ou `staging` exigent `JWT_SECRET >=32 chars` + `POSTGRES_PASSWORD` non-default (sinon l'API refuse de booter).
- `JWT_SECRET` — pour M0 le démon ne signe rien, mais autant le mettre propre tout de suite : `python3 -c "import secrets; print(secrets.token_urlsafe(64))"`.
- `HOST_FRONT_PORT` / `HOST_API_PORT` — modifie si 8080/8000 sont déjà occupés.
## 2. Build & démarrage
```bash
make up # build des 3 images + démarrage
make ps # vérifie que les 3 services tournent
```
**Attendu** :
```
metamorph-db postgres:16-alpine Up (healthy)
metamorph-api metamorph-api Up
metamorph-front metamorph-front Up (healthy)
```
Si `db` reste en `starting` au-delà de 30 s : `make logs` pour voir l'erreur (généralement un mismatch de credentials dans `.env`).
## 3. Tests fonctionnels manuels
### 3.1 — Health API direct (port 8000)
```bash
curl -s http://localhost:8000/api/v1/health | jq
```
**Attendu** :
```json
{ "status": "ok", "version": "0.1.0" }
```
### 3.2 — Health API via le proxy nginx (port 8080)
```bash
curl -s http://localhost:8080/api/v1/health | jq
```
Doit renvoyer le **même** JSON. Cela valide la conf nginx qui proxifie `/api/* → api:8000`.
### 3.3 — SPA dans le navigateur
Ouvrir <http://localhost:8080>. **Vérifications visuelles** :
- [ ] Header centré, fond `#0a0e1a`, titre « Metamorph Purple Team Platform » avec « Meta » en rouge et « Purple Team Platform » en violet.
- [ ] Section `// System Health` avec une card bordée vert affichant `version 0.1.0` et `status: ok`.
- [ ] Section `// Design Tokens` montrant les tags colorés (EVASION, C2, LATERAL…), la flow chain `recon → phish → c2 → lateral → impact`, et 3 boutons.
- [ ] Footer en mono dim avec la mention M0 bootstrap.
- [ ] Toutes les polices sont chargées (titres en JetBrains Mono, body en IBM Plex Sans). Onglet Network : **aucune** requête vers `fonts.googleapis.com` ou `fonts.gstatic.com`.
- [ ] Console JS sans aucune erreur.
### 3.4 — Logs structurés JSON
```bash
make logs-api # tail uniquement le container api (engine-agnostic)
```
**Attendu** : chaque ligne est un objet JSON avec au minimum `ts`, `level`, `logger`, `message`. Exemple :
```json
{"ts":"2026-05-10 14:21:33,012","level":"INFO","logger":"metamorph.boot","message":"metamorph.api.boot","cors_origins":["http://localhost:8080"],"log_level":"INFO","evidence_dir":"/data/evidence"}
```
Si tu vois du texte non-JSON, c'est gunicorn qui parle ; vérifier que l'app est bien chargée via `app.main:app` (le formatter doit s'appliquer).
### 3.5 — Healthchecks containers
```bash
make inspect-health
```
**Attendu** : `healthy` pour les trois containers (à 30 s près après le boot).
```
metamorph-db healthy
metamorph-api healthy
metamorph-front healthy
```
### 3.6 — Garde APP_ENV (sécurité)
Test négatif : on prouve que l'API refuse de booter en non-dev avec un secret faible.
```bash
make down
APP_ENV=prod JWT_SECRET=trop-court $(make engine | sed -n 's/^COMPOSE=//p') up api 2>&1 | head -30
# ou plus simplement, en explicitant ton moteur :
# APP_ENV=prod JWT_SECRET=trop-court docker compose up api
# APP_ENV=prod JWT_SECRET=trop-court podman compose up api
```
**Attendu** : trace d'erreur Pydantic mentionnant *"JWT_SECRET is missing, default, or shorter than 32 chars"*. L'API doit s'arrêter, pas démarrer.
Reset :
```bash
make down && make up
```
### 3.7 — CORS
```bash
curl -is -H 'Origin: http://localhost:8080' http://localhost:8080/api/v1/health \
| grep -i access-control-allow-origin
```
**Attendu** : un header `Access-Control-Allow-Origin: http://localhost:8080`.
```bash
curl -is -H 'Origin: http://evil.example' http://localhost:8080/api/v1/health \
| grep -i access-control-allow-origin || echo "no CORS allow header (expected)"
```
**Attendu** : pas de header (origine non-allowée).
### 3.8 — Volumes persistants
```bash
make volumes
```
**Attendu** : deux volumes nommés (le préfixe peut varier selon le moteur) :
```
metamorph_db
metamorph_evidence
```
Test de persistance basique : `make down && make up` ne doit pas effacer les volumes ; seul `make clean` le fait (destructeur, demande explicite).
## 4. Tests automatisés (Playwright)
```bash
make e2e-install # à faire une seule fois (download chromium + deps OS)
make up # si la stack n'est pas déjà up
make e2e # lance la suite
make e2e-report # ouvre le rapport HTML
```
**Suite M0** (`e2e/tests/m0-smoke.spec.ts`) — 8 tests :
| # | Test | Couvre |
|---|-----------------------------------------------------------|-------------------------------------------------|
| 1 | home page loads and renders the RTOps header | Front + nginx + assets statiques |
| 2 | API health card eventually shows OK | Front → API via proxy `/api/*` |
| 3 | design system primitives render with the expected accents | Card / Tag / FlowNode / Button |
| 4 | body uses self-hosted IBM Plex Sans, no Google Fonts | Spec §7 « pas de CDN runtime » |
| 5 | background uses the RTOps deep navy token | Token `--bg = #0a0e1a` appliqué |
| 6 | no JS console errors on first load | Pas de regression silencieuse côté SPA |
| 7 | API health endpoint returns the expected JSON shape | Contrat API direct |
| 8 | CORS headers are set when the SPA origin asks for them | flask-cors configuré sur `FRONT_ORIGIN` |
Le rapport HTML (`e2e/playwright-report/index.html`) inclut, pour chaque test : steps, screenshots sur échec, vidéo sur retry, trace Playwright (timeline réseau + DOM).
Le rapport JUnit XML (`e2e/playwright-report/junit.xml`) est consommable directement par GitLab CI / GitHub Actions / Jenkins.
## 5. Tests unitaires backend
```bash
make test-api
```
**Attendu** : `tests/test_health.py::test_health_returns_ok PASSED`.
## 6. Lint & typecheck
```bash
make lint
```
Lance ruff (back), eslint + tsc --noEmit (front). Tout doit passer.
## 7. Critères de DoD M0 (extraits de `tasks/todo.md`)
- [ ] `make up` démarre les 3 conteneurs
- [ ] `curl http://localhost:8080/api/v1/health``{"status":"ok","version":"…"}`
- [ ] Front affiche la home RTOps (manuel + e2e #1, #3, #5)
- [ ] Logs JSON sur stdout (manuel #3.4)
- [ ] Volumes nommés présents (manuel #3.8)
- [ ] Suite Playwright M0 verte
- [ ] Rapport HTML disponible dans `e2e/playwright-report/`
## 8. Si quelque chose casse
| Symptôme | Diagnostic |
|-------------------------------------------------------|---------------------------------------------------------|
| `make up` plante en build du back | Probablement un download `uv` lent ; relancer ou `make rebuild` |
| API réponse 502 via le front | api pas encore healthy ; `make logs api` |
| Page blanche, console : `Failed to load module …` | Le bundle Vite n'a pas été produit ; `make rebuild` |
| Polices custom non chargées (fallback sans-serif visible) | Vérifier que `@fontsource/*` est bien dans `node_modules` du build context |
| Tests Playwright `Timeout … API health card` | API pas joignable depuis le navigateur ; tester `curl` d'abord |
| `make volumes` ne montre rien | Vérifier que la stack est `make up`. Sous Podman rootless, les volumes vivent dans `~/.local/share/containers/storage/volumes/`. |
| `make engine` annonce le mauvais moteur | Override : `make up ENGINE=docker COMPOSE="docker compose"` ou inverse pour podman. |
| `podman compose` indisponible mais `podman-compose` oui | Le Makefile fallback automatiquement, ou force-le : `COMPOSE=podman-compose make up`. |
## 9. Pièges connus (validés sur podman 5.x / Fedora 43)
- **Short-name resolution sous Podman** : si tu remplaces une image par son nom court (`postgres:16-alpine`), Podman échoue avec `short-name resolution enforced but cannot prompt without a TTY`. **Toujours utiliser `docker.io/library/<image>:<tag>`** (Docker accepte le préfixe transparente).
- **Premier `make up`** : compte ~3 min pour télécharger `postgres:16-alpine` + builder les images custom. Les builds suivants sont quasi instantanés grâce au cache.
- **`make inspect-health` montre `(no-healthcheck)` malgré le Dockerfile** : podman-compose 1.x ne propage pas les healthchecks du Dockerfile. Le projet redéclare les healthchecks dans `docker-compose.yml` pour cette raison.
- **`api` reste en `starting` ~15 s** avant de basculer healthy : c'est le `start_period: 10s` du healthcheck + 1 round de polling. Normal.
- **Volumes Podman rootless** : `~/.local/share/containers/storage/volumes/` au lieu de `/var/lib/docker/volumes/`. `make volumes` liste les bons volumes peu importe l'engine.
## 10. Teardown
```bash
make down # garde les volumes
make clean # supprime aussi les volumes (DESTRUCTEUR)
```