feat(e2e): add distributed E2E test framework with parametric traffic generation

Add run-e2e-test.sh with CLI parameters (--hits, --http-ratio, --dns, --tls,
--src-ips, --keep-analysis, --up) for configurable traffic generation. Traffic
runs from VM endpoints with multiple source IPs (alias IPs on eth0) to produce
distinct sessions for the ML pipeline. Fix curl TLS flags (--tlsv1.2 instead
of --tls-v1-2), skip redundant local verification in distributed mode, and
fix dashboard is_available() cache that never retried after ClickHouse recovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-04-15 00:09:32 +02:00
parent 7894d39f1c
commit f88b739992
40 changed files with 2154 additions and 337 deletions

189
docs/testing-e2e.md Normal file
View File

@ -0,0 +1,189 @@
# Test E2E distribué — Stack de test complète ja4-platform
## Objectif
Valider le pipeline complet de bout en bout :
```
trafic simulé → ja4ebpf (capture eBPF) → ClickHouse (stockage + agrégation MV)
→ bot-detector (ML) → dashboard (visualisation)
```
Les tests unitaires et d'intégration existants testent la capture eBPF isolément.
Le test E2E distribué valide la **chaine complète** sur une architecture multi-VMs.
## Architecture
```
HOST (orchestrateur — run-e2e-test.sh)
├── centos8 (el8) ── nginx + ja4ebpf ──eth1──┐
├── rocky9 (el9) ── nginx + ja4ebpf ──eth1──┤ réseau privé ja4-e2e
├── rocky10 (el10) ── nginx + ja4ebpf ──eth1──┤ 192.168.42.0/24
│ │
│ analysis ────┘ 192.168.42.10 (fixe)
│ ├── Docker ClickHouse :9000/:8123
│ ├── Docker bot-detector :8080
│ └── Docker dashboard :8000
└── Trafic curl/httpx → endpoints :80/:443
```
### VMs
| VM | Rôle | Box | IP | Services |
|----|------|-----|-----|----------|
| centos8 | Endpoint el8 | centos/8 | DHCP eth0 | nginx, ja4ebpf |
| rocky9 | Endpoint el9 | generic/rocky9 | DHCP eth0 | nginx, ja4ebpf |
| rocky10 | Endpoint el10 | almalinux/10 | DHCP eth0 | nginx, ja4ebpf |
| analysis | Serveur central | generic/rocky9 | 192.168.42.10 (eth1 fixe) | Docker: ClickHouse, bot-detector, dashboard |
### Réseau
- **eth0** (NAT libvirt) : SSH depuis le host, réception du trafic de test
- **eth1** (réseau privé `ja4-e2e`) : communication inter-VMs
- Les endpoints utilisent eth1 pour envoyer les logs ja4ebpf vers `192.168.42.10:9000`
- Le host accède au dashboard et ClickHouse via l'IP eth0 de la VM analysis (routée via libvirt NAT)
## Pipeline de données
```
1. HOST → endpoints curl/httpx génère du trafic HTTP/HTTPS/H2
2. ja4ebpf Capture eBPF : TLS ClientHello (JA4), TCP SYN (L3/L4),
HTTP via uprobe SSL_read (L7)
3. → ClickHouse :9000 ja4ebpf écrit dans ja4_logs.http_logs_raw (batch 100 lignes, flush 1s)
4. MV mv_http_logs Materialized View : http_logs_raw → http_logs (parsed, corrélé)
5. MV mv_agg_host_ip_ja4_1h Agrégation horaire par (host, src_ip, ja4) → agg_host_ip_ja4_1h
6. view_ai_features_1h Vue qui joint les features pour le ML
7. bot-detector Cycle ML toutes les 30s (config de test) :
- Lit view_ai_features_1h
- Pipeline : NFEnsemble (M=5 NF) → ADWIN (River) → MLP fusion
- Écrit ml_all_scores + ml_detected_anomalies
8. dashboard API FastAPI sur :8000, requête ClickHouse
```
## Principe clé : DB vierge avant chaque test
Avant chaque exécution E2E, la Phase 1 fait un `docker compose down -v` qui supprime tous les volumes Docker (y compris les données ClickHouse). Cela garantit que :
- ClickHouse démarre avec un schéma vierge
- Les données observées sont exclusivement celles générées par le test
- Les vérifications de la Phase 5 sont déterministes
## Stack Docker (VM analysis)
Définie dans `tests/vm/analysis/docker-compose.yml` :
### ClickHouse
- Image : `clickhouse/clickhouse-server:24.8`
- Ports : `0.0.0.0:9000` (native, ja4ebpf), `0.0.0.0:8123` (HTTP, API)
- Schéma : 12 fichiers SQL de `shared/clickhouse/*.sql`, exécutés via `clickhouse-init.sh`
- Credentials : `user=default, password=""` (patché par clickhouse-init.sh)
- Dictionnaires : CSV stubs de `tests/integration/platform/csv-stubs/`
### bot-detector
- Build : `services/bot-detector/bot_detector/Dockerfile`
- Port : `0.0.0.0:8080` (health check)
- Configuration accélérée pour les tests :
- `CYCLE_INTERVAL_SEC: 30` (vs 300 en prod)
- `MIN_VALID_FEATURE_RATIO: 0.10` (vs 0.50 en prod)
- SHAP, clustering, multi-fenêtres désactivés
### dashboard
- Build : `services/dashboard/Dockerfile`
- Port : `0.0.0.0:8000`
- Routes de vérification : `/health`, `/api/overview`, `/api/detections`
## Phases du test (run-e2e-test.sh)
| Phase | Description | Durée |
|-------|-------------|-------|
| 0 | Setup : démarrage VMs, rsync, découverte IPs | ~2 min (si VMs existantes) |
| 1 | Stack analysis : purge volumes (DB vierge), `docker compose up -d --build`, attente healthy | ~3 min |
| 2 | Endpoints : nginx + ja4ebpf (DSN → analysis:9000), en parallèle | ~1 min |
| 3 | Trafic : 500 req/VM × 3 VMs, HTTP/HTTPS/H2, méthodes variées | ~5 min |
| 4 | Attente : flush ja4ebpf 15s, poll ml_all_scores (max 120s) | ~2 min |
| 5 | Vérifications : 15+ checks sur 4 layers | ~1 min |
## Vérifications (Phase 5)
### Layer 1 — Données brutes
- `ja4_logs.http_logs_raw` : lignes > 0
- `uniqExact(host)` : >= 2 hôtes distincts (multi-source)
### Layer 2 — Pipeline ClickHouse (MVs)
- `ja4_logs.http_logs` : JA4 fingerprints capturés
- `ja4_logs.http_logs` : méthodes HTTP capturées (L7 via uprobe SSL_read)
- `ja4_processing.agg_host_ip_ja4_1h` : agrégation horaire peuplée
- `ja4_processing.view_ai_features_1h` : features ML disponibles
### Layer 3 — ML bot-detector
- `ja4_processing.ml_all_scores` : classifications produites
- `ja4_processing.ml_detected_anomalies` : anomalies détectées (optionnel)
- Health check `:8080`
### Layer 4 — Dashboard
- `/health` : OK
- `/api/overview` : données non-vides
- `/api/detections` : accessible
## Utilisation
```bash
# Créer les 4 VMs
make e2e-up
# Test complet (500 req/VM, ~15 min)
make test-e2e
# Test rapide (100 req/VM)
make test-e2e-quick
# Garder les VMs après le test (pour debug)
KEEP_RUNNING=true make test-e2e
# Détruire les VMs
make e2e-down
```
## Accès manuel (debug)
```bash
# ClickHouse — vérifier les données
curl "http://192.168.42.10:8123/?query=SELECT+count()+FROM+ja4_logs.http_logs"
# Dashboard
curl http://192.168.42.10:8000/health
curl http://192.168.42.10:8000/api/overview | python3 -m json.tool
# bot-detector
curl http://192.168.42.10:8080/
# SSH dans la VM analysis
cd tests/vm && vagrant ssh analysis
# Logs des conteneurs
vagrant ssh analysis -- "docker logs bot_detector_ai --tail 50"
vagrant ssh analysis -- "docker logs ja4-dashboard --tail 50"
```
## Fichiers
| Fichier | Rôle |
|---------|------|
| `tests/vm/Vagrantfile` | Définition des 4 VMs + réseau ja4-e2e |
| `tests/vm/provision-analysis.sh` | Provisionneur VM analysis (Docker, firewall) |
| `tests/vm/analysis/docker-compose.yml` | Stack centralisée CH + bot-detector + dashboard |
| `tests/vm/run-e2e-test.sh` | Orchestrateur E2E 5 phases |
| `tests/vm/run-tests-vm.sh` | Script endpoint (modifié pour CH_HOST) |
| `Makefile` | Cibles e2e-up, e2e-down, test-e2e, test-e2e-quick |
## Dépannage
| Problème | Diagnostic |
|----------|------------|
| ClickHouse inaccessible | `vagrant ssh analysis -- "docker ps"` ; vérifier le port binding |
| ja4ebpf n'écrit pas | `vagrant ssh rocky9 -- "cat /tmp/ja4ebpf.log \| tail 20"` |
| Pas de JA4 | Le hook TC nécessite CAP_BPF ; vérifier `dmesg \| grep bpf` |
| bot-detector ne démarre pas | `vagrant ssh analysis -- "docker logs bot_detector_ai"` |
| Pas de données ML | Volume insuffisant pour les fenêtres d'agrégation horaire |
| Dashboard vide | Le bot-detector doit avoir complété au moins 1 cycle (30s) |