Session 14 — Chaos Métier Niveau Master (A12–A16) + Chaos Sécurité revue complète¶
Durée : ~5 heures (1 conversation Claude)
Objectif initial : Ajouter le niveau 4 Master au Chaos Métier — anomalies fonctionnelles avancées
Objectif final : 5 anomalies Master implémentées (A12–A16), UI pédagogique frontend, revue sécurité complète + 8 bugs corrigés
🎯 Réalisations¶
1. Chaos Métier — Niveau 4 Master (A12–A16)¶
Temps : ~2h30
Difficulté : ⭐⭐⭐⭐
Extension du système de chaos métier avec 5 anomalies fonctionnelles ciblant la validation de données et la cohérence métier — toutes silencieuses (aucune erreur HTTP), détectables uniquement par assertions sur les données.
Anomalies implémentées¶
| Code | Nom | Mécanisme | Détection recommandée |
|---|---|---|---|
| A12 | Remise fidélité silencieuse | orderCount > 5 → condition != -999 toujours vraie → remise -5% jamais accordée |
Comparer total payé vs calcul attendu sur compte avec historique |
| A13 | Devise affichage USD | getCurrency() retourne "USD" au lieu d"EUR" dans /api/products |
Parser réponse API, valider champ currency |
| A14 | Frais de port doublés | shippingCost × 2 dans le total commande |
Comparer total vs (prix × TVA) + frais port attendu |
| A15 | Corruption historique ×1.1 | GET /api/orders retourne totaux × 1.1 |
Croiser total création commande vs total historique |
| A16 | Annulation sans remboursement stock | cancelOrder ne recrédite pas le stock |
Vérifier stock avant/après commande/après annulation |
Fil rouge pédagogique
Toutes les anomalies Master sont silencieuses — aucune erreur HTTP, aucune exception visible. Elles nécessitent des assertions de données (validation métier) pour être détectées. C'est l'enjeu du niveau Master : passer de la détection d'erreurs techniques à la validation fonctionnelle.
Interaction A14 × A1 (cumul niveaux)¶
En niveau 4, A1 (TVA 19,6%) est aussi active. Formule effective cumulative :
Cette interaction est documentée par un commentaire pédagogique dans OrderService.java.
Architecture backend¶
BusinessChaosService.java — 5 nouvelles méthodes :
- applyLoyaltyDiscount(total, orderCount, orderNumber, email) → A12
- getCurrency() → A13 — retourne "USD" en niveau 4, "EUR" sinon
- applyShippingCost(cost, orderNumber, email) → A14
- applyHistoryCorruption(amount, orderNumber) → A15
- shouldRestockOnCancel(orderNumber, email) → A16
OrderController.java — hooks A15 + A16 :
- getUserOrders() : applyHistoryCorruption() sur chaque totalAmount avant retour
- cancelOrder() : shouldRestockOnCancel() conditionne le recrédit stock
- Requête changée : findByIdWithUser → findByIdWithItemsAndUser (nouvelle méthode repository)
OrderService.java — hooks A14 + A12 dans createOrderFromItems() :
- A14 : effectiveShipping = applyShippingCost(shippingCost) avant accumulation articles
- A12 : applyLoyaltyDiscount(total, orderCount) après TVA (A1)
ProductController.java — hook A13 :
- getAllProducts() : si getCurrency() retourne "USD" → wrapper Map avec currency: "USD"
- N0-3 : retour ResponseEntity.ok(products) strictement identique
OrderRepository.java — nouvelle requête JPQL :
@Query("SELECT o FROM Order o JOIN FETCH o.user LEFT JOIN FETCH o.orderItems i LEFT JOIN FETCH i.product WHERE o.id = :id")
Optional<Order> findByIdWithItemsAndUser(@Param("id") Long id);
Modifications BusinessChaosService.java¶
setLevel(): validation étendue à0-4labelOf(): case 4 →"Master"levelName(): case 4 →"Niveau 4 — Master"anomalyCount(): case 4 → 16anomalyList(): case 4 → liste A1–A16anomalyDescriptions(): blocif (l >= 4)avec descriptions A12–A16getCounters(): entréesA12_loyalty,A13_currency,A14_shipping,A15_history,A16_cancelreset():cntA12.set(0)àcntA16.set(0)
2. Frontend React — UI pédagogique¶
Temps : ~45 min
Difficulté : ⭐⭐
Deux indicateurs pédagogiques visibles dans l'interface — permettent aux étudiants de valider leur compréhension des anomalies.
Bannière Fidélité — MyOrders.jsx¶
Bannière violette en haut de la page "Mes commandes" indiquant le statut du programme fidélité :
- Badge "✓ Éligible" si
orders.length >= 6→ la remise devrait s'appliquer - Badge "N/6" sinon (ex :
3/6) - Compteur basé sur TOUTES les commandes (y compris
CANCELLED) pour correspondre exactement àcountByUserId()côté backend
// Alignement intentionnel avec le backend
const loyaltyCount = orders.length; // TOUTES commandes, pas seulement ACTIVE
const isLoyaltyEligible = loyaltyCount >= 6;
Piège pédagogique
En niveau 4, la bannière affiche "✓ Éligible" et la remise "s'applique automatiquement" — mais A12 la supprime silencieusement. L'étudiant voit le message, paie le prix plein, et doit détecter l'écart par assertion sur le total.
Bandeau devise — Products.jsx¶
Bandeau jaune d'avertissement ⚠️ Les prix sont affichés en USD visible uniquement quand currency !== 'EUR' (i.e. en niveau 4 uniquement).
- State
currencyinitialisé à'EUR' fetchProducts():setCurrency(data.currency || 'EUR')— fallback'EUR'si champ absent- Bandeau conditionnel
{currency !== 'EUR'}— invisible en N0-3
3. Revue chaos sécurité — non-régression complète¶
Temps : ~45 min
Audit complet de tous les fichiers consommateurs de SecurityChaosService après les modifications de la session.
| Faille | Controller | Modifié session 14 ? |
|---|---|---|
| S1 SQLi | ProductController |
✅ Non (seul getAllProducts modifié — searchProducts inchangé) |
| S2 IDOR | OrderController |
✅ Non |
| S3 Hash exposé | UserController |
✅ Non |
| S4 XSS stocké | OrderController |
✅ Non |
| S5 Prix falsifié | OrderController |
✅ Non |
| S6 Timing attack | AuthController |
✅ Non |
| S7 Token faible | AuthController |
✅ Non |
| S8 Path traversal | OrderController |
✅ Non |
| S9 Mass assignment | UserController |
✅ Non |
| S10–S12 Portail admin | AdminPortalController |
✅ Non |
Conclusion : aucune régression sécurité — les deux corrections dans OrderController (getUserOrders et createOrderFromItems) sont dans des méthodes entièrement séparées des hooks sécurité.
🐛 Bugs corrigés¶
| # | Fichier | Bug | Correction | Sévérité |
|---|---|---|---|---|
| 1 | Products.jsx |
if (data.currency) ne réinitialisait pas à 'EUR' au retour en N0-3 |
setCurrency(data.currency \|\| 'EUR') |
⭐⭐ |
| 2 | MyOrders.jsx |
orders.filter(o => o.status !== 'CANCELLED').length divergeait de countByUserId() backend |
orders.length (toutes commandes) |
⭐⭐⭐ |
| 3 | MyOrders.jsx |
"devrait s'appliquer" suggérait une incertitude côté UI | "s'applique automatiquement" | ⭐ |
| 4 | monitoring.html |
Texte Sortie parasite en ligne 1 avant <!DOCTYPE html> |
Suppression | ⭐⭐ |
| 5 | BusinessChaosController.java |
Javadoc { "level": 0-3 } incorrect |
Corrigé en 0-4 |
⭐ |
| 6 | OrderService.java |
Interaction A14×A1 non documentée | Commentaire pédagogique ajouté | ⭐ |
| 7 | OrderController.java |
Cast row[2] silencieux si type inattendu (BigDecimal vs autre) |
Cast défensif 3 niveaux : null / BigDecimal / toString() |
⭐⭐⭐ |
| 8 | OrderService.java |
orderNumber dans log A14 = "pending-email" au lieu de ORD-xxx |
order.getOrderNumber() (appelé après buildOrderWithCard) |
⭐⭐ |
🤖 Erreurs imputables à Claude AI — Session 14¶
❌ Erreur S14-1 — if (data.currency) sans fallback¶
Ce que j'ai proposé : dans Products.jsx, if (data.currency) setCurrency(data.currency) — ce qui laisse currency à "USD" même après retour en niveau 0-3 (car l'API retourne alors products[] sans champ currency).
Ce qui s'est passé : le bandeau "USD" restait visible après désactivation du chaos — régression UX détectée lors de la revue.
Pourquoi c'était une erreur : ne pas avoir anticipé le cas "champ absent = retour à la valeur par défaut" — pattern courant en React avec des réponses API variables.
Temps perdu : ~5 min | Sévérité : ⭐⭐
❌ Erreur S14-2 — Compteur fidélité excluant les commandes annulées¶
Ce que j'ai proposé : orders.filter(o => o.status !== 'CANCELLED').length pour le compteur fidélité dans MyOrders.jsx.
Ce qui s'est passé : le backend utilise countByUserId() qui compte toutes les commandes sans filtre — l'UI divergeait donc du comportement backend, rendant l'anomalie A12 non reproductible proprement.
Pourquoi c'était une erreur : ne pas avoir audité l'implémentation backend countByUserId() avant de coder la logique frontend.
Temps perdu : ~10 min | Sévérité : ⭐⭐⭐
📊 Récapitulatif Session 14¶
| # | Erreur | Temps perdu | Sévérité |
|---|---|---|---|
| S14-1 | Fallback currency manquant dans Products.jsx | ~5 min | ⭐⭐ |
| S14-2 | Compteur fidélité frontend/backend désaligné | ~10 min | ⭐⭐⭐ |
| TOTAL | ~15 min |
Pattern : ne pas auditer l'implémentation backend avant de coder la logique frontend miroir — les deux côtés doivent utiliser exactement les mêmes règles de comptage/calcul.
📁 Fichiers modifiés¶
Backend Java¶
chaos/BusinessChaosService.java— compteurs A12–A16, 5 méthodes, reset, labels, descripteurscontroller/BusinessChaosController.java— validationlevel > 4, javadoc corrigéecontroller/OrderController.java— hooks A15 (history corruption) + A16 (restock cancel), cast défensifrow[2], requêtefindByIdWithItemsAndUsercontroller/ProductController.java— hook A13 (currency USD), injectionBusinessChaosServiceservice/OrderService.java— hooks A14 (shipping ×2) + A12 (loyalty discount), commentaire A14×A1repository/OrderRepository.java— méthodefindByIdWithItemsAndUser
Frontend React¶
pages/MyOrders.jsx— bannière programme fidélité, compteur toutes commandespages/Products.jsx— statecurrency, bandeau USD conditionnel, fallback'EUR'
Monitoring¶
monitoring/public/admin/monitoring.html— suppression texte parasiteSortie, tableau anomalies A1–A16,LEVEL_THRESHOLDS.master = 4
🎓 Conclusion Session 14¶
✅ Chaos Métier niveau 4 Master — 5 anomalies A12–A16, toutes silencieuses, nécessitant assertion de données
✅ Interaction A14×A1 documentée — formule cumulative commentée dans OrderService.java
✅ UI pédagogique — bannière fidélité MyOrders.jsx + bandeau devise Products.jsx
✅ 8 bugs corrigés — dont 2 divergences frontend/backend sur des règles de calcul
✅ Revue sécurité complète — 12 failles S1–S12 auditées, zéro régression
✅ Non-régression chaos — A1–A11, Scripting, Fonctionnel, Sécurité inchangés
Ratio temps productif / temps total : ~95%
Total cumulé projet : ~87h de vibe coding sur 14 sessions
Prochaine étape : Build Docker perfshop-backend:v34 + perfshop-frontend:v34, déploiement NAS — puis mise à jour mkdocs/docs/chaos/business.md et roadmap