Aller au contenu

Chaos Métier

Le Chaos Métier injecte des anomalies fonctionnelles dans le parcours e-commerce de PerfShop. Contrairement au Chaos Backend (dégradation infrastructure) ou au Chaos Scripting (tokens HTTP), ces anomalies touchent la logique applicative : prix, stock, commandes, livraison.


Principe pédagogique

Les étudiants doivent identifier et noter les anomalies — pas les corriger.

Règle d'or

Avec les bonnes données de test, une commande doit toujours pouvoir aboutir, quel que soit le niveau de chaos actif.

Les anomalies sont cumulatives : le niveau 2 inclut les anomalies du niveau 1, etc.


Niveaux

Niveau Label Anomalies actives Profil étudiant
0 Désactivé 0 Référence — tout nominal
1 Junior 3 (A1–A3) Tests fonctionnels basiques
2 Confirmé 7 (A1–A7) Tests de régression
3 Expert 11 (A1–A11) Analyse avancée / TMAP
4 Master 16 (A1–A16) Validation métier par assertions

Anomalies niveau 1 — Junior

A1 · TVA 19,6% au lieu de 20%

Implémentation : BusinessChaosService.applyTva() → appelée dans OrderService.createOrderFromItems()

// Niveau 0 : taux correct
return new BigDecimal("0.20");

// Niveau 1+ : ancien taux (supprimé en France en 2014)
return new BigDecimal("0.196");

Le taux est appliqué au total HT pour calculer le totalAmount stocké en base — le montant affiché dans "Mes commandes" est donc réellement différent du montant correct.

Détection dans l'UI et les logs

A1 est détectable directement dans l'interface :

  • Commander un article à 100,00 € HT → total affiché 119,60 € au lieu de 120,00 €
  • Écart de 0,33% — subtil mais mesurable par un test de régression sur le calcul TTC

Et dans les logs applicatifs du container perfshop-app :

WARN [BusinessChaos][A1] TVA incorrecte appliquee: 19.6% au lieu de 20% — user=...
Ainsi que dans l'onglet Métier du monitoring.

Approche de test recommandée : passer une commande d'un montant HT connu, comparer le TTC affiché avec montant_HT × 1,20 attendu — l'écart révèle le taux incorrect.


A2 · Arrondi prix à l'entier inférieur

Implémentation : BusinessChaosService.applyPriceRounding()

Niveau 1+ : tout prix > 10 EUR est arrondi à l'entier inférieur (floor).

Impact : 99,99 € facturé 99,00 € → manque à gagner de 0,99 € par article.

Détection : comparer le prix unitaire affiché dans le panier avec le prix catalogue produit.


A3 · Stock non décrémenté

Implémentation : BusinessChaosService.shouldDecrementStock()OrderService

Niveau 0 : après chaque commande, product.setStock(stock - quantité) est appelé et persisté en base.

Niveau 1+ : shouldDecrementStock() retourne false → la mise à jour du stock est sautée. Le produit reste affiché "disponible" indéfiniment, même épuisé.

Impact : survente silencieuse — un produit commandé 10 fois reste toujours disponible.

Détection : noter le stock affiché sur la fiche produit, passer une commande, revérifier — le stock est inchangé en niveau 1+.


Anomalies niveau 2 — Confirmé

A4 · Frais de port absents de l'email de confirmation

Email envoyé sans la ligne "Frais de livraison" alors que le montant total les inclut.

A5 · Double commande sur double-clic

Absence d'idempotence sur POST /api/orders : deux clics rapides créent deux commandes identiques.

Détection : la liste des commandes affiche deux entrées avec le même contenu et des numéros consécutifs.

A6 · Code promo invalide accepté

Un code promo inexistant est accepté sans erreur, avec 0% de réduction appliquée.

Détection : soumettre un code aléatoire — la réponse est 200 OK au lieu de 400 Bad Request.

A7 · Délai de livraison en jours calendaires

Le délai affiché ("3 jours ouvrés") est calculé sur 7 jours/7 au lieu de jours ouvrés.


Anomalies niveau 3 — Expert

A8 · Race condition sur le stock

Lecture et écriture du stock sans verrou → survente possible en charge concurrente.

A9 · Injection de logs (log poisoning)

Les champs texte libres (prénom, nom, ville) acceptent des caractères LF/CRLF, permettant d'injecter de fausses entrées dans les logs applicatifs.

A10 · Total historique des commandes incorrect

Le total cumulé affiché dans "Mes commandes" est différent de la somme réelle en base.

A11 · Token session non invalidé après logout

Après un POST /api/auth/logout, le comportement diffère selon le niveau :

Niveau 0-2 (normal) : session.invalidate() est appelé → tous les attributs de session sont détruits (user, securityToken, bundle scripting, données checkout).

Niveau 3 (anomalie A11) : seul session.removeAttribute("LOGGED_IN_USER") est appelé. La session HTTP elle-même reste active avec : - le securityToken encore valide → POST /api/orders accessible - le bundle scripting non invalidé → tokens Chaos Scripting encore utilisables - les données checkout encore présentes en session

En pratique, tout le parcours checkout reste exploitable pendant 30 secondes après le logout — pas seulement un token.

Le champ graceActive est exposé dans /api/auth/status pour indiquer si A11 est configurée :

GET /api/auth/status
{
  "authenticated": false,
  "hasToken": false,
  "userId": null,
  "graceActive": true
}

graceActive: true signifie que le chaos est en niveau 3 — la surface d'attaque est donc plus large que le simple securityToken.


Anomalies niveau 4 — Master

Détection par assertion uniquement

Toutes les anomalies Master sont silencieuses — aucune erreur HTTP, aucune exception visible. La détection nécessite des assertions explicites sur les données métier. C'est l'enjeu du niveau Master : passer de la détection d'erreurs techniques à la validation fonctionnelle.

A12 · Remise fidélité silencieuse

Implémentation : BusinessChaosService.applyLoyaltyDiscount()OrderService.createOrderFromItems()

Le programme fidélité prévoit une remise de -5% à partir de 6 commandes. En niveau 4, la condition de déclenchement contient un bug silencieux (orderCount != -999, condition toujours vraie) qui empêche systématiquement l'application de la remise.

Impact : l'interface MyOrders.jsx affiche "Programme Fidélité — ✓ Éligible" mais le total payé ne bénéficie d'aucune réduction.

Détection : créer un compte avec 6+ commandes, calculer le total attendu avec remise -5%, comparer avec le total réellement débité.


A13 · Devise affichage USD

Implémentation : BusinessChaosService.getCurrency()ProductController.getAllProducts()

En niveau 4, GET /api/products retourne un champ currency: "USD" dans la réponse. Le bandeau ⚠️ Les prix sont affichés en USD apparaît dans l'interface.

// Réponse niveau 0–3 (nominal)
[{ "id": 1, "name": "...", "price": 29.99 }]

// Réponse niveau 4 (A13 actif)
{ "currency": "USD", "products": [{ "id": 1, "name": "...", "price": 29.99 }] }

Détection : parser la réponse JSON de /api/products, valider que currency === "EUR".


A14 · Frais de port doublés

Implémentation : BusinessChaosService.applyShippingCost()OrderService.createOrderFromItems()

En niveau 4, les frais de port sont multipliés par 2 dans le calcul du total commande.

Interaction A14 × A1

En niveau 4, A1 (TVA 19,6%) est aussi active. La formule effective cumulative est :

total = (shippingCost × 2 + Σarticles_HT) × 1.196
Un test correct doit tenir compte des deux anomalies simultanément.

Détection : calculer (prix_HT + frais_port_nominal) × 1.20, comparer avec le total affiché.


A15 · Corruption historique ×1.1

Implémentation : BusinessChaosService.applyHistoryCorruption()OrderController.getUserOrders()

En niveau 4, chaque total retourné par GET /api/orders est multiplié par 1.1. Le total stocké en base reste correct — seule la lecture de l'historique est altérée.

Impact : une commande de 100 € apparaît à 110 € dans "Mes commandes".

Détection : croiser le total enregistré au moment de la création vs le total affiché dans l'historique.


A16 · Annulation sans remboursement stock

Implémentation : BusinessChaosService.shouldRestockOnCancel()OrderController.cancelOrder()

En niveau 4, l'annulation d'une commande ne recrédite pas le stock des produits concernés. La commande est bien passée en statut CANCELLED en base, mais product.stock n'est pas incrémenté.

Détection : noter le stock avant commande, commander, annuler, vérifier que le stock est revenu à sa valeur initiale.


Observabilité

Chaque anomalie déclenchée produit :

  • un log WARN dans les logs du container perfshop-app (préfixe [BusinessChaos][AN])
  • une entrée dans l'activity log visible dans l'onglet Métier du monitoring

Endpoint logs :

GET /api/chaos/public/business/logs

Endpoint statut + compteurs :

GET /api/chaos/public/business/status


Contrôle admin

POST /api/admin/chaos/business
{ "level": 1 }          # 0 = off, 1 = Junior, 2 = Confirmé, 3 = Expert, 4 = Master

Accessible depuis l'onglet 💼 Chaos Métier du chaos-admin, via cookie de session ou header X-Admin-Token.