Aller au contenu

PD-282 — Acceptabilité

1. Références

  • Spécification : PD-282-specification.md
  • Tests contractuels : PD-282-tests.md
  • Plan d'implémentation : PD-282-plan.md
  • Commit évalué : 3d852da feat(PD-282): ProofEnvelope scellement HSM + materiel validation eIDAS
  • Branche : feature/PD-282-proof-envelope-seal-eidas
  • Date de la revue : 2026-03-02

Prérequis acceptabilité

  • Tests CI : 259/259 PASS (247 unitaires legal-pre + 12 intégration PD-282). 4 échecs pré-existants hors périmètre (modules user/documents).
  • Coverage : 92.22% global (seuil 80%). Module legal-pre : 82.25% stmts. Lacunes ciblées : ocsp-client.service.ts (9.83%), offline-verification.service.ts (43.43%).
  • TODO non tracés : 0 dans le code PD-282. 9 TODO pré-existants dans stubs avec story destination (IAM, TSP).
  • Code DEV ONLY : aucun scaffolding non déclaré.

2. Synthèse exécutive

PD-282 implémente le scellement HSM global (envelopeSeal) et le matériel de vérification eIDAS/OCSP pour les ProofEnvelopes. L'implémentation couvre 7 nouveaux services (seal, verification, OCSP, format validation, secret detection) avec 259 tests passants.

Cependant, les reviews croisées ChatGPT ont identifié 3 écarts BLOQUANTS et 5 écarts MAJEURS qui empêchent l'acceptation :

  1. Double-hash crypto : le pipeline sign (pre-hash SHA3-384 + HSM ECDSA_SHA384) et verify (createVerify('SHA3-384') sur le hash) produisent des signatures/vérifications incohérentes.
  2. Structure envelope_seal imbriquée : la colonne DB stocke SealedProofEnvelope {envelopeSeal, verificationMaterial} mais le vérificateur attend EnvelopeSeal directement.
  3. Bypass trust anchor : trustedRoots est optionnel dans verify() — un certificat auto-signé passe la vérification Mode A.

Verdict : NON ACCEPTABLE — corrections BLOQUANTES requises avant Gate 8.

3. Résultats des reviews

3.1 Reviews automatisées

Outil Résultat Détail
ESLint 0 erreur
Prettier 0 fichier non formaté
TypeScript 0 erreur de type
Tests (legal-pre) 259/259 pass (24 suites unitaires + 1 intégration)
Tests (global) ⚠️ 6992/7060 pass, 6 fail pré-existants (modules user/documents)
Coverage (global) 92.22% (seuil 80%)
Coverage (legal-pre) ⚠️ 82.25% stmts (seuil 85% module). ocsp-client.service.ts 9.83%, offline-verification.service.ts 43.43%
Sonar QG ⚠️ ERROR (5 violations MINOR/MAJOR dans module TSA — PD-281, 0 dans legal-pre PD-282)

3.2 Reviews LLM (ChatGPT — validation croisée)

Review Verdict Écarts BLOQUANTS Écarts MAJEURS Réserves
Code (développeur senior) ❌ REJETÉ 2 (E-01, E-02) 2 (E-03, E-05) 4 (INV-282-07/08/09/10 dépendent PD-272 externe)
Tests (QA engineer) ⚠️ RÉSERVES 0 3 (T-01, T-02, T-03) 2 (T-04, T-05)
Sécurité (pentester) ❌ NON CONFORME 1 (S-01) 2 (S-02, S-03) 1 (S-04)

4. Écarts identifiés

Classification des écarts

Niveau Définition
BLOQUANT Violation d'invariant, faille de sécurité, non-conformité majeure
MAJEUR Fonction incomplète ou non conforme sans rupture de sécurité
MINEUR Détail ou dette non critique

Détail des écarts

ID Description Référence Gravité Statut Validation orchestrateur
E-01 Double-hash crypto sign/verify : EnvelopeSealService.seal() fait pre-hash SHA3-384 puis envoie au HSM avec SignatureAlgorithm.ECDSA_SHA384 (qui potentiellement re-hash en SHA-384). OfflineVerificationService.verify() passe le hash SHA3-384 à createVerify('SHA3-384') qui re-hash en SHA3-384. Les chaînes de hachage ne correspondent pas. INV-282-01, INV-282-03, CA-01, CA-02 BLOQUANT OUVERT CONFIRMÉ — Vérification code source envelope-seal.service.ts:72-81 vs offline-verification.service.ts:72,84-88,157-163. Le createVerify('SHA3-384') re-hash le buffer déjà hashé.
E-02 Structure envelope_seal imbriquée : legal-composite-proof.service.ts:143 persiste sealedEnvelope (type SealedProofEnvelope = {envelopeSeal, verificationMaterial}) dans la colonne envelope_seal. Le vérificateur offline-verification.service.ts:47 lit envelope.envelopeSeal et le cast en EnvelopeSeal. Si l'enveloppe est reconstruite depuis la DB, envelopeSeal contient le SealedProofEnvelope imbriqué, pas directement le EnvelopeSeal. INV-282-01, INV-282-04 BLOQUANT OUVERT CONFIRMÉlegal-composite-proof.service.ts:127-130,143 stocke l'objet wrapper SealedProofEnvelope dans la colonne, pas EnvelopeSeal directement.
S-01 Bypass trust anchor (auto-signé accepté) : OfflineVerificationService.verify() accepte trustedRoots optionnel. Sans trusted roots, verifyCertificateChain() vérifie uniquement la cohérence interne de la chaîne. Un attaquant peut générer sa propre paire EC P-384, signer un faux payload, injecter son cert dans certificateChain, et obtenir valid=true en Mode A. INV-282-04, CA-08, H-01 BLOQUANT OUVERT CONFIRMÉoffline-verification.service.ts:168,192-206. Si trustedRoots absent/vide, la validation d'ancrage est sautée. H-01 documente l'hypothèse mais l'implémentation devrait rendre trustedRoots obligatoire ou échouer explicitement.
E-03 Policy OCSP dégradée incohérente : VerificationMaterialAssembler peut produire validationPolicy=GENERATION_TIME_SNAPSHOT avec ocspResponses=[] (quand aucune requête OCSP n'est soumise). Spec ERR-05 autorise ocspResponses=[] uniquement avec OCSP_UNAVAILABLE. INV-282-05, ERR-05 MAJEUR OUVERT CONFIRMÉlegal-composite-proof.service.ts:109 passe [] comme OCSP requests.
S-02 Mode B ne fait pas de vérification OCSP live : verifyOnlineOcsp() vérifie uniquement la période de validité du certificat (dates), sans requêter les responders OCSP/CRL publics. Le plan spécifie pourtant que Mode B DOIT requêter les serveurs OCSP/CRL. INV-282-04, §Mode B MAJEUR OUVERT CONFIRMÉoffline-verification.service.ts:219-252. Seul check : validité temporelle cert.
S-03 Risque SSRF sur OCSP responder URL : OcspClientService effectue fetch() sur des URLs extraites des extensions AIA des certificats sans allowlist/denylist ni contrôle de schéma/réseau. URL vers endpoints internes possible. Defense-in-depth MAJEUR OUVERT Non vérifié en détail (ocsp-client.service.ts faiblement couvert).
E-05 Duplication verificationMaterial : envelopePayload (ligne 121) contient verificationMaterial: enhancedVerificationMaterial, et sealedEnvelope (ligne 129) contient aussi verificationMaterial. La colonne verification_material legacy (ligne 142) stocke encore l'ancien format. Trois versions coexistent. Clarté, maintenabilité MAJEUR OUVERT CONFIRMÉlegal-composite-proof.service.ts:98,106-110,121,129,142.
T-01 TC-NOM-09 (Mode B nominal) absent : aucun test de succès Mode B avec vérification OCSP online. Seuls les cas d'échec sont testés. CA-08, Mode B MAJEUR OUVERT Cohérent avec S-02 (Mode B non implémenté réellement).
T-02 TC-NOM-08 (crash simulation) faible : le test mock save() mais ne simule pas de transaction réelle pre/post-commit avec vérification DB explicite. §5.5, TC-NOM-08 MAJEUR OUVERT Acceptable pour tests unitaires, à renforcer en e2e.
T-03 TC-NOM-04/TC-ERR-08 incomplets : Mode A testé partiellement (absence d'appel réseau mockée), mais preuve de succès avec trust-store insuffisante. CA-08, H-01 MAJEUR OUVERT Lié à S-01.
S-04 Parsing OCSP heuristique : OcspClientService décode l'ASN.1 par inspection d'octets au lieu d'utiliser @peculiar/asn1-ocsp (prévu dans DA-05). Risque de réponse forgée influençant le statut. Defense-in-depth, DA-05 MINEUR OUVERT À corriger lors de l'intégration OCSP réelle.
T-04 Assertions génériques (toBeDefined, toBeTruthy) au lieu d'assertions contractuelles sur contenu/motif. Qualité tests MINEUR OUVERT
T-05 TC-INV-07 : preuve par commentaire, pas d'assertions exécutables I/O. INV-282-07 MINEUR OUVERT Acceptable (INV-282-07 satisfait par conception).

5. Traçabilité

5.1 Spec → Tests

INV/CA TC-ID Statut
INV-282-01, CA-01 TC-NOM-01, TC-ERR-01, TC-ERR-03 ✅ tests existent, ⚠️ résultat compromis par E-01
INV-282-02, CA-02 TC-NOM-01
INV-282-03, CA-03 TC-NOM-02 ✅ tests existent, ⚠️ résultat compromis par E-01
INV-282-04, CA-04/08 TC-NOM-03/04, TC-ERR-04 ⚠️ partiel (Mode A ok, Mode B absent)
INV-282-05, CA-10 TC-NOM-03/04, TC-NEG-05
INV-282-06, CA-06 TC-INV-06, TC-NEG-08
INV-282-07 TC-INV-07 ⚠️ preuve par commentaire
INV-282-08, CA-07 TC-NOM-05, TC-ERR-07
INV-282-09, CA-11 TC-NOM-06, TC-INV-09
INV-282-10, CA-11 TC-INV-10
INV-282-11, CA-09 TC-NOM-07
INV-282-12, CA-12 TC-ERR-06, TC-NEG-01..07

5.2 Tests → Code

TC-ID Fichier test Statut
TC-NOM-01..08 pd282-proof-envelope-seal.spec.ts ✅ 12/12 pass
TC-NOM-09 ❌ absent
TC-ERR-01..08 envelope-seal.service.spec.ts, offline-verification.service.spec.ts
TC-INV-06 secret-detection.service.spec.ts
TC-INV-07 envelope-seal.service.spec.ts ⚠️ déclaratif
TC-INV-09/10 pd282-proof-envelope-seal.spec.ts
TC-NEG-01..10 envelope-format-validator.service.spec.ts, secret-detection.service.spec.ts, offline-verification.service.spec.ts
TC-NR-01 pd282-proof-envelope-seal.spec.ts
TC-NR-02 ❌ absent

6. Hypothèses et TODO recensés

Hypothèses complémentaires

  • H-01 reste pertinente : le trust-store doit être fourni par le vérificateur. L'implémentation doit néanmoins échouer explicitement si absent.
  • La cohérence sign/verify dépend du mécanisme HSM exact (CKM_ECDSA raw vs CKM_ECDSA_SHA384). Un test d'interopérabilité réel est requis (cf. risque plan §8).

TODO non bloquants

  • ocsp-client.service.ts : couverture 9.83% — à renforcer (lié à l'implémentation OCSP réelle).
  • offline-verification.service.ts : couverture 43.43% — lignes Mode B et cert chain non couvertes.
  • Sonar QG ERROR sur module TSA (PD-281, hors périmètre PD-282).

7. Analyse Sonar

  • Quality Gate : ERROR (5 violations new code)
  • Issues BLOCKER : 0
  • Issues CRITICAL : 0
  • Issues MAJOR : 1 (module TSA, optional chain — PD-281)
  • Issues MINOR : 4 (module TSA — PD-281)
  • Aucune violation dans le code PD-282 (legal-pre)
  • URL : https://sonar.dev.probatiovault.com/dashboard?id=probatiovault-backend

8. Verdict d'acceptabilité

  • Verdict actuel : ⛔ REFUSÉ
  • Date : 2026-03-02
  • Motif synthétique : 3 écarts BLOQUANTS identifiés par les reviews croisées ChatGPT (double-hash crypto, structure imbriquée, bypass trust anchor) empêchent la validation probatoire de base. 5 écarts MAJEURS additionnels (policy OCSP, Mode B non implémenté, SSRF, tests incomplets). Corrections requises avant soumission à Gate 8.

Corrections requises (priorité)

  1. [BLOQUANT] E-01 : Aligner le pipeline crypto sign/verify. Options :
  2. (a) Utiliser SignatureAlgorithm.ECDSA_RAW dans le HSM (pre-hash SHA3-384 + raw sign) et createVerify avec un custom verify (ou crypto.verify sans double hash).
  3. (b) Passer canonicalJson (pas le hash) au createVerify('SHA3-384') et utiliser ECDSA_SHA3_384 si disponible.
  4. [BLOQUANT] E-02 : Stocker EnvelopeSeal directement dans la colonne envelope_seal (pas le wrapper SealedProofEnvelope). Restructurer verificationMaterial pour éviter la duplication.
  5. [BLOQUANT] S-01 : Rendre trustedRoots obligatoire dans verify() (ou échouer avec reason: 'no_trusted_roots' si absent).
  6. [MAJEUR] E-03 : Implémenter la logique OCSP réelle dans generateProof() ou forcer OCSP_UNAVAILABLE quand aucune requête OCSP n'est soumise.
  7. [MAJEUR] S-02 : Implémenter la vérification OCSP live en Mode B ou documenter Mode B comme hors périmètre PD-282.
  8. [MAJEUR] T-01/T-03 : Ajouter TC-NOM-09 et renforcer TC-NOM-04 une fois S-01/S-02 corrigés.