# AUDIT TECHNIQUE EXHAUSTIF - VEZA STREAM SERVER
## Module: veza-stream-server (Rust)

**Date**: 2025-01-27  
**Version du module**: 0.2.0  
**Auditeur**: AI Technical Auditor  
**Méthodologie**: Audit ultra-exhaustif, priorisé, actionnable

---

# PHASE A — CARTOGRAPHIE DU MODULE

## 1. But du module

**Rôle exact dans Veza** : Serveur de streaming audio haute performance avec :
- Streaming HTTP Range Requests (partial content)
- WebSocket pour streaming temps réel synchronisé multi-client
- Transcodage audio (FFmpeg pipeline)
- Génération HLS (HTTP Live Streaming)
- Synchronisation multi-client (<10ms de précision)
- Cache audio et compression adaptative
- Analytics et monitoring

**Position dans l'architecture Veza** :
- **Backend Go** (veza-backend-api) : API REST, gestion utilisateurs, métadonnées
- **Chat Server Rust** : WebSocket chat
- **Stream Server Rust** (ce module) : Streaming audio, transcodage, HLS
- **Frontend React** : Interface utilisateur

## 2. Entrées / Sorties

### APIs exposées

#### HTTP REST (Port 3002/8082)
- `GET /` : Health check basique
- `GET /health` : Health check détaillé
- `GET /healthz` : Liveness probe (K8s)
- `GET /readyz` : Readiness probe (K8s)
- `GET /metrics` : Métriques Prometheus
- `GET /stream/:filename?expires=&sig=` : Streaming audio avec signature HMAC
- `POST /internal/jobs/transcode` : Transcodage interne (non authentifié ⚠️)
- `POST /v1/stream/transcode` : Transcodage HLS
- `GET /v1/stream/job/:id` : Statut job transcodage
- `GET /api/streams/jobs/:id/status` : Statut détaillé job
- `GET /v1/stream/hls/:job_id/index.m3u8` : Manifest HLS master
- `GET /v1/stream/hls/:job_id/:segment` : Segment HLS (.ts)
- `GET /hls/:track_id/master.m3u8` : Master playlist HLS
- `GET /hls/:track_id/:quality/playlist.m3u8` : Playlist qualité spécifique
- `GET /hls/:track_id/:quality/:segment` : Segment HLS

#### WebSocket (Port 3002/8082)
- `GET /ws?token=&user_id=` : Connexion WebSocket pour streaming temps réel
  - Commandes : Play, Pause, Stop, Seek, Subscribe, GetStatus, Ping
  - Événements : PlaybackStarted, PlaybackPaused, PlaybackFinished, Error

#### gRPC (si activé)
- Service `StreamService` (proto/stream/stream.proto)
- Service `AuthService` (proto/common/auth.proto)

### Formats de données

**JSON** :
- Requêtes/Réponses REST : JSON standard
- WebSocket messages : JSON avec `type` discriminator
- Health checks : JSON structuré

**Protobuf** :
- gRPC services : Messages définis dans `proto/`

**Binaire** :
- Audio streams : MP3, WAV, FLAC, AAC, Opus
- HLS segments : .ts (MPEG-TS)
- HLS playlists : .m3u8 (text)

## 3. Dépendances internes

### Modules Veza partagés
- `veza-common` : Types communs, utilitaires partagés
  - Path : `../veza-common` (workspace local)

### Types communs attendus
- UUID pour IDs (utilisateurs, tracks, streams)
- Formats de dates/timestamps (chrono)
- Structures d'erreurs standardisées

## 4. Dépendances externes

### Base de données
- **PostgreSQL** (via sqlx 0.7)
  - Tables : `stream_jobs`, `stream_segments`
  - Références : `tracks` (table externe, backend Go)
  - Pool : 10 max, 1 min, timeout 30s

### Cache
- **Redis** (optionnel, via redis 0.25)
  - URL : `REDIS_URL` (env)
  - Pool : configurable

### Message Queue
- **RabbitMQ** (via lapin 2.3)
  - URL : `RABBITMQ_URL` (env, défaut: `amqp://guest:guest@localhost:5672/`)
  - Mode dégradé : Le serveur démarre même si RabbitMQ est down

### Stockage fichiers
- **Filesystem local** : `AUDIO_DIR` (défaut: `./audio`)
- **S3/MinIO** : ❌ Absent (stockage local uniquement)

### Outils externes
- **FFmpeg** : Transcodage audio (optionnel, chemin via `FFMPEG_PATH`)
  - Formats : MP3, AAC, FLAC, Opus, HLS

### Services externes
- **Backend API** : `BACKEND_URL` (défaut: `http://backend-api:8080`)
  - Utilisé pour : Validation auth, métadonnées tracks

## 5. Exécution

### Commandes de build/run

```bash
# Build
cargo build --release

# Run (dev)
cargo run

# Run (production)
./target/release/stream_server

# Tests
cargo test

# Clippy (lint)
cargo clippy -- -D warnings

# Benchmarks
cargo bench
```

### Configuration (variables d'environnement)

**Obligatoires** :
- `SECRET_KEY` : Clé HMAC (min 32 chars) pour signatures URLs
- `DATABASE_URL` : PostgreSQL connection string
- `JWT_SECRET` : Secret JWT (min 32 chars)

**Optionnelles** (avec defaults) :
- `STREAM_PORT` / `PORT` : Port serveur (défaut: 3002)
- `AUDIO_DIR` : Dossier fichiers audio (défaut: `./audio`)
- `ALLOWED_ORIGINS` : CORS origins (défaut: `*` ⚠️)
- `MAX_FILE_SIZE` : Taille max fichier (défaut: 100MB)
- `MAX_RANGE_SIZE` : Taille max range request (défaut: 10MB)
- `RABBITMQ_URL` : URL RabbitMQ (défaut: `amqp://guest:guest@localhost:5672/`)
- `REDIS_URL` : URL Redis (optionnel)
- `RUST_LOG` : Niveau logging (défaut: `stream_server=info`)

**Fichiers de config** :
- `.env` : Variables d'environnement (optionnel, chargé via dotenv)
- `env.example` : Template de configuration

### Docker

```bash
# Build
docker build -t veza-stream-server .

# Run (compose)
docker-compose up

# Run (production compose)
docker-compose -f docker-compose.production.yml up
```

**Dockerfile** :
- Multi-stage build (builder + runtime)
- Base : `rust:alpine` → `alpine:latest`
- User non-root : `app` (UID 1001)
- Healthcheck : `wget http://localhost:8082/health`
- Port exposé : 8082

### Kubernetes

**Manifests** : `k8s/production/`
- `stream-server-deployment.yaml` : Deployment
- `configmap.yaml` : Configuration
- `secrets.yaml` : Secrets (DB, JWT, TLS)

## 6. Points d'intégration avec autres services

### Contrats d'API attendus

#### Backend Go (veza-backend-api)
- **Auth** : Validation JWT via `JWT_SECRET` partagé
  - Audience : `veza-services`
  - Issuer : `veza-platform`
- **Métadonnées** : Table `tracks` (UUID, metadata)
  - Référence FK : `stream_jobs.track_id → tracks.id`
- **Format** : UUID v4 pour tous les IDs

#### Frontend React
- **CORS** : `ALLOWED_ORIGINS` (⚠️ `*` par défaut en dev)
- **WebSocket** : `ws://host:port/ws?token=<JWT>&user_id=<UUID>`
- **Streaming** : URLs signées avec `expires` et `sig` (HMAC-SHA256)

### Auth (JWT/SSO)

**JWT Validation** :
- Header : `Authorization: Bearer <token>`
- Query param : `?token=<JWT>` (WebSocket)
- Validation : `iss=veza-platform`, `aud=veza-services`, `alg=HS256`
- Expiration : Configurable (défaut: 3600s)
- Révocation : Session-based (HashMap en mémoire ⚠️)

**Permissions** :
- `StreamAudio` : Accès streaming basique
- `StreamHighQuality` : Streaming haute qualité
- `StreamUnlimited` : Streaming illimité
- `UploadAudio` : Upload fichiers
- `SystemAdmin` : Admin système

**Rôles** :
- `Admin`, `Moderator`, `User`, `Premium`, `Artist`, `Guest`

### Headers HTTP

**CORS** :
- `Access-Control-Allow-Origin` : `ALLOWED_ORIGINS` (⚠️ `*` par défaut)
- `Access-Control-Allow-Methods` : GET, POST, PUT, DELETE, OPTIONS
- `Access-Control-Allow-Headers` : Content-Type, Authorization, Accept

**Sécurité** :
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `X-XSS-Protection: 1; mode=block`
- `Content-Security-Policy: default-src 'none'; media-src 'self'`
- `Referrer-Policy: strict-origin-when-cross-origin`

### Schéma DB / UUID / Conventions

**UUID** :
- Format : UUID v4 (via `uuid` crate)
- IDs utilisateurs : `String` (UUID en string)
- IDs tracks : `UUID` (PostgreSQL)
- IDs streams : `UUID` (PostgreSQL)

**Tables PostgreSQL** :
- `stream_jobs` : Jobs transcodage (FK → `tracks.id`)
- `stream_segments` : Segments HLS (FK → `tracks.id`)
- `tracks` : ❌ **Table externe** (backend Go, doit exister)

**Conventions** :
- Timestamps : `TIMESTAMPTZ` (PostgreSQL)
- Durées : `FLOAT` (secondes) ou `INTEGER` (millisecondes)
- Status : `TEXT` avec CHECK constraints

---

# PHASE B — SANTÉ TECHNIQUE

## Build Status

### Compilation

**État** : ✅ Compile avec warnings

**Commandes de validation** :
```bash
cargo check  # ✅ Passe (avec warnings)
cargo build --release  # ✅ Passe
```

**Warnings détectés** :
- 174 occurrences de `unwrap()` / `expect()` dans 39 fichiers
- Dépendances obsolètes (axum 0.7 vs 0.8, sqlx 0.7 vs 0.8, etc.)
- Clippy warnings non traités (109 warnings selon audit précédent)

### Erreurs de types / Linters

**Clippy** :
```bash
cargo clippy -- -D warnings
```
- ⚠️ **109 warnings** (non bloquants mais qualité dégradée)
- Patterns détectés : `unwrap()`, `expect()`, allocations inutiles, clones

**Rustfmt** :
```bash
cargo fmt --check
```
- ✅ Formatage cohérent (sauf fichiers non formatés)

### Tests

**Couverture** :
- Tests unitaires : ~25% (estimé)
- Tests d'intégration : ❌ Absents
- Tests E2E : ❌ Absents

**Fichiers de tests** :
- `src/lib.rs` : 1 test basique (structure)
- `src/config/mod.rs` : 3 tests (config, dotenv, default)
- `src/error.rs` : 6 tests (conversions erreurs)
- `src/structured_logging.rs` : 5 tests (logging)
- `src/utils/mod.rs` : 3 tests (validation, signature)
- `src/middleware/security.rs` : 3 tests (patterns dangereux)
- `src/database/pool.rs` : 2 tests (ignorés, nécessitent DB)

**Tests manquants** :
- ❌ Tests WebSocket (connexion, messages, déconnexion)
- ❌ Tests streaming HTTP Range
- ❌ Tests transcodage FFmpeg
- ❌ Tests HLS generation
- ❌ Tests synchronisation multi-client
- ❌ Tests auth JWT
- ❌ Tests rate limiting
- ❌ Tests cache
- ❌ Tests analytics

### Gestion des erreurs

**Patterns utilisés** :
- ✅ `Result<T, AppError>` pour erreurs applicatives
- ✅ `thiserror` pour définitions d'erreurs
- ✅ `anyhow` pour erreurs contextuelles
- ⚠️ **174 `unwrap()` / `expect()`** : Risque de panics en production

**Fichiers avec le plus d'`unwrap()`** :
- `src/core/sync.rs` : 16 occurrences
- `src/analytics/mod.rs` : 11 occurrences
- `src/auth/mod.rs` : 12 occurrences
- `src/middleware/logging.rs` : 6 occurrences
- `src/routes/api.rs` : 3 occurrences

**Erreurs HTTP** :
- ✅ Mapping `AppError` → `StatusCode` (via `IntoResponse`)
- ✅ Messages d'erreur structurés (JSON)
- ⚠️ Certaines erreurs retournent 500 au lieu de codes appropriés

### Cohérence des conventions

**Naming** :
- ✅ Snake_case pour fonctions/variables
- ✅ PascalCase pour types
- ✅ Modules organisés par domaine

**Structure dossiers** :
```
src/
├── analytics/      # Analytics engine
├── audio/          # Audio processing
├── auth/           # Authentication
├── cache/          # File cache
├── codecs/         # Audio codecs
├── config/         # Configuration
├── core/           # Core streaming logic
├── database/       # DB pool
├── middleware/     # HTTP middlewares
├── monitoring/     # Metrics, health
├── routes/         # HTTP routes
├── streaming/      # Streaming protocols
├── transcoding/    # FFmpeg transcoding
└── utils/          # Utilities
```

**Séparation couches** :
- ✅ Routes → Handlers → Services → DB
- ✅ Middlewares séparés (auth, rate limit, security, logging)
- ⚠️ Certains handlers font trop de logique métier

---

# PHASE C — SÉCURITÉ

## Top 10 Risques Sécurité

### 1. **MOD-P0-001** : CORS permissif par défaut (`*`)

**Impact** : Attaques CSRF, accès non autorisé depuis n'importe quelle origine

**Preuve** :
```rust:340:344:src/config/mod.rs
allowed_origins: env::var("ALLOWED_ORIGINS")
    .unwrap_or_else(|_| "*".to_string())
    .split(',')
    .map(|s| s.trim().to_string())
    .collect(),
```

```rust:38:41:src/routes/api.rs
let cors = if allowed_origins_str.trim() == "*" {
    // Mode développement: autoriser toutes les origines
    CorsLayer::new()
        .allow_origin(Any)
```

**Cause racine** : Configuration par défaut trop permissive pour faciliter le développement

**Fix minimal** :
```rust
// Dans src/config/mod.rs
allowed_origins: env::var("ALLOWED_ORIGINS")
    .unwrap_or_else(|_| {
        if cfg!(debug_assertions) {
            "http://localhost:5176,http://localhost:3000".to_string()
        } else {
            panic!("ALLOWED_ORIGINS must be set in production")
        }
    })
```

**Plan de validation** :
1. Test : `curl -H "Origin: https://evil.com" http://localhost:8082/health`
2. Vérifier : Header `Access-Control-Allow-Origin` ne doit pas être `*` en prod
3. Test : Connexion WebSocket depuis origine non autorisée doit échouer

**Effet de bord** : Devs doivent configurer `ALLOWED_ORIGINS` en local

**Effort** : S (1h)

---

### 2. **MOD-P0-002** : Endpoint transcodage interne non authentifié

**Impact** : N'importe qui peut déclencher des jobs de transcodage (DoS, consommation CPU)

**Preuve** :
```rust:118:118:src/routes/api.rs
.route("/internal/jobs/transcode", post(internal_transcode_handler))
```

```rust:146:184:src/routes/api.rs
async fn internal_transcode_handler(
    State(state): State<AppState>,
    Json(payload): Json<serde_json::Value>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    // Aucune vérification d'authentification
```

**Cause racine** : Endpoint prévu pour usage interne mais exposé publiquement

**Fix minimal** :
```rust
// Ajouter middleware auth ou vérification IP
.route(
    "/internal/jobs/transcode",
    post(internal_transcode_handler)
        .layer(axum::middleware::from_fn_with_state(
            state.clone(),
            auth_middleware,
        ))
)
```

**Plan de validation** :
1. Test : `curl -X POST http://localhost:8082/internal/jobs/transcode -d '{}'`
2. Vérifier : 401 Unauthorized sans token
3. Test : Avec token valide, doit fonctionner

**Effet de bord** : Services internes doivent s'authentifier

**Effort** : S (1h)

---

### 3. **MOD-P0-003** : WebSocket sans authentification obligatoire

**Impact** : Connexions WebSocket anonymes possibles, accès streaming non contrôlé

**Preuve** :
```rust:802:808:src/streaming/websocket.rs
// Si un token est fourni, on le valide (pour l'instant, on accepte la connexion)
// En production, on validerait le token avec AuthManager
let user_id = params.user_id.or_else(|| {
    // Si un token est fourni, on pourrait extraire user_id du token
    // Pour l'instant, on utilise le user_id fourni dans les params
    None
});
```

**Cause racine** : Authentification WebSocket non implémentée (TODO)

**Fix minimal** :
```rust
// Dans websocket_handler
let token = params.token.ok_or_else(|| {
    tracing::warn!("WebSocket connection without token rejected");
    return StatusCode::UNAUTHORIZED;
})?;

let validation_result = auth_manager.validate_token(&token).await;
if !validation_result.valid {
    return StatusCode::UNAUTHORIZED.into_response();
}
```

**Plan de validation** :
1. Test : `wscat -c "ws://localhost:8082/ws"` (sans token)
2. Vérifier : Connexion rejetée
3. Test : Avec token valide, connexion acceptée

**Effet de bord** : Clients doivent fournir JWT pour WebSocket

**Effort** : M (4h)

---

### 4. **MOD-P0-004** : Secrets en clair dans k8s/secrets.yaml

**Impact** : Secrets commités dans Git (même si base64, facilement décodables)

**Preuve** :
```yaml:8:9:k8s/production/secrets.yaml
data:
  url: cG9zdGdyZXNxbDovL3ZlemE6c2VjdXJlX3Bhc3NAcG9zdGdyZXM6NTQzMi92ZXphX3Byb2Q=
```

**Cause racine** : Secrets de test commités par erreur

**Fix minimal** :
1. Supprimer `k8s/production/secrets.yaml` du repo
2. Ajouter à `.gitignore` : `**/secrets.yaml`
3. Documenter : Utiliser Sealed Secrets ou Vault

**Plan de validation** :
1. Vérifier : `git log --all --full-history -- k8s/production/secrets.yaml`
2. Vérifier : Fichier absent du repo
3. Test : Secrets créés via `kubectl create secret`

**Effet de bord** : Devs doivent créer secrets manuellement

**Effort** : S (30min)

---

### 5. **MOD-P1-005** : Rate limiting non implémenté (stub)

**Impact** : Pas de protection contre DoS, requêtes illimitées

**Preuve** :
```rust:57:73:src/middleware/rate_limit.rs
async fn check_rate_limit(state: &AppState, client_ip: &str) -> bool {
    // Implémentation basique du rate limiting
    // Dans une vraie application, on utiliserait un store externe comme Redis

    let max_requests_per_minute = state.config.security.rate_limit_requests_per_minute;
    let _now = Instant::now();

    // Pour cette implémentation basique, on permet toutes les requêtes
    // En production, il faudrait implémenter un vrai système de rate limiting
    tracing::debug!(
        client_ip = %client_ip,
        limit = max_requests_per_minute,
        "Vérification du rate limit"
    );

    true  // ⚠️ TOUJOURS TRUE
}
```

**Cause racine** : Implémentation placeholder non complétée

**Fix minimal** :
```rust
// Utiliser governor ou implémenter avec Redis
use governor::{Quota, RateLimiter};
let limiter = RateLimiter::keyed(Quota::per_minute(nonzero!(max_requests_per_minute)));
limiter.check_key(&client_ip).is_ok()
```

**Plan de validation** :
1. Test : 1000 requêtes rapides depuis même IP
2. Vérifier : Après 60 req/min, 429 Too Many Requests
3. Test : Différentes IPs, limites indépendantes

**Effet de bord** : Redis requis si implémentation distribuée

**Effort** : M (4h)

---

### 6. **MOD-P1-006** : Révocation JWT en mémoire (non persistant)

**Impact** : Tokens révoqués revalidés après redémarrage serveur

**Preuve** :
```rust:124:124:src/auth/mod.rs
revoked_tokens: Arc<tokio::sync::RwLock<HashMap<String, u64>>>, // session_id -> revocation_time
```

**Cause racine** : Stockage en mémoire pour simplicité

**Fix minimal** :
- Option 1 : Redis pour révocation (TTL = expiration token)
- Option 2 : DB table `revoked_tokens` (session_id, revoked_at, expires_at)

**Plan de validation** :
1. Test : Révoquer token, vérifier rejeté
2. Test : Redémarrer serveur, token toujours rejeté (si Redis/DB)
3. Test : Nettoyage automatique tokens expirés

**Effet de bord** : Redis/DB requis pour révocation persistante

**Effort** : M (4h)

---

### 7. **MOD-P1-007** : Validation signature HMAC avec timing attack possible

**Impact** : Attaque par timing pour deviner signature (faible mais présent)

**Preuve** :
```rust:194:195:src/utils/mod.rs
use subtle::ConstantTimeEq;
expected_sig.as_bytes().ct_eq(sig.as_bytes()).into()
```

✅ **DÉJÀ CORRIGÉ** : Utilise `subtle::ConstantTimeEq` (comparaison temps constant)

**Note** : Pas de problème, mais vérifier que tous les usages utilisent `ct_eq`

---

### 8. **MOD-P1-008** : Path traversal possible si validation bypass

**Impact** : Accès fichiers hors `AUDIO_DIR` (si validation contournée)

**Preuve** :
```rust:51:67:src/utils/mod.rs
pub fn build_safe_path(config: &Config, filename: &str) -> Result<PathBuf> {
    let audio_dir = Path::new(&config.audio_dir);
    let file_path = audio_dir.join(filename);

    // Utiliser un check basique au lieu de canonicalize qui nécessite que le fichier existe
    // Ceci est nécessaire pour les tests où audio_dir peut ne pas exister physiquement
    // Dans un environnement de prod, le dossier existe.
    // Pour la sécurité, on vérifie juste qu'il n'y a pas de composants ".." après normalisation
    
    // Note: std::fs::canonicalize requires file to exist. 
    // We can try to simplify path manually or just rely on validate_filename having rejected ".."
    
    // Pour une sécurité maximale tout en permettant les tests:
    let normalized_path = file_path; // validate_filename a déjà filtré ".."
    
    Ok(normalized_path)
}
```

**Cause racine** : `canonicalize()` nécessite fichier existant, donc contourné

**Fix minimal** :
```rust
// Vérifier que le chemin résolu est bien dans audio_dir
let canonical_audio_dir = std::fs::canonicalize(&config.audio_dir)?;
let canonical_file_path = std::fs::canonicalize(&file_path)?;
if !canonical_file_path.starts_with(&canonical_audio_dir) {
    return Err(AppError::Forbidden);
}
```

**Plan de validation** :
1. Test : `GET /stream/../../../etc/passwd?expires=...&sig=...`
2. Vérifier : 403 Forbidden ou 400 Bad Request
3. Test : Fichier valide dans `AUDIO_DIR`, doit fonctionner

**Effet de bord** : `AUDIO_DIR` doit exister (pas de problème en prod)

**Effort** : S (2h)

---

### 9. **MOD-P2-009** : Headers sécurité manquants (HSTS, CSP strict)

**Impact** : Vulnérabilités XSS, clickjacking (mitigé mais pas optimal)

**Preuve** :
```rust:178:183:src/middleware/security.rs
// HSTS (si HTTPS)
// Note: À activer uniquement en HTTPS
// headers.insert(
//     HeaderName::from_static("strict-transport-security"),
//     HeaderValue::from_static("max-age=31536000; includeSubDomains")
// );
```

**Cause racine** : HSTS commenté (nécessite HTTPS)

**Fix minimal** :
```rust
if config.tls_enabled() {
    headers.insert(
        HeaderName::from_static("strict-transport-security"),
        HeaderValue::from_static("max-age=31536000; includeSubDomains")
    );
}
```

**Plan de validation** :
1. Test : Requête HTTPS, vérifier header `Strict-Transport-Security`
2. Test : Requête HTTP, header absent

**Effet de bord** : Nécessite TLS configuré

**Effort** : S (1h)

---

### 10. **MOD-P2-010** : Injection SQL possible si requêtes non paramétrées

**Impact** : SQL injection si requêtes construites dynamiquement (non vérifié partout)

**Preuve** :
```rust:589:596:src/analytics/mod.rs
// Utiliser des requêtes SQL simples sans macros pour éviter les erreurs de driver
let total_sessions = sqlx::query(
    "SELECT COUNT(*) as count FROM play_sessions WHERE started_at BETWEEN ? AND ?",
)
.bind(start_ts)
.bind(end_ts)
```

✅ **DÉJÀ PROTÉGÉ** : Utilise `sqlx::query()` avec `.bind()` (requêtes paramétrées)

**Note** : Vérifier tous les usages de `sqlx::query!` et `sqlx::query_scalar!` utilisent des paramètres

---

## Autres Risques Sécurité (P2/P3)

### MOD-P2-011 : Secrets dans logs (potentiel)

**Impact** : Tokens JWT, secrets exposés dans logs

**Preuve** : Vérifier tous les `tracing::*!` ne loggent pas de secrets

**Fix** : Audit des logs, masquer tokens/secrets

**Effort** : M (4h)

---

### MOD-P2-012 : Pas de validation taille upload

**Impact** : DoS via upload fichiers énormes

**Preuve** : Endpoint upload non trouvé (peut-être absent)

**Fix** : Limiter taille body requests

**Effort** : S (2h)

---

### MOD-P3-013 : Dépendances obsolètes (vulnérabilités)

**Impact** : Vulnérabilités connues dans dépendances

**Preuve** :
- `axum 0.7` (latest: 0.8)
- `sqlx 0.7` (latest: 0.8)
- `jsonwebtoken 9.2` (latest: 10.2)

**Fix** : `cargo audit` + mise à jour dépendances

**Effort** : M (4h)

---

# PHASE D — ROBUSTESSE & OBSERVABILITÉ

## Logs structurés

**État** : ✅ Implémenté avec `tracing`

**Format** :
- Dev : Pretty (lisible)
- Prod : JSON (structuré)

**Champs contextuels** :
- `stream_id`, `user_id`, `track_id`, `client_ip`, `event`, etc.

**Rotation** :
- ✅ Configuré (via `tracing-appender`)
- Rotation : Daily (>100MB) ou Hourly (≤100MB)

**Niveaux** :
- `RUST_LOG` : `stream_server=info` (défaut)
- Filtrage par module possible

**Gaps** :
- ⚠️ Pas de corrélation `request_id` / `trace_id` automatique
- ⚠️ Logs fichiers optionnels (pas de config par défaut)

---

## Métriques

**État** : ✅ Prometheus intégré

**Endpoints** :
- `GET /metrics` : Métriques Prometheus

**Métriques disponibles** :
- Via `metrics` crate (0.22)
- Exporter : `metrics-exporter-prometheus` (0.13)

**Gaps** :
- ⚠️ Métriques custom non documentées
- ⚠️ Pas de dashboard Grafana fourni (template existe mais non déployé)

---

## Healthchecks

**État** : ✅ Implémenté

**Endpoints** :
- `GET /healthz` : Liveness (basique)
- `GET /readyz` : Readiness (détaillé)
- `GET /health` : Health détaillé

**Vérifications** :
- ✅ Database : Ping PostgreSQL
- ✅ Audio directory : Existence
- ✅ RabbitMQ : Connexion (mode dégradé si down)
- ✅ Services : Statut global

**Gaps** :
- ⚠️ Pas de vérification Redis (si activé)
- ⚠️ Pas de vérification FFmpeg disponible

---

## Timeouts / Retries / Circuit Breakers

**Timeouts** :
- ✅ HTTP : 30s (via `TimeoutLayer`)
- ✅ DB : 30s (connection timeout)
- ⚠️ WebSocket : Pas de timeout explicite
- ⚠️ FFmpeg : Pas de timeout (peut bloquer indéfiniment)

**Retries** :
- ✅ RabbitMQ : 3 retries avec backoff (2s)
- ⚠️ DB : Pas de retry automatique
- ⚠️ HTTP client (reqwest) : Pas de retry configuré

**Circuit Breakers** :
- ❌ Absent

---

## Gestion de charge

**Pool DB** :
- ✅ Configuré : 10 max, 1 min
- ✅ Timeouts : 30s acquire, 600s idle, 3600s max lifetime

**WebSocket** :
- ⚠️ Pas de limite de connexions
- ⚠️ Pas de backpressure

**Streaming** :
- ✅ `MAX_RANGE_SIZE` : 10MB
- ✅ `MAX_FILE_SIZE` : 100MB
- ⚠️ Pas de limite de streams simultanés

**FFmpeg** :
- ✅ `max_concurrent_jobs` : 4 (configurable)
- ⚠️ Pas de queue limit (peut consommer mémoire)

---

## Migrations / Compatibilité

**Migrations** :
- ✅ SQLx migrations : `migrations/`
- ✅ Auto-migration : `DB_MIGRATE_ON_START=true` (défaut)

**Tables** :
- `stream_jobs` : ✅ Migration 001
- `stream_segments` : ✅ Migration 002
- ⚠️ **FK vers `tracks`** : Table externe (backend Go), doit exister

**Compatibilité** :
- ⚠️ Pas de versioning de schéma
- ⚠️ Pas de rollback migrations

---

# PHASE E — PERFORMANCE & SCALABILITÉ

## Hotspots évidents

### 1. Allocations inutiles

**Preuve** :
- Clones de `AppState` (Arc mais clones fréquents)
- String allocations dans hot paths

**Fix** : Utiliser `Cow<str>`, `&str` où possible

**Effort** : M (4h)

---

### 2. Copies de buffers audio

**Preuve** : Streaming peut copier buffers inutilement

**Fix** : Utiliser `Bytes` (zero-copy) pour streaming

**Effort** : M (6h)

---

### 3. JSON sérialisation dans hot paths

**Preuve** : WebSocket messages sérialisés à chaque envoi

**Fix** : Cache sérialisation ou utiliser binaire (MessagePack)

**Effort** : L (8h)

---

### 4. Locks contention (DashMap/RwLock)

**Preuve** :
- `WebSocketManager.connections` : `RwLock<HashMap>`
- `SyncEngine` : Multiples `DashMap` / `RwLock`

**Fix** : Sharding, lock-free structures où possible

**Effort** : L (10h)

---

### 5. FFmpeg blocking dans async

**Preuve** : FFmpeg exécuté dans threads bloquants (correct) mais monitoring peut bloquer

**Fix** : Vérifier tous les appels FFmpeg sont dans `spawn_blocking`

**Effort** : M (4h)

---

## Streaming optimisations

**HTTP Range** :
- ✅ Implémenté avec `tokio::fs::File::seek`
- ✅ Streaming avec `ReaderStream` (pas de chargement complet en mémoire)

**HLS** :
- ⚠️ Génération playlists synchrones (peut bloquer)
- ⚠️ Segments non pré-générés (génération à la volée)

**WebSocket** :
- ✅ Broadcast channel (1000 capacity)
- ⚠️ Pas de compression WebSocket (per-message deflate)

---

## Rust-specific

**Async runtime** :
- ✅ Tokio 1.35 (à jour)
- ⚠️ Pas de tuning runtime (threads, etc.)

**Blocking in async** :
- ⚠️ Vérifier tous les I/O bloquants sont dans `spawn_blocking`

**Memory** :
- ⚠️ Pas de profiling mémoire
- ⚠️ Pas de limites mémoire explicites

---

# PHASE F — LISTE EXHAUSTIVE DES PROBLÈMES

## P0 — Bloquants (Sécurité / Crash / Build)

| ID | Titre | Impact | Preuve | Cause | Fix | Validation | Effet de bord | Effort |
|----|-------|--------|--------|-------|-----|------------|---------------|--------|
| **MOD-P0-001** | CORS permissif `*` par défaut | CSRF, accès non autorisé | `src/config/mod.rs:340`, `src/routes/api.rs:38` | Default trop permissif | Require `ALLOWED_ORIGINS` en prod | Test CORS depuis origine non autorisée | Devs doivent configurer | S (1h) |
| **MOD-P0-002** | Endpoint `/internal/jobs/transcode` non authentifié | DoS, jobs transcodage illimités | `src/routes/api.rs:118,146` | Endpoint interne exposé | Ajouter middleware auth | Test POST sans token → 401 | Services internes doivent s'auth | S (1h) |
| **MOD-P0-003** | WebSocket sans auth obligatoire | Streaming anonyme possible | `src/streaming/websocket.rs:802` | Auth non implémentée | Valider JWT avant connexion | Test WS sans token → rejet | Clients doivent fournir JWT | M (4h) |
| **MOD-P0-004** | Secrets en clair dans Git | Secrets compromis | `k8s/production/secrets.yaml:8` | Secrets commités | Supprimer du repo, utiliser Sealed Secrets | Vérifier fichier absent | Devs créent secrets manuellement | S (30min) |
| **MOD-P0-005** | Table `tracks` externe non vérifiée | FK violations, crashes | `migrations/001_create_stream_jobs.sql:14` | Dépendance externe non validée | Vérifier existence table au démarrage | Test FK violation → erreur claire | Backend Go doit créer table | S (2h) |

## P1 — Critiques (Bugs fréquents / Dette bloquante)

| ID | Titre | Impact | Preuve | Cause | Fix | Validation | Effet de bord | Effort |
|----|-------|--------|--------|-------|-----|------------|---------------|--------|
| **MOD-P1-006** | Rate limiting stub (toujours `true`) | Pas de protection DoS | `src/middleware/rate_limit.rs:72` | Implémentation placeholder | Implémenter avec `governor` ou Redis | Test 1000 req → 429 après limite | Redis requis si distribué | M (4h) |
| **MOD-P1-007** | Révocation JWT en mémoire | Tokens révoqués revalidés après restart | `src/auth/mod.rs:124` | Stockage non persistant | Redis ou DB pour révocation | Test révocation → restart → toujours rejeté | Redis/DB requis | M (4h) |
| **MOD-P1-008** | Path traversal si validation bypass | Accès fichiers hors `AUDIO_DIR` | `src/utils/mod.rs:51` | `canonicalize()` contourné | Vérifier chemin résolu dans `AUDIO_DIR` | Test `../../../etc/passwd` → 403 | `AUDIO_DIR` doit exister | S (2h) |
| **MOD-P1-009** | 174 `unwrap()` / `expect()` | Panics en production | `grep -r "unwrap\|expect" src/` (174 matches) | Gestion erreurs incomplète | Remplacer par `?` ou `match` | Test erreurs → pas de panic | Code plus verbeux | L (20h) |
| **MOD-P1-010** | FFmpeg sans timeout | Jobs peuvent bloquer indéfiniment | `src/transcoding/engine.rs` (à vérifier) | Pas de timeout configuré | Ajouter timeout FFmpeg (5min) | Test job bloqué → timeout | Jobs longs peuvent échouer | S (2h) |
| **MOD-P1-011** | WebSocket pas de limite connexions | DoS mémoire | `src/streaming/websocket.rs:231` | Pas de limite | Limiter connexions (1000 max) | Test 2000 connexions → rejet | Clients peuvent être rejetés | S (2h) |
| **MOD-P1-012** | HLS segments générés à la volée | Latence première requête | `src/routes/api.rs:356` | Pas de pré-génération | Pré-générer segments lors transcodage | Test première requête → rapide | Stockage requis | M (6h) |
| **MOD-P1-013** | Pas de tests intégration | Bugs non détectés | Aucun test dans `tests/` | Tests manquants | Ajouter tests intégration | `cargo test --test integration` | Maintenance tests | L (16h) |

## P2 — Majeurs (Qualité / Maintenabilité)

| ID | Titre | Impact | Preuve | Cause | Fix | Validation | Effet de bord | Effort |
|----|-------|--------|--------|-------|-----|------------|---------------|--------|
| **MOD-P2-014** | 109 warnings Clippy | Qualité code dégradée | `cargo clippy` (109 warnings) | Warnings non traités | Corriger warnings | `cargo clippy` → 0 warnings | Code plus strict | M (8h) |
| **MOD-P2-015** | Dépendances obsolètes | Vulnérabilités, perf | `Cargo.toml` (axum 0.7, sqlx 0.7) | Pas de mise à jour | `cargo update` + tests | `cargo audit` → 0 vulns | Tests de régression | M (4h) |
| **MOD-P2-016** | Pas de `request_id` / `trace_id` | Debugging difficile | Logs sans corrélation | Pas implémenté | Middleware `request_id` | Test logs → même `request_id` | Overhead minimal | M (4h) |
| **MOD-P2-017** | HSTS manquant (si HTTPS) | Man-in-the-middle | `src/middleware/security.rs:178` | Commenté | Activer si TLS | Test HTTPS → header HSTS | Nécessite TLS | S (1h) |
| **MOD-P2-018** | Pas de circuit breaker | Cascading failures | Absent | Pas implémenté | Ajouter circuit breaker (DB, Redis) | Test DB down → circuit ouvert | Retries échouent plus tôt | M (6h) |
| **MOD-P2-019** | Pas de retry DB | Erreurs transitoires non récupérées | `src/database/pool.rs` | Pas de retry | Ajouter retry avec backoff | Test DB temporairement down → retry | Latence augmentée | S (2h) |
| **MOD-P2-020** | Pas de monitoring Redis | État Redis inconnu | Health check ne vérifie pas Redis | Non implémenté | Ajouter check Redis dans health | Test Redis down → health degraded | Redis requis | S (1h) |
| **MOD-P2-021** | Pas de compression WebSocket | Bande passante gaspillée | `src/streaming/websocket.rs` | Pas activé | Activer per-message deflate | Test taille messages → réduite | CPU légèrement augmenté | S (2h) |
| **MOD-P2-022** | Pas de pré-génération HLS | Latence première requête | `src/routes/api.rs:356` | Génération à la volée | Pré-générer lors transcodage | Test première requête → rapide | Stockage requis | M (6h) |
| **MOD-P2-023** | Pas de cache Redis pour métadonnées | Requêtes DB répétées | `src/cache/audio_cache.rs` | Cache fichiers uniquement | Cache DB queries | Test requêtes répétées → cache hit | Redis requis | M (4h) |
| **MOD-P2-024** | Pas de backpressure WebSocket | Mémoire illimitée | `src/streaming/websocket.rs:248` | Pas de limite | Limiter buffer messages | Test messages rapides → backpressure | Messages peuvent être perdus | M (4h) |
| **MOD-P2-025** | Pas de profiling mémoire | Fuites mémoire non détectées | Absent | Pas d'outil | Ajouter `dhat` ou `valgrind` | Test fuites → détectées | Overhead profiling | S (2h) |

## P3 — Mineurs (Cosmétique / Refactors)

| ID | Titre | Impact | Preuve | Cause | Fix | Validation | Effet de bord | Effort |
|----|-------|--------|--------|-------|-----|------------|---------------|--------|
| **MOD-P3-026** | Documentation cargo doc incomplète | DX dégradée | `cargo doc` (docstrings manquantes) | Pas de doc | Ajouter docstrings | `cargo doc --open` → docs complètes | Maintenance docs | M (8h) |
| **MOD-P3-027** | Tests unitaires manquants | Couverture faible (~25%) | `cargo test` (peu de tests) | Tests non écrits | Ajouter tests unitaires | `cargo test --coverage` → >80% | Maintenance tests | L (20h) |
| **MOD-P3-028** | Pas de benchmarks | Performance non mesurée | `cargo bench` (peu de benches) | Benchmarks manquants | Ajouter benchmarks | `cargo bench` → métriques | Maintenance benches | M (6h) |
| **MOD-P3-029** | Code dupliqué (validation patterns) | Maintenance difficile | Plusieurs fichiers | Pas de factorisation | Extraire helpers | Test factorisation → moins de code | Refactor | M (4h) |
| **MOD-P3-030** | Pas de migration rollback | Rollback impossible | `migrations/` (pas de down) | Pas implémenté | Ajouter migrations down | Test rollback → succès | Maintenance migrations | M (4h) |

---

# PHASE G — PLAN D'EXÉCUTION

## Checklist P0 (Ordre strict)

1. **MOD-P0-004** : Supprimer secrets du repo (30min)
   - Supprimer `k8s/production/secrets.yaml`
   - Ajouter à `.gitignore`
   - Documenter Sealed Secrets

2. **MOD-P0-001** : Fix CORS permissif (1h)
   - Require `ALLOWED_ORIGINS` en prod
   - Test CORS

3. **MOD-P0-002** : Auth endpoint transcodage (1h)
   - Ajouter middleware auth
   - Test 401 sans token

4. **MOD-P0-005** : Vérifier table `tracks` (2h)
   - Check existence au démarrage
   - Erreur claire si absente

5. **MOD-P0-003** : Auth WebSocket (4h)
   - Valider JWT avant connexion
   - Test rejet sans token

**Total P0** : ~8h (1 jour)

---

## Checklist P1 (Par lots cohérents)

### Lot 1 : Rate limiting + Révocation (8h)

6. **MOD-P1-006** : Implémenter rate limiting (4h)
7. **MOD-P1-007** : Révocation JWT persistante (4h)

### Lot 2 : Sécurité paths + FFmpeg (4h)

8. **MOD-P1-008** : Fix path traversal (2h)
9. **MOD-P1-010** : Timeout FFmpeg (2h)

### Lot 3 : WebSocket + HLS (10h)

10. **MOD-P1-011** : Limite connexions WS (2h)
11. **MOD-P1-012** : Pré-génération HLS (6h)
12. **MOD-P1-013** : Tests intégration (2h, début)

### Lot 4 : Gestion erreurs (20h)

13. **MOD-P1-009** : Remplacer `unwrap()` (20h, progressif)

**Total P1** : ~42h (1 semaine)

---

## Quick Wins (≤ 1h chacun)

- **MOD-P2-017** : HSTS si HTTPS (1h)
- **MOD-P2-020** : Monitoring Redis (1h)
- **MOD-P2-021** : Compression WebSocket (2h)
- **MOD-P2-019** : Retry DB (2h)

**Total Quick Wins** : ~6h

---

## Tests à ajouter en priorité

1. **Tests WebSocket** (4h)
   - Connexion, messages, déconnexion
   - Auth, rate limiting

2. **Tests streaming HTTP** (4h)
   - Range requests, signatures, path traversal

3. **Tests transcodage** (6h)
   - FFmpeg pipeline, HLS generation, timeouts

4. **Tests intégration** (8h)
   - End-to-end streaming, WebSocket sync

**Total Tests** : ~22h

---

## PR Plan

### PR 1 : Sécurité critique (P0)
**Titre** : `fix(security): Remove secrets from repo, fix CORS, add auth to internal endpoints`

**Changements** :
- MOD-P0-004 : Secrets
- MOD-P0-001 : CORS
- MOD-P0-002 : Auth transcodage

**Tests** : Tests sécurité ajoutés

---

### PR 2 : WebSocket auth
**Titre** : `feat(websocket): Add JWT authentication to WebSocket connections`

**Changements** :
- MOD-P0-003 : Auth WebSocket

**Tests** : Tests WebSocket auth

---

### PR 3 : Rate limiting + Révocation
**Titre** : `feat(security): Implement rate limiting and persistent JWT revocation`

**Changements** :
- MOD-P1-006 : Rate limiting
- MOD-P1-007 : Révocation

**Tests** : Tests rate limiting

---

### PR 4 : Path traversal + FFmpeg timeout
**Titre** : `fix(security): Fix path traversal validation and add FFmpeg timeout`

**Changements** :
- MOD-P1-008 : Path traversal
- MOD-P1-010 : FFmpeg timeout

**Tests** : Tests sécurité

---

### PR 5 : WebSocket improvements
**Titre** : `feat(websocket): Add connection limits and compression`

**Changements** :
- MOD-P1-011 : Limite connexions
- MOD-P2-021 : Compression

**Tests** : Tests WebSocket

---

### PR 6 : HLS pré-génération
**Titre** : `feat(hls): Pre-generate HLS segments during transcoding`

**Changements** :
- MOD-P1-012 : Pré-génération HLS

**Tests** : Tests HLS

---

### PR 7 : Tests intégration
**Titre** : `test: Add integration tests for streaming and WebSocket`

**Changements** :
- MOD-P1-013 : Tests intégration

---

### PR 8 : Code quality
**Titre** : `chore: Fix Clippy warnings and update dependencies`

**Changements** :
- MOD-P2-014 : Clippy
- MOD-P2-015 : Dépendances

---

### PR 9 : Observabilité
**Titre** : `feat(observability): Add request_id, Redis monitoring, circuit breakers`

**Changements** :
- MOD-P2-016 : Request ID
- MOD-P2-020 : Redis monitoring
- MOD-P2-018 : Circuit breakers

---

### PR 10 : Gestion erreurs (progressif)
**Titre** : `refactor: Replace unwrap() with proper error handling`

**Changements** :
- MOD-P1-009 : Remplacer `unwrap()` (par lots)

**Tests** : Tests erreurs

---

## Estimation Totale

| Priorité | Problèmes | Effort | Délai |
|----------|-----------|--------|-------|
| **P0** | 5 | 8h | 1 jour |
| **P1** | 8 | 42h | 1 semaine |
| **P2** | 12 | 40h | 1 semaine |
| **P3** | 5 | 42h | 1 semaine |
| **Tests** | - | 22h | 3 jours |
| **TOTAL** | **30** | **154h** | **~4 semaines** |

---

# CONCLUSION

Le module **veza-stream-server** est **fonctionnel** mais présente des **gaps critiques de sécurité et de robustesse** qui doivent être corrigés avant production.

**Points forts** :
- Architecture solide (Axum, Tokio, SQLx)
- Logging structuré (tracing)
- Métriques Prometheus
- Health checks

**Points faibles** :
- Sécurité : CORS permissif, endpoints non authentifiés
- Robustesse : Rate limiting stub, révocation JWT non persistante
- Tests : Couverture faible (~25%)
- Performance : Pas de benchmarks, optimisations manquantes

**Recommandation** : **Ne pas déployer en production** avant correction des **P0** et **P1 critiques** (sécurité).

**Prochaines étapes** :
1. Corriger P0 (1 jour)
2. Corriger P1 critiques (1 semaine)
3. Ajouter tests (3 jours)
4. Code review sécurité
5. Déploiement staging
6. Tests charge
7. Déploiement production

---

**Fin du rapport d'audit**

