PD-40 — Tests contractuels (Rotation de clés HSM)¶
User Story : PD-40 — Rotation de clés HSM et re-signature probatoire Epic : PD-189 — CRYPTO Date : 2026-01-01 Statut : CONTRACTUEL (référence minimale obligatoire)
1. Objet et portée¶
Ce document définit le socle minimal contractuel de tests obligatoires pour PD-40.
Règles normatives :
- Tous les tests TC-* ci-dessous doivent être implémentés (ou explicitement justifiés si impossibles).
- Chaque test automatisé contractuel doit porter l'identifiant TC-* dans le nom du test ou un commentaire/annotation.
- Les tests additionnels (unitaires, intégration, non-régression) sont autorisés et encouragés tant qu'ils n'étendent ni ne contredisent la spec.
2. Tests des invariants (INV-*)¶
TC-INV-01 : Clés privées ne sortent jamais du HSM¶
Invariant : INV-1 (Spec §7)
Objectif : Vérifier que les clés privées sont non-exportables.
Préconditions : - HSM configuré et accessible - Aucune clé existante
Étapes : 1. Générer une nouvelle clé Ed25519 via HsmKeyManager.generateKeyPair() 2. Récupérer les métadonnées de la clé (keyId, algorithm, status) 3. Tenter d'exporter la clé privée via API HSM
Résultat attendu : - La tentative d'export de clé privée échoue avec erreur KEY_NOT_EXPORTABLE ou équivalent - Les métadonnées (keyId, algorithm, createdAt, status) sont exportables - La clé publique est exportable
Criticité : BLOQUANTE
TC-INV-02 : Signatures produites exclusivement par HSM¶
Invariant : INV-2 (Spec §7)
Objectif : Vérifier que toute signature passe par le HSM.
Préconditions : - Clé ACTIVE existante dans HSM
Étapes : 1. Construire un payload de test canonique (JSON RFC 8785) 2. Appeler HsmKeyManager.sign(keyId, payload) 3. Vérifier que la signature est produite 4. Vérifier via logs/traces que l'appel HSM a été effectué
Résultat attendu : - Signature retournée au format base64 - Log HSM montre l'opération de signature - Aucune signature n'est générée en software (vérification par mock/spy)
Criticité : BLOQUANTE
TC-INV-03 : Unicité stricte de la clé active¶
Invariant : INV-3 (Spec §7)
Objectif : Vérifier qu'à tout instant, il existe exactement UNE clé avec status=ACTIVE.
Préconditions : - Base de données vide
Étapes : 1. Insérer une clé K1 avec status=ACTIVE 2. Tenter d'insérer une deuxième clé K2 avec status=ACTIVE 3. Vérifier la contrainte DB
Résultat attendu : - Insertion de K2 échoue avec erreur de contrainte UNIQUE - SELECT COUNT(*) FROM keys WHERE status='ACTIVE' retourne exactement 1
Criticité : BLOQUANTE
TC-INV-04 : Clé archivée ne peut produire signatures ACTIVE¶
Invariant : INV-4 (Spec §7)
Objectif : Vérifier qu'une clé ARCHIVED/CANDIDATE/DISCARDED ne peut jamais signer.
Préconditions : - Clé K1 avec status=ARCHIVED dans la DB
Étapes : 1. Appeler HsmKeyManager.sign(K1.keyId, payload) 2. Observer l'exception
Résultat attendu : - Exception KEY_NOT_ACTIVE_ERROR ou équivalent - Message : "Key status must be ACTIVE to sign" (ou similaire) - Aucune signature produite
Criticité : BLOQUANTE
TC-INV-05 : Modèle append-only (événements et signatures)¶
Invariant : INV-5 (Spec §7)
Objectif : Vérifier que les signatures ne sont jamais supprimées ni modifiées.
Préconditions : - Événement E1 avec 2 signatures existantes
Étapes : 1. Appeler EventRepository.appendSignature(E1.event_id, newSignature) 2. Recharger l'événement E1 3. Vérifier que les 2 signatures précédentes sont intactes 4. Vérifier que la nouvelle signature est ajoutée en fin de tableau
Résultat attendu : - E1.signatures.length === 3 - Les 2 premières signatures ont les mêmes valeurs (keyId, signature, signed_at inchangés) - La 3ème signature est la nouvelle
Criticité : BLOQUANTE
TC-INV-06 : Signature valide ssi state=ACTIVE¶
Invariant : INV-6 (Spec §7)
Objectif : Vérifier que les signatures CANDIDATE sont ignorées lors de la vérification.
Préconditions : - Événement E1 avec : - 1 signature S1 (state=ACTIVE, keyId=K1) - 1 signature S2 (state=CANDIDATE, keyId=K2)
Étapes : 1. Récupérer les signatures actives de E1 : E1.signatures.filter(s => s.state === 'ACTIVE') 2. Compter les signatures valides
Résultat attendu : - Exactement 1 signature active (S1) - S2 est présente dans le tableau mais ignorée (state=CANDIDATE)
Criticité : BLOQUANTE
TC-INV-07 : Toute signature ACTIVE reste vérifiable¶
Invariant : INV-7 (Spec §7)
Objectif : Vérifier que les signatures ACTIVE peuvent être vérifiées même après rotation (clé archivée).
Préconditions : - Événement E1 signé avec clé K1 (state=ACTIVE) - Rotation effectuée : K1 → ARCHIVED, K2 → ACTIVE - Événement E1 a maintenant 2 signatures : S1 (K1, ACTIVE) et S2 (K2, ACTIVE)
Étapes : 1. Exporter la clé publique de K1 (archivée) 2. Récupérer la signature S1 de E1 3. Vérifier la signature S1 avec la clé publique K1
Résultat attendu : - Clé publique K1 est accessible malgré status=ARCHIVED - Vérification cryptographique de S1 réussit - Signature S1 est toujours marquée state=ACTIVE
Criticité : BLOQUANTE
TC-INV-08 : Atomicité par promotion d'état¶
Invariant : INV-8 (Spec §7)
Objectif : Vérifier que la promotion est tout-ou-rien.
Préconditions : - 100 événements re-signés avec signatures CANDIDATE (rotation R1)
Étapes : 1. Simuler échec DB au milieu de la transaction de promotion (après 50 UPDATE) 2. Vérifier rollback automatique 3. Compter les signatures promues
Résultat attendu : - Transaction échoue avec exception - Rollback automatique : TOUTES les signatures restent CANDIDATE (aucune promue à ACTIVE) - Ancienne clé reste ACTIVE, nouvelle clé reste CANDIDATE
Criticité : BLOQUANTE
TC-INV-09 : Sélection E déterministe, bornée, testable¶
Invariant : INV-9 (Spec §7)
Objectif : Vérifier que l'ensemble E est déterministe et reproductible.
Préconditions : - 150 événements en base avec timestamps variés - rotation_start_time = T0 = 2026-01-15T12:00:00Z
Étapes : 1. Appeler EventSelector.selectEligibleEvents(T0) → E1 2. Appeler à nouveau EventSelector.selectEligibleEvents(T0) → E2 3. Comparer E1 et E2 (mêmes event_id, même ordre)
Résultat attendu : - E1 et E2 sont identiques (mêmes événements, même ordre) - Tous les événements sont dans la fenêtre ]T0 - 24h ; T0[ - Tous ont type ∈ {CREATE, UPDATE_METADATA, ACCESS_LOG, PRE_DELEGATION, REKEY} - Tous ont status=FINALIZED - Ordre : (timestamp ASC, event_id ASC)
Criticité : BLOQUANTE
TC-INV-10 : Rotation authentifiée, autorisée, journalisée, exportable¶
Invariant : INV-10 (Spec §7)
Objectif : Vérifier que toute rotation est tracée dans un journal immuable exportable.
Préconditions : - Rotation R1 effectuée (succès ou échec)
Étapes : 1. Rechercher le log de rotation dans rotation_audit_logs WHERE rotation_id=R1 2. Vérifier la présence de tous les champs obligatoires (§10.1 spec) 3. Tenter de modifier le log (UPDATE) 4. Tenter de supprimer le log (DELETE) 5. Exporter les logs en format NDJSON et JSON_CANONICAL
Résultat attendu : - Log existe avec tous les champs : rotation_id, rotation_start_time, rotation_end_time, trigger, initiator, old_keyId, new_keyId, algorithm, eligible_count, event_ids, final_status - UPDATE échoue avec exception "Audit logs are immutable (PD-40 §10.3)" - DELETE échoue avec exception "Audit logs are immutable (PD-40 §10.3)" - Export NDJSON : une ligne JSON par log - Export JSON_CANONICAL : canonicalisation RFC 8785 (clés triées, déterministe)
Criticité : BLOQUANTE
3. Tests des critères d'acceptation (CA*)¶
TC-CA1 : Unicité de la clé active à tout instant¶
Critère : CA1 (Spec §11)
Objectif : À tout instant, il existe exactement UNE clé pouvant produire des signatures ACTIVE.
Préconditions : - Rotation complète effectuée (K1 → K2)
Étapes : 1. Vérifier SELECT COUNT(*) FROM keys WHERE status='ACTIVE' 2. Vérifier que K2 a status=ACTIVE 3. Vérifier que K1 a status=ARCHIVED
Résultat attendu : - Exactement 1 clé active (K2) - K1 est archivée
Criticité : BLOQUANTE
TC-CA2 : Événement signé avant rotation reste vérifiable¶
Critère : CA2 (Spec §11)
Objectif : Les signatures pré-rotation restent valides.
Préconditions : - Événement E1 signé avec K1 avant rotation - Rotation effectuée : K1 → K2
Étapes : 1. Vérifier que E1 a une signature S1 (keyId=K1, state=ACTIVE) 2. Exporter clé publique K1 3. Vérifier cryptographiquement S1
Résultat attendu : - S1 reste state=ACTIVE après rotation - Vérification cryptographique réussit - K1 est accessible (métadonnées) malgré status=ARCHIVED
Criticité : BLOQUANTE
TC-CA3 : Clé archivée ne peut produire signatures ACTIVE¶
Critère : CA3 (Spec §11)
Objectif : Une clé archivée est inutilisable pour signature.
Préconditions : - K1 archivée après rotation
Étapes : 1. Appeler HsmKeyManager.sign(K1.keyId, payload)
Résultat attendu : - Exception KEY_NOT_ACTIVE_ERROR - Aucune signature produite
Criticité : BLOQUANTE
TC-CA4 : Chaque signature expose keyId et algorithm=Ed25519¶
Critère : CA4 (Spec §11)
Objectif : Métadonnées de signature complètes.
Préconditions : - Événement E1 signé
Étapes : 1. Récupérer E1.signatures[0] 2. Vérifier présence et valeurs des champs
Résultat attendu : - signature.keyId existe et est un UUID valide - signature.algorithm === 'Ed25519' - signature.signature est une chaîne base64 - signature.signed_at est un ISO-8601 - signature.rotation_id est un UUID (si rotation) - signature.state ∈ {CANDIDATE, ACTIVE}
Criticité : BLOQUANTE
TC-CA5 : Après succès, tous événements E ont signature ACTIVE supplémentaire¶
Critère : CA5 (Spec §11)
Objectif : Vérifier couverture complète de E.
Préconditions : - 1000 événements éligibles (E) - Rotation R1 réussie (K1 → K2)
Étapes : 1. Pour chaque événement dans E : - Compter les signatures avec rotation_id=R1 et state=ACTIVE - Vérifier keyId=K2
Résultat attendu : - Chaque événement de E a exactement 1 signature ACTIVE supplémentaire (nouvelle signature) - Toutes ces signatures ont keyId=K2, rotation_id=R1, state=ACTIVE - Les signatures pré-existantes (K1, ACTIVE) sont intactes
Criticité : BLOQUANTE
TC-CA6 : En cas d'échec, aucune signature ACTIVE supplémentaire¶
Critère : CA6 (Spec §11)
Objectif : Vérifier absence de promotion en cas d'échec.
Préconditions : - 100 événements éligibles - Simulation d'échec HSM après 50 signatures
Étapes : 1. Démarrer rotation R1 2. Simuler échec HSM après 50 signatures 3. Vérifier que ResigningService retourne success=false 4. Compter les signatures ACTIVE ajoutées (rotation_id=R1, state=ACTIVE)
Résultat attendu : - 0 signatures ACTIVE ajoutées (aucune promotion) - 50 signatures CANDIDATE existent (ignorées) - Ancienne clé K1 reste ACTIVE - Nouvelle clé K2 a status=DISCARDED ou CANDIDATE - Log d'audit : final_status=ROTATION_FAILED avec failure_reason
Criticité : BLOQUANTE
TC-CA7 : Journal d'audit complet, durable, exportable¶
Critère : CA7 (Spec §11)
Objectif : Conformité audit (§10 spec).
Préconditions : - Rotation R1 effectuée (succès) - Rotation R2 effectuée (échec)
Étapes : 1. Exporter logs entre date_debut et date_fin en NDJSON 2. Exporter logs en JSON_CANONICAL 3. Vérifier immutabilité (test UPDATE/DELETE) 4. Vérifier contenu des logs R1 et R2
Résultat attendu : - Export NDJSON : 2 lignes (R1, R2), chacune un JSON valide - Export JSON_CANONICAL : 2 lignes, canonicalisation RFC 8785 (clés triées) - UPDATE/DELETE échouent avec exception trigger - Logs contiennent tous les champs obligatoires (§10.1 spec) - R1 : final_status=SUCCESS - R2 : final_status=ROTATION_FAILED avec failure_reason renseigné
Criticité : BLOQUANTE
4. Tests des flux nominaux (N*)¶
TC-N1 : Déclenchement de rotation¶
Flux : N1 (Spec §8)
Objectif : Vérifier initialisation de session de rotation.
Préconditions : - Acteur autorisé (role=ADMIN) - Clé K1 active
Étapes : 1. Appeler RotationOrchestrator.initiateRotation(trigger=MANUAL, initiator=USER_123) 2. Vérifier création de RotationSession
Résultat attendu : - RotationSession créée avec : - rotation_id (UUID v4) - rotation_start_time ≈ now() (±5s) - trigger=MANUAL - initiator.userId=USER_123 - status=INITIATED - oldKeyId=K1
Criticité : BLOQUANTE
TC-N2 : Génération de clé¶
Flux : N2 (Spec §8)
Objectif : Vérifier génération HSM et création métadonnées.
Préconditions : - RotationSession R1 initiée
Étapes : 1. Appeler HsmKeyManager.generateKeyPair('Ed25519') 2. Vérifier persistence dans KeyRepository
Résultat attendu : - KeyMetadata créée avec : - keyId (UUID) - algorithm=Ed25519 - createdAt ≈ now() - status=CANDIDATE - rotationId=R1 - Session mise à jour : newKeyId=K2
Criticité : BLOQUANTE
TC-N3 : Construction ensemble E¶
Flux : N3 (Spec §8)
Objectif : Vérifier sélection déterministe.
Préconditions : - 200 événements en base avec types et statuts variés - rotation_start_time=T0
Étapes : 1. Appeler EventSelector.selectEligibleEvents(T0) 2. Vérifier taille et contenu de E
Résultat attendu : - E contient uniquement événements avec : - timestamp ∈ ]T0 - 24h ; T0[ - type ∈ {CREATE, UPDATE_METADATA, ACCESS_LOG, PRE_DELEGATION, REKEY} - status=FINALIZED - Ordre : (timestamp ASC, event_id ASC) - |E| ≤ 100 000
Criticité : BLOQUANTE
TC-N4 : Re-signature phase CANDIDATE¶
Flux : N4 (Spec §8)
Objectif : Vérifier signature en lot avec state=CANDIDATE.
Préconditions : - Ensemble E de 50 événements - Clé K2 (CANDIDATE) - rotation_id=R1
Étapes : 1. Appeler ResigningService.resignEvents(E, K2, R1) 2. Vérifier succès et état signatures
Résultat attendu : - ResigningResult.success=true - ResigningResult.processedCount=50 - Chaque événement de E a une nouvelle signature avec : - keyId=K2 - algorithm=Ed25519 - signature (base64, longueur 86-88 caractères) - signed_at ≈ now() - rotation_id=R1 - state=CANDIDATE - Aucune signature promue à ACTIVE
Criticité : BLOQUANTE
TC-N5 : Promotion atomique¶
Flux : N5 (Spec §8)
Objectif : Vérifier promotion tout-ou-rien.
Préconditions : - 50 signatures CANDIDATE (rotation R1) - eligible_count=50
Étapes : 1. Appeler PromotionService.promoteSignatures(R1) 2. Vérifier état final
Résultat attendu : - Transaction réussit - Toutes les 50 signatures ont state=ACTIVE - Clé K2 a status=ACTIVE - Clé K1 a status=ARCHIVED, archivedAt ≈ now() - Log d'audit créé avec final_status=SUCCESS
Criticité : BLOQUANTE
TC-N6 : Échec et rollback¶
Flux : N6 (Spec §8)
Objectif : Vérifier gestion d'échec sans promotion.
Préconditions : - 100 événements éligibles - Simulation échec HSM après 30 signatures
Étapes : 1. Démarrer rotation R1 2. Simuler échec HSM (timeout/erreur) 3. Vérifier état final
Résultat attendu : - ResigningResult.success=false - 30 signatures CANDIDATE existent (ignorées, jamais promues) - 0 signatures ACTIVE ajoutées - Clé K1 reste ACTIVE - Clé K2 a status=DISCARDED - Log d'audit : final_status=ROTATION_FAILED, failure_reason="HSM timeout" (ou similaire)
Criticité : BLOQUANTE
5. Tests des cas d'erreur (E*)¶
TC-E4 : Échec partiel de re-signature¶
Cas d'erreur : E4 (Spec §9)
Objectif : Vérifier cohérence append-only après échec.
Préconditions : - 1000 événements éligibles - Échec HSM après 500 signatures
Étapes : 1. Démarrer rotation 2. Simuler échec HSM au milieu 3. Vérifier état DB
Résultat attendu : - 500 signatures CANDIDATE existent - Aucune promotion d'état (state reste CANDIDATE) - Aucune signature ACTIVE ajoutée - État cohérent append-only (pas de suppression des 500 signatures CANDIDATE) - Ancienne clé reste ACTIVE
Criticité : BLOQUANTE
TC-ERR-HSM-UNREACHABLE : HSM indisponible¶
Objectif : Vérifier gestion timeout HSM.
Préconditions : - HSM simulé indisponible (timeout 30s)
Étapes : 1. Appeler HsmKeyManager.generateKeyPair()
Résultat attendu : - Exception HSM_UNREACHABLE après timeout - Rotation échoue avant re-signature - Log d'audit : final_status=ROTATION_FAILED, failure_reason="HSM unreachable"
Criticité : MOYENNE
TC-ERR-ELIGIBLE-SET-TOO-LARGE : Dépassement N_max¶
Objectif : Vérifier rejet si |E| > 100 000.
Préconditions : - 150 000 événements éligibles dans fenêtre 24h
Étapes : 1. Appeler EventSelector.selectEligibleEvents(T0)
Résultat attendu : - Exception ELIGIBLE_SET_TOO_LARGE avec message "Eligible set size 150000 exceeds N_max=100000" - Rotation échoue avant re-signature - Recommandation dans logs : fenêtre plus courte ou rotation intermédiaire
Criticité : MOYENNE
TC-ERR-UNAUTHORIZED-TRIGGER : Déclenchement non autorisé¶
Objectif : Vérifier contrôle d'accès.
Préconditions : - Utilisateur USER_456 avec role=USER (non-admin)
Étapes : 1. Appeler RotationOrchestrator.initiateRotation(trigger=MANUAL, initiator=USER_456)
Résultat attendu : - Exception UNAUTHORIZED_TRIGGER - HTTP 403 (si via API REST) - Log sécurité enregistré
Criticité : HAUTE
TC-ERR-ROTATION-IN-PROGRESS : Rotation concurrente¶
Objectif : Vérifier protection contre rotations simultanées.
Préconditions : - Rotation R1 en cours (status=RESIGNING)
Étapes : 1. Tenter de démarrer rotation R2
Résultat attendu : - Exception ROTATION_ALREADY_IN_PROGRESS - HTTP 409 (si via API REST) - R2 n'est pas créée
Criticité : HAUTE
6. Tests de robustesse et performance¶
TC-PERF-LOAD : Performance avec 100 000 événements¶
Objectif : Vérifier performance à la limite.
Préconditions : - Exactement 100 000 événements éligibles
Étapes : 1. Mesurer temps de sélection E 2. Mesurer temps de re-signature 3. Mesurer temps de promotion 4. Mesurer temps total
Résultat attendu : - Sélection E : < 10s - Re-signature : < 2h (dépend débit HSM, 100k * 50ms ≈ 83 min théorique) - Promotion : < 30s - Temps total : < 2h30m - Mémoire : < 2GB (streaming, pas de buffering complet)
Criticité : MOYENNE
Note : Temps acceptables dépendent du HSM. Monitoring requis.
TC-ROBUST-CLEANUP : Nettoyage signatures CANDIDATE orphelines¶
Objectif : Vérifier cleanup automatique.
Préconditions : - Rotation R1 échouée il y a 8 jours (signatures CANDIDATE orphelines)
Étapes : 1. Exécuter cleanupOrphanedCandidates() 2. Vérifier état après cleanup
Résultat attendu : - Rotation R1 marquée final_status=ROTATION_FAILED, failure_reason="Cleanup: orphaned CANDIDATE signatures" - Signatures CANDIDATE restent en base (append-only) - Clé K2 supprimée du HSM (ou marquée DISCARDED)
Criticité : BASSE
TC-ROBUST-VERIFY-POST-ROTATION : Vérification post-rotation¶
Objectif : Checklist automatique après promotion.
Préconditions : - Rotation R1 terminée avec succès
Étapes : 1. Appeler verifyRotationSuccess(R1)
Résultat attendu : - Vérification 1 : count(signatures ACTIVE avec rotation_id=R1) = eligible_count ✓ - Vérification 2 : count(keys WHERE status=ACTIVE) = 1 ✓ - Vérification 3 : oldKey.status=ARCHIVED ✓ - VerificationResult.success=true
Criticité : HAUTE
7. Tests de canonicalisation RFC 8785¶
TC-CANON-RFC8785 : Canonicalisation déterministe¶
Objectif : Vérifier conformité RFC 8785.
Préconditions : - Événement E1 avec payload complexe (clés non triées, espaces, Unicode)
Étapes : 1. Construire EventToSign depuis E1 2. Appeler canonicalize(eventToSign) (lib canonicalize) 3. Vérifier sortie
Résultat attendu : - JSON compact (pas d'espaces ni retours ligne) - Clés triées alphabétiquement - Unicode normalisé - Résultat identique à deux appels successifs (déterministe) - Hash SHA-256 du JSON canonique identique à chaque fois
Criticité : BLOQUANTE
TC-CANON-SIGNATURE-VERIFY : Vérification avec payload canonique¶
Objectif : Vérifier signature basée sur canonicalisation.
Préconditions : - Événement E1 signé avec canonicalisation RFC 8785
Étapes : 1. Reconstruire EventToSign depuis E1 2. Canonicaliser 3. Vérifier signature avec clé publique
Résultat attendu : - Vérification cryptographique réussit - Hash canonique identique entre signature et vérification
Criticité : BLOQUANTE
8. Tests d'intégration end-to-end¶
TC-E2E-FULL-ROTATION-SUCCESS : Rotation complète réussie¶
Objectif : Scénario nominal complet N1→N2→N3→N4→N5.
Préconditions : - Système vierge avec clé K1 ACTIVE - 500 événements éligibles
Étapes : 1. Déclencher rotation (N1) 2. Générer clé K2 (N2) 3. Sélectionner E (N3) 4. Re-signer E (N4) 5. Promouvoir atomiquement (N5) 6. Vérifier état final
Résultat attendu : - K2 ACTIVE, K1 ARCHIVED - 500 signatures ACTIVE ajoutées (keyId=K2) - Toutes signatures pré-existantes intactes - Log d'audit SUCCESS - Vérification post-rotation réussie
Criticité : BLOQUANTE
TC-E2E-FULL-ROTATION-FAILURE : Rotation complète échouée¶
Objectif : Scénario échec complet N1→N2→N3→N4(fail)→N6.
Préconditions : - Système avec clé K1 ACTIVE - 200 événements éligibles - Échec HSM programmé après 100 signatures
Étapes : 1. Déclencher rotation 2. Générer clé K2 3. Sélectionner E 4. Re-signer E (échec au milieu) 5. Vérifier rollback (N6)
Résultat attendu : - K1 reste ACTIVE - K2 DISCARDED - 100 signatures CANDIDATE existent (ignorées) - 0 signatures ACTIVE ajoutées - Log d'audit ROTATION_FAILED avec failure_reason
Criticité : BLOQUANTE
9. Matrice de couverture Test-ID → Implémentation¶
Cette matrice sera complétée lors de l'implémentation. Format attendu :
| Test-ID | Fichier de test | Statut | Remarques |
|---|---|---|---|
| TC-INV-01 | src/modules/crypto/rotation/__tests__/hsm-key-manager.spec.ts | ✅ PASS | |
| TC-INV-02 | src/modules/crypto/rotation/__tests__/hsm-key-manager.spec.ts | ✅ PASS | |
| TC-INV-03 | src/modules/crypto/rotation/__tests__/key-repository.spec.ts | ✅ PASS | Contrainte DB UNIQUE INDEX |
| TC-INV-04 | src/modules/crypto/rotation/__tests__/hsm-key-manager.spec.ts | ✅ PASS | |
| TC-INV-05 | src/modules/crypto/rotation/__tests__/event-repository.spec.ts | ✅ PASS | |
| TC-INV-06 | src/modules/crypto/rotation/__tests__/event-repository.spec.ts | ✅ PASS | |
| TC-INV-07 | src/modules/crypto/rotation/__tests__/hsm-key-manager.spec.ts | ✅ PASS | Export clé publique archivée |
| TC-INV-08 | src/modules/crypto/rotation/__tests__/promotion-service.spec.ts | ✅ PASS | Transaction atomique |
| TC-INV-09 | src/modules/crypto/rotation/__tests__/event-selector.spec.ts | ✅ PASS | |
| TC-INV-10 | src/modules/crypto/rotation/__tests__/rotation-audit-logger.spec.ts | ✅ PASS | Trigger WORM testé |
| TC-CA1 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-CA2 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-CA3 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-CA4 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-CA5 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-CA6 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-CA7 | src/modules/crypto/rotation/__tests__/rotation-acceptance.spec.ts | ✅ PASS | |
| TC-N1 | src/modules/crypto/rotation/__tests__/rotation-orchestrator.spec.ts | ✅ PASS | |
| TC-N2 | src/modules/crypto/rotation/__tests__/rotation-orchestrator.spec.ts | ✅ PASS | |
| TC-N3 | src/modules/crypto/rotation/__tests__/event-selector.spec.ts | ✅ PASS | |
| TC-N4 | src/modules/crypto/rotation/__tests__/resigning-service.spec.ts | ✅ PASS | |
| TC-N5 | src/modules/crypto/rotation/__tests__/promotion-service.spec.ts | ✅ PASS | |
| TC-N6 | src/modules/crypto/rotation/__tests__/rotation-orchestrator.spec.ts | ✅ PASS | |
| TC-E4 | src/modules/crypto/rotation/__tests__/resigning-service.spec.ts | ✅ PASS | |
| TC-ERR-HSM-UNREACHABLE | src/modules/crypto/rotation/__tests__/hsm-key-manager.spec.ts | ✅ PASS | |
| TC-ERR-ELIGIBLE-SET-TOO-LARGE | src/modules/crypto/rotation/__tests__/event-selector.spec.ts | ✅ PASS | |
| TC-ERR-UNAUTHORIZED-TRIGGER | src/modules/crypto/rotation/__tests__/rotation-orchestrator.spec.ts | ✅ PASS | |
| TC-ERR-ROTATION-IN-PROGRESS | src/modules/crypto/rotation/__tests__/rotation-orchestrator.spec.ts | ✅ PASS | |
| TC-PERF-LOAD | src/modules/crypto/rotation/__tests__/performance.spec.ts | ⏸️ SKIP | Test long, exécution manuelle |
| TC-ROBUST-CLEANUP | src/modules/crypto/rotation/__tests__/cleanup.spec.ts | ✅ PASS | |
| TC-ROBUST-VERIFY-POST-ROTATION | src/modules/crypto/rotation/__tests__/verification.spec.ts | ✅ PASS | |
| TC-CANON-RFC8785 | src/modules/crypto/rotation/__tests__/canonicalization.spec.ts | ✅ PASS | |
| TC-CANON-SIGNATURE-VERIFY | src/modules/crypto/rotation/__tests__/canonicalization.spec.ts | ✅ PASS | |
| TC-E2E-FULL-ROTATION-SUCCESS | src/modules/crypto/rotation/__tests__/e2e-rotation.spec.ts | ✅ PASS | |
| TC-E2E-FULL-ROTATION-FAILURE | src/modules/crypto/rotation/__tests__/e2e-rotation.spec.ts | ✅ PASS |
10. Exigences de couverture¶
- Couverture minimale : ≥ 90% (lignes et branches)
- Tests contractuels : 100% des TC-* implémentés (ou justifiés)
- Tests additionnels : Encouragés pour robustesse, sécurité, non-régression
Fin du document PD-40-tests.md