Aller au contenu

PD-19 — Retour d'expérience (REX)

1. Résumé exécutif

Métrique Valeur
Objectif initial Configurer CORS, security headers et rate limiting global
Résultat obtenu Conforme — 12/12 invariants couverts
Verdict final GO (Gate 8)
Tests contractuels 61/61 passés

2. Métriques de convergence

2.1 Temps et itérations

Étape Durée estimée Durée réelle Itérations Écart
0 - Besoin 30 min 30 min 1 0%
1 - Spécification 2h 2h 1 0%
2 - Tests 1h 1h 1 0%
3 - Gate spec 1h 3h 2 +200%
4 - Plan 1h 1.5h 1 +50%
5 - Gate plan 1h 2h 2 +100%
6 - Implémentation 4h 5h 1 +25%
7 - Acceptabilité 2h 2h 2 0%
8 - Gate acceptabilité 1h 1.5h 1 +50%
9 - REX 30 min 30 min 1 0%
TOTAL ~14h ~18.5h 13 +32%

2.2 Scores de convergence par gate

Gate Score v1 Score final Delta Itérations
Gate 3 5.25/10 7.50/10 +2.25 2
Gate 5 7.75/10 8.50/10 +0.75 2
Gate 8 8.0/10 8.0/10 0 1

2.3 Écarts par catégorie

Catégorie d'écart Gate 3 Gate 5 Gate 8 Total
ECT (complétude/testabilité) 7 0 2 9
DIV (divergence spec/impl) 5 1 0 6
AMB (ambiguïté) 2 2 0 4
SEC (sécurité) 1 0 1 2
PERF (performance) 0 0 0 0
TOTAL écarts 15 3 3 21

3. Points fluides

Ce qui a bien fonctionné : - Extension de l'existant : Helmet v7.1.0, CORS natif, RateLimitService Redis — aucune nouvelle dépendance requise - ConfigModule avec validation Joi : fail-fast naturel, multi-env sans modification de code - Pattern middleware NestJS : séparation claire des responsabilités (SecurityHeaders → CORS → RateLimit) - Code contracts YAML : contrat d'interface explicite accélérant l'implémentation et les tests - Correction automatique Gate 3→v2 : delta +2.25 en une itération (prompt de correction complet)

4. Points difficiles

Obstacles rencontrés : - Spec v1 rejetée : 4 paramètres contractuels critiques absents (socle headers, CORS, seuils limitation, eIDAS) - 8 règles non testables : critères d'acceptation non mesurables — score testability 4/10 - Trust proxy et X-Forwarded-For : vulnérabilité XFF bypass identifiée en review sécurité (SEC-01 HIGH) - Validation IPv6 permissive : regex insuffisante (SEC-02 HIGH) - Headers sur erreurs : res.on('finish') nécessaire pour garantir les headers sur 404/500/429

5. Hypothèses révélées tardivement

Hypothèses non explicites découvertes en cours de workflow : - eIDAS non testable HTTP — découverte à l'étape 3 : les exigences de valeur probatoire (signature, horodatage qualifié) ne sont pas observables au niveau HTTP pur → exclusion explicite du périmètre - Rétention 90 jours = infra — découverte à l'étape 5 : la rétention des logs de sécurité est une configuration infrastructure (ELK/Loki lifecycle) et non applicative - Vary: Origin obligatoire — découverte à l'étape 8 : header nécessaire pour éviter les problèmes de cache CORS multi-origines

6. Invariants complexes

Invariants difficiles à implémenter ou sensibles aux régressions : - INV-01 (socle headers) + INV-11 (headers sur erreurs) — TC-NOM-05, TC-ERR-02 : garantir les headers même sur les exceptions non gérées via res.on('finish') plutôt que dans le middleware - INV-06 (résolution IP) — TC-INT-01 : chaîne de proxy de confiance avec Express trust proxy et validation de X-Forwarded-For - INV-07 (format 429) — TC-ERR-04 : corps JSON exact {"error":"rate_limited","message":"Too many requests","retryAfter":<seconds>}

7. Dette technique

Compromis acceptés et non bloquants : - ECT-01 (indépendance métier) — impact: faible : preuve par analyse code, pas par test explicite ; à documenter dans architecture - ECT-02 (format logs) — impact: faible : format JSON UTC couvert par configuration du transport (Winston/Pino), pas de test unitaire dédié - ECT-04 (Vary: Origin) — impact: faible : implémenté via res.setHeader() au lieu de res.vary() ; amélioration cosmétique future - TC-NOM-06 absent — impact: moyen : pas de test explicite de la journalisation ; couvert par tests d'intégration implicites

8. Risques résiduels

Risque Type Probabilité Impact Mitigation
Redis indisponible → fail-open tech faible moyen Monitoring alerting + fallback in-memory (dégradé)
X-Forwarded-For forgé hors trust chain sec faible moyen Validation stricte TRUSTED_PROXIES
Cache preflight trop long (600s prod) ops faible faible Ajustable via configuration
RGPD rétention IP 90 jours legal moyen moyen Base légale intérêt légitime + politique protection données

9. Patterns récurrents détectés

9.1 Patterns confirmés (déjà vus dans d'autres stories)

  • Fail-fast config sécurité — aussi dans PD-22 (config Vault), PD-240 (account deletion)
  • Validation croisée LLM — ChatGPT review / Claude implémentation — pattern standard du workflow
  • Rate limiting Redis atomique — aussi dans PD-238 (MFA), guards auth existants
  • Code contracts YAML — standard depuis PD-19

9.2 Nouveaux patterns identifiés

  • res.on('finish') pour headers universels — à surveiller : garantit les headers même sur exceptions non catchées
  • Trust proxy Express + TRUSTED_PROXIES env — pattern à documenter pour tous les rate limitings
  • CORS contractuel sans wildcard — origines explicites par environnement, pas de * même en dev

10. Améliorations du workflow

10.1 Améliorations des prompts/templates

Fichier Amélioration suggérée Priorité
docs/prompts/1 Specification.md Ajouter checklist : "tous les paramètres contractuels ont des valeurs explicites et testables" haute
docs/prompts/3 Spécification – Review.md Ajouter critère : "chaque invariant a au moins un observable mesurable" moyenne
docs/templates/PD-XX-tests.md Ajouter section "Règles non testables (justification)" moyenne

10.2 Améliorations des agents

Agent Amélioration suggérée Justification
agent-adversarial Ajouter check XFF/trust proxy dans review sécurité SEC-01 identifié tardivement
agent-metier Clarifier la frontière périmètre testable HTTP vs eIDAS Éviter les ambiguïtés eIDAS

10.3 Améliorations du processus

  • Synchroniser PD-XX-tests.md après correction spec : le document de tests v1 n'a pas été mis à jour après la correction spec v2 (DIV-02 Gate 3 v2)
  • Ajouter ticket suivi pour réserves infra : la rétention 90 jours (DIV-04 Gate 5) nécessite un ticket infra séparé

11. Enseignements clés

  1. Paramètres contractuels explicites dès la spec — Les critères d'acceptation non mesurables (socle headers sans liste, CORS sans origines) sont les premières causes de rejet Gate 3. Définir les valeurs exactes dès l'étape 1.

  2. Headers sur erreurs = res.on('finish') — Les security headers doivent être appliqués même sur les réponses d'erreur. Le pattern res.on('finish') garantit cette couverture là où les middlewares classiques échouent.

  3. Trust proxy est une surface d'attaque — La résolution IP via X-Forwarded-For sans validation de la chaîne de confiance permet le bypass du rate limiting. Configurer trust proxy de manière restrictive.

  4. Faux positifs reviews LLM = lecture partielle — Les 2 faux positifs Gate 5 (credentials/exposedHeaders "absents") étaient causés par la lecture de résumés plutôt que des documents complets. Injecter les documents inline.

  5. Rétention logs = configuration infra — La rétention de 90 jours (INV-09) n'est pas codée dans l'application mais dans la configuration du système de logging (ELK lifecycle). Documenter comme prérequis déploiement.

12. Métriques cumulatives

Métrique Cette story Moyenne projet Tendance
Temps total 18.5h 16h
Itérations gates 5 4.5
Écarts totaux 21 18
Score convergence moyen 7.75/10 7.9/10

Document produit par le workflow de gouvernance IA — Étape 9 (Claude mode créatif) Date : 2026-02-10