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 :
- 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. - Structure
envelope_sealimbriquée : la colonne DB stockeSealedProofEnvelope {envelopeSeal, verificationMaterial}mais le vérificateur attendEnvelopeSealdirectement. - Bypass trust anchor :
trustedRootsest optionnel dansverify()— 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_ECDSAraw vsCKM_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é)¶
- [BLOQUANT] E-01 : Aligner le pipeline crypto sign/verify. Options :
- (a) Utiliser
SignatureAlgorithm.ECDSA_RAWdans le HSM (pre-hash SHA3-384 + raw sign) etcreateVerifyavec un custom verify (oucrypto.verifysans double hash). - (b) Passer
canonicalJson(pas le hash) aucreateVerify('SHA3-384')et utiliserECDSA_SHA3_384si disponible. - [BLOQUANT] E-02 : Stocker
EnvelopeSealdirectement dans la colonneenvelope_seal(pas le wrapperSealedProofEnvelope). RestructurerverificationMaterialpour éviter la duplication. - [BLOQUANT] S-01 : Rendre
trustedRootsobligatoire dansverify()(ou échouer avecreason: 'no_trusted_roots'si absent). - [MAJEUR] E-03 : Implémenter la logique OCSP réelle dans
generateProof()ou forcerOCSP_UNAVAILABLEquand aucune requête OCSP n'est soumise. - [MAJEUR] S-02 : Implémenter la vérification OCSP live en Mode B ou documenter Mode B comme hors périmètre PD-282.
- [MAJEUR] T-01/T-03 : Ajouter TC-NOM-09 et renforcer TC-NOM-04 une fois S-01/S-02 corrigés.