xpeditis2.0/docs/security/check-secu/REMEDIATION-2026-09-14.md

39 lines
4.7 KiB
Markdown

# Poursuite des corrections — 14 septembre 2026
Branche : `check_secu`, base de cette passe : `c09b8be`.
Cette passe traite deux problèmes ciblés. Elle ne constitue pas une nouvelle couverture exhaustive du dépôt et ne remplace pas les limites du rapport initial.
## 1. Rattachement des sessions Stripe à leur organisation
**Problème confirmé, correction vérifiée localement.** Un ADMIN/MANAGER pouvait présenter à `sync-from-stripe` une session Checkout appartenant à une autre organisation. Le service consommait ses identifiants sans comparer les métadonnées créées côté serveur avec l'organisation authentifiée. La contrainte d'unicité empêchait un double rattachement déjà enregistré, mais pas un abonnement avant traitement du webhook, après échec de celui-ci ou un ancien identifiant libéré. L'exploitation nécessite de connaître une session étrangère : aucune fuite de cet identifiant n'a été établie dans cette passe.
Le service refuse désormais les métadonnées absentes ou étrangères avant de récupérer ou enregistrer l'abonnement Stripe. Les changements d'offre d'une même organisation et la synchronisation sans session restent possibles.
Preuve : avant correction, deux tests de refus échouaient parce que la synchronisation réussissait et enregistrait l'offre GOLD. Après correction, les six tests ciblés passent. Une investigation indépendante puis une revue indépendante en lecture seule n'ont relevé aucun problème concret résiduel sur cette frontière.
## 2. Droits payants conservés après suspension
**Problème confirmé, correction vérifiée localement.** Plusieurs consommateurs utilisaient l'offre facturée sans tenir compte de son état : garde de fonctionnalités, clés API, quotas, frais, aperçu d'abonnement et déclarations de droits. Le garde acceptait également des fonctionnalités présentes dans un ancien jeton avant de consulter la base.
`Subscription.accessPlan` centralise les droits courants : ACTIVE, TRIALING et PAST_DUE conservent l'offre payante conformément à la période de grâce existante ; UNPAID, PAUSED, INCOMPLETE, INCOMPLETE_EXPIRED et CANCELED retrouvent les droits Bronze. L'offre persistée et les données Stripe restent disponibles pour la facturation et la reprise. Les exceptions ADMIN existantes sont conservées, sans en ajouter aux clés API.
Le garde consulte toujours les droits actuels. Les clés API existantes deviennent inutilisables dès que les droits API disparaissent et leur création est refusée. Les quotas de réservation, les frais, les claims de connexion, l'aperçu et la résolution MCP utilisent également les droits courants. Le catalogue MCP actuel ne déclare pas de fonctionnalité payante obligatoire : son correctif évite notamment d'annoncer une ancienne offre via `whoami` et prépare correctement les contrôles du registre.
Preuve : avant correction, 12 cas de refus échouaient dans la matrice domaine/garde, contre 7 contrôles légitimes réussis. Après correction, cette matrice passe, ainsi que les tests de révocation/création des clés API, les contrôles MCP et le quota Bronze après suspension. Une investigation indépendante et une revue indépendante n'ont relevé aucun contournement concret dans cette correction.
## Validation
- Suite backend complète : **491 tests réussis, 5 ignorés**, 36 suites réussies, 1 ignorée.
- Compilation backend réussie.
- ESLint sur les fichiers modifiés réussi ; `git diff --check` réussi.
- Les tests utilisent des doubles de services et des serveurs locaux pour les vérifications HTTP/TLS existantes ; aucun appel réel Stripe, SMTP ou à la base de production.
- Aucun déploiement ni migration nécessaire pour ces changements. La vérification en environnement de préproduction avec Stripe reste à effectuer.
## Limites et suites identifiées
- L'audit exhaustif et la couverture des zones restantes ne sont pas terminés ; voir les rapports précédents.
- L'audit des dépendances reste en attente d'une autorisation explicite d'envoyer les noms et versions au registre npm, après le refus de la revue automatique précédente. Aucun nouvel envoi tenté.
- Les actions de production déjà documentées (rotation des secrets, révocation des liens exposés, configuration CA PostgreSQL) restent distinctes de ces corrections locales.
- Observation à analyser séparément : `CsvBookingService.resolveBookingFeeEur` retourne encore zéro en cas d'erreur de récupération de l'abonnement. Les préconditions et l'impact financier de ce comportement ne sont pas validés dans cette passe.
- Le dépassement de quota lève actuellement une exception métier qui n'hérite pas de `DomainException` ; sa présentation HTTP mérite une correction fonctionnelle distincte. Le refus avant création est vérifié.