PD-276 — Scénarios de tests contractuels
1. Références
- Spécification : PD-276-specification.md
- Epic : PD-189 (Epic crypto-proof)
2. Matrice de couverture
| ID Invariant | ID Critère | ID Test | Couverture | Commentaire |
| INV-276-01-zeroknowledge | CA-276-04 | TC-NOM-01 | Oui | Validation seule, sans dérivation serveur |
| INV-276-01-zeroknowledge | CA-276-06 | TC-INV-01 | Oui | Vérification contractuelle anti-dérivation |
| INV-276-02-argon2-minima | CA-276-04 | TC-NOM-01 | Oui | Minima exacts acceptés |
| INV-276-02-argon2-minima | CA-276-04 | TC-ERR-01 | Oui | Valeur sous minima rejetée |
| INV-276-02-argon2-minima | CA-276-04 | TC-ERR-02 | Oui | Itérations sous minima rejetées |
| INV-276-02-argon2-minima | CA-276-04 | TC-ERR-03 | Oui | Paramètre manquant rejeté |
| INV-276-02-argon2-minima | CA-276-04 | TC-ERR-04 | Oui | type != 2 rejeté |
| INV-276-03-argon2-bounds | CA-276-04 | TC-NOM-01 | Oui | Bornes basses exactes acceptées |
| INV-276-03-argon2-bounds | CA-276-05 | TC-NOM-02 | Oui | Bornes hautes exactes acceptées |
| INV-276-03-argon2-bounds | CA-276-05 | TC-ERR-05 | Oui | Valeur > max rejetée |
| INV-276-04-config-centralisee | CA-276-06 | TC-NOM-03 | Oui | Endpoint expose config unique et exacte |
| INV-276-05-metadata-binding | CA-276-08 | TC-NOM-04 | Oui | Tag créé avec longueur 32 bytes |
| INV-276-05-metadata-binding | CA-276-07 | TC-NOM-08 | Oui | Colonne/fait metadata_tag vérifiés |
| INV-276-05-metadata-binding | CA-276-09 | TC-NOM-06 | Oui | Phase 1 nullable |
| INV-276-05-metadata-binding | CA-276-09 | TC-NOM-07 | Oui | Phase 2 NOT NULL |
| INV-276-05-metadata-binding | CA-276-13 | TC-NOM-12 | Oui | LEGACY en phase 1 : lecture seule + warning |
| INV-276-06-separation-cles | CA-276-08 | TC-INV-02 | Oui | HKDF + contexte strict vérifié |
| INV-276-07-verify-before-access | CA-276-08 | TC-NOM-05 | Oui | Vérification préalable avec tag valide |
| INV-276-07-verify-before-access | CA-276-08 | TC-ERR-07 | Oui | Tag invalide => refus immédiat (HTTP 422, <100ms) |
| INV-276-07-verify-before-access | CA-276-08 | TC-NEG-01 | Oui | Substitution inter-device bloquée |
| INV-276-08-envelope-encryption | CA-276-12 | TC-INV-03 | Oui (probatoire) | Contrôles probatoires sur échantillons et scans |
| INV-276-09-prolog-facts | CA-276-02 | TC-NOM-08 | Oui | service(argon2, 'Argon2Service') présent |
| INV-276-09-prolog-facts | CA-276-03 | TC-NOM-08 | Oui | service_method(argon2, validateParams) présent |
| INV-276-09-prolog-facts | CA-276-07 | TC-NOM-08 | Oui | entity_column(...metadata_tag, bytea) présent |
| INV-276-09-prolog-facts | CA-276-01 | TC-NOM-09 | Oui | Audit final 24/24 |
| INV-276-09-prolog-facts | CA-276-01 | TC-INV-04 | Oui | Faits émis/consommés alignés avec check_10/check_19/check_22 |
| INV-276-10-non-regression | CA-276-11 | TC-NR-01 | Oui | 21 checks précédents inchangés (même statut OK/KO) |
| INV-276-10-non-regression | CA-276-01 | TC-NOM-09 | Oui | Score final sans baisse |
| INV-276-11-state-machine | CA-276-09 | TC-NOM-10 | Oui | Transition LEGACY -> BOUND autorisée |
| INV-276-11-state-machine | CA-276-09 | TC-NOM-13 | Oui | Transition LEGACY -> TAMPERED autorisée si incohérence détectée |
| INV-276-11-state-machine | CA-276-09 | TC-ERR-10 | Oui | Transition BOUND -> LEGACY interdite |
| INV-276-11-state-machine | CA-276-08 | TC-ERR-11 | Oui | État TAMPERED terminal |
| INV-276-11-state-machine | CA-276-09 | TC-NEG-02 | Oui | Downgrade sécurité interdit |
| INV-276-05-metadata-binding | CA-276-10 | TC-NOM-11 | Oui | down() restaure état contractuel |
3. Scénarios de test – Flux nominaux
TEST-ID: TC-NOM-01
Référence spec: INV-276-01, INV-276-02, INV-276-03, CA-276-04
GIVEN
- Requête de validation KDF avec {memory=65536, iterations=3, parallelism=4, type=2, hashLength=32}
- Contexte serveur en mode validation contractuelle
WHEN
- La validation Argon2id est exécutée
THEN
- La validation est acceptée
- Aucun rejet de conformité n'est retourné
AND
- Le journal d'audit trace une opération de validation (pas de dérivation de clé métier)
TEST-ID: TC-NOM-02
Référence spec: INV-276-03, CA-276-05
GIVEN
- Requête de validation KDF avec bornes hautes exactes {memory=1048576, iterations=10, parallelism=16, type=2, hashLength=32}
WHEN
- La validation Argon2id est exécutée
THEN
- La validation est acceptée
AND
- La réponse confirme la conformité aux bornes contractuelles
TEST-ID: TC-NOM-03
Référence spec: INV-276-04, CA-276-06
GIVEN
- Appel autorisé au point d'accès de configuration Argon2id
WHEN
- La configuration centralisée est récupérée
THEN
- La réponse contient exactement: memory(default=65536,min=65536,max=1048576), iterations(default=3,min=3,max=10), parallelism(default=4,min=4,max=16), type(default=2,min=2,max=2), hashLength(default=32,min=32,max=32)
AND
- La configuration est unique et cohérente avec le contrat de validation
TEST-ID: TC-NOM-04
Référence spec: INV-276-05, INV-276-06, CA-276-08
GIVEN
- Métadonnées complètes {algorithm, version, envelope_type, device_id}
- Enveloppe en création/rotation
WHEN
- Le metadata binding est calculé et persisté
THEN
- metadata_tag est présent
- metadata_tag a une longueur de 32 bytes
AND
- L'opération est auditée comme BOUND_TAG_VALID
TEST-ID: TC-NOM-05
Référence spec: INV-276-07, CA-276-08
GIVEN
- Enveloppe persistée avec metadata_tag valide
WHEN
- Un unwrap logique est demandé
THEN
- Le système vérifie metadata_tag avant toute restitution exploitable
- L'accès est autorisé après validation réussie
AND
- Le journal d'audit trace la vérification préalable du tag
TEST-ID: TC-NOM-06
Référence spec: INV-276-05, CA-276-09
GIVEN
- Schéma initial sans colonne metadata_tag
WHEN
- Migration phase 1 exécutée
THEN
- La colonne vault_secure.key_envelopes.metadata_tag existe en BYTEA NULL
AND
- Aucun trigger existant ne change de comportement
TEST-ID: TC-NOM-07
Référence spec: INV-276-05, CA-276-09
GIVEN
- Phase 1 appliquée
- Backfill LEGACY terminé
WHEN
- Migration phase 2 exécutée
THEN
- metadata_tag devient NOT NULL
- Les écritures avec metadata_tag absent sont rejetées
AND
- Les services dépendants restent compatibles après bascule
TEST-ID: TC-NOM-08
Référence spec: INV-276-09, CA-276-02, CA-276-03, CA-276-07
GIVEN
- Génération des faits Prolog de la branche candidate
WHEN
- Les faits générés sont inspectés
THEN
- service(argon2, 'Argon2Service') est présent
- service_method(argon2, validateParams) est présent
- entity_column(key_envelope, metadata_tag, bytea) est présent
AND
- Aucun fait requis n'est manquant
TEST-ID: TC-NOM-09
Référence spec: INV-276-09, INV-276-10, CA-276-01, CA-276-11
GIVEN
- Faits Prolog générés
- Règles de contrôle inchangées
WHEN
- L'audit Prolog est exécuté
THEN
- Le résultat est 24/24 checks OK
- Les 21 checks historiquement conformes restent conformes
AND
- Le rapport d'audit est exporté comme preuve
TEST-ID: TC-NOM-10
Référence spec: INV-276-11, CA-276-09
GIVEN
- Enveloppe en état LEGACY_NULL_TAG
WHEN
- Backfill/rotation conforme est appliqué
THEN
- Transition LEGACY_NULL_TAG -> BOUND_TAG_VALID autorisée
AND
- La transition est tracée dans le journal d'état
TEST-ID: TC-NOM-11
Référence spec: CA-276-10
GIVEN
- Migration phase 1 + phase 2 déjà appliquées
WHEN
- down() est exécuté
THEN
- La contrainte NOT NULL est supprimée
- La colonne metadata_tag est supprimée
AND
- Le schéma revient à l'état contractuel antérieur
TEST-ID: TC-NOM-12
Référence spec: CA-276-13, Q-276-02
GIVEN
- Système en phase 1
- Enveloppe LEGACY avec metadata_tag IS NULL
WHEN
- Requête de lecture de l'enveloppe
THEN
- L'accès lecture seule est autorisé
- Aucun flux d'écriture/modification n'est autorisé sur cette enveloppe sans rotation
AND
- Un warning d'audit indique "LEGACY access in phase1; rotation recommended, not forced"
TEST-ID: TC-NOM-13
Référence spec: INV-276-11, CA-276-09
GIVEN
- Enveloppe en état LEGACY_NULL_TAG
- Incohérence de binding détectée (tag invalide calculé lors d'un contrôle d'intégrité)
WHEN
- Le moteur de vérification évalue l'accès
THEN
- Transition LEGACY_NULL_TAG -> TAMPERED_TAG_INVALID autorisée
- L'accès est refusé avec HTTP 422
AND
- L'état TAMPERED est tracé comme terminal
TEST-ID: TC-INV-01
Référence spec: INV-276-01, CA-276-06
GIVEN
- Exécution d'un flux de validation Argon2id avec mot de passe fourni par le client
WHEN
- Le flux complet de validation est audité
THEN
- Aucune sortie de dérivation de clé serveur n'est produite
- Aucun artefact de clé dérivée n'est persistant en base
AND
- Le service se limite à une décision conformité (accept/reject)
TEST-ID: TC-INV-02
Référence spec: INV-276-06, CA-276-08
GIVEN
- Création d'une enveloppe avec metadata binding
WHEN
- Les traces de calcul de binding sont inspectées
THEN
- Le contexte HKDF utilisé est exactement "ProbatioVault::MetadataBinding::v1"
- La dérivation emploie K_binding et non K_master_user directement
AND
- Toute dérivation sans ce contexte est rejetée comme non conforme
TEST-ID: TC-INV-03
Référence spec: INV-276-08, CA-276-12
GIVEN
- Jeux d'artefacts cryptographiques temporaires (clé, fragment, DEK, ReKey) créés en environnement de test
WHEN
- Les enregistrements persistés sont contrôlés via scans probatoires
THEN
- Aucun secret temporaire n'apparaît en clair dans l'échantillon contrôlé
- Les champs cryptographiques observés sont chiffrés (AES-256-GCM ou enveloppe HSM)
AND
- Toute occurrence en clair détectée entraîne un échec bloquant
TEST-ID: TC-INV-04
Référence spec: H-276-02, INV-276-09
GIVEN
- Sortie du générateur de faits Prolog de la candidate
- Cartographie des dépendances checks -> faits
WHEN
- Vérification de consommation ciblée est exécutée
THEN
- check_10 consomme service(argon2, 'Argon2Service')
- check_19 consomme entity_column(key_envelope, metadata_tag, bytea)
- check_22 consomme service_method(argon2, validateParams)
AND
- Aucun autre fait non prévu n'est requis pour ces 3 checks
4. Scénarios de test – Cas d’erreur
TEST-ID: TC-ERR-01
Référence spec: E-01, INV-276-02, CA-276-04
GIVEN
- Requête KDF avec memory=65535
WHEN
- Validation serveur
THEN
- Rejet explicite de validation
- Aucun changement d'état persistant
TEST-ID: TC-ERR-02
Référence spec: E-01, INV-276-02, CA-276-04
GIVEN
- Requête KDF avec iterations=2
WHEN
- Validation serveur
THEN
- Rejet explicite de validation
- Aucune opération métier poursuivie
TEST-ID: TC-ERR-03
Référence spec: E-03, INV-276-02, CA-276-04
GIVEN
- Requête KDF sans hashLength
WHEN
- Validation serveur
THEN
- Rejet explicite pour paramètre manquant
- Aucune persistance de requête invalide
TEST-ID: TC-ERR-04
Référence spec: E-04, INV-276-02, CA-276-04
GIVEN
- Requête KDF avec type=1
WHEN
- Validation serveur
THEN
- Rejet explicite de conformité
- La requête n'atteint pas les flux de chiffrement métier
TEST-ID: TC-ERR-05
Référence spec: E-02, INV-276-03, CA-276-05
GIVEN
- Requête KDF avec memory=1048577 (au-delà du max)
WHEN
- Validation serveur
THEN
- Rejet explicite hors bornes max
- Aucune mutation d'état métier
TEST-ID: TC-ERR-06
Référence spec: E-05, INV-276-05, CA-276-09
GIVEN
- Système en phase finale (NOT NULL actif)
- Tentative d'écriture d'enveloppe sans metadata_tag
WHEN
- Persistance de l'enveloppe
THEN
- Rejet de non-conformité de données
- Aucun enregistrement invalide n'est créé
TEST-ID: TC-ERR-07
Référence spec: E-06, INV-276-07, CA-276-08
GIVEN
- Enveloppe existante avec metadata_tag altéré
WHEN
- Accès unwrap logique
THEN
- Refus immédiat d'accès (HTTP 422, décision < 100 ms)
- Aucune donnée exploitable n'est restituée
TEST-ID: TC-ERR-08
Référence spec: E-07, INV-276-09, CA-276-01
GIVEN
- Génération des faits avec omission d'un fait requis
WHEN
- Audit Prolog exécuté
THEN
- Audit non conforme (<24/24)
- Livraison refusée
TEST-ID: TC-ERR-09
Référence spec: E-08, INV-276-10, CA-276-11
GIVEN
- Build candidate avec baisse d'un check historiquement conforme
WHEN
- Exécution audit comparatif baseline vs candidate
THEN
- Régression détectée
- Livraison refusée
TEST-ID: TC-ERR-10
Référence spec: INV-276-11, CA-276-09
GIVEN
- Enveloppe en état BOUND_TAG_VALID
WHEN
- Tentative de transition vers LEGACY_NULL_TAG
THEN
- Transition rejetée
- Aucun downgrade sécurité n'est appliqué
TEST-ID: TC-ERR-11
Référence spec: INV-276-11, CA-276-08
GIVEN
- Enveloppe en état TAMPERED_TAG_INVALID
WHEN
- Tentative de transition vers tout autre état
THEN
- Transition interdite (état terminal)
- Remédiation manuelle explicitement requise hors flux nominal
5. Tests d’invariants (non négociables)
| Invariant | Test(s) dédiés | Observable | Commentaire |
| INV-276-01-zeroknowledge | TC-NOM-01, TC-INV-01 | Validation acceptée/rejetée sans artefact de dérivation serveur | Contrôle de séparation validation vs dérivation |
| INV-276-02-argon2-minima | TC-NOM-01, TC-ERR-01, TC-ERR-02, TC-ERR-03, TC-ERR-04 | Minima respectés, sous-minima rejetés | Couverture complète des paramètres minimums |
| INV-276-03-argon2-bounds | TC-NOM-02, TC-ERR-05 | Bornes max appliquées | Vérifie anti-dérive numérique |
| INV-276-04-config-centralisee | TC-NOM-03 | Valeurs d'endpoint exactes au contrat | Cohérence client/serveur |
| INV-276-05-metadata-binding | TC-NOM-04, TC-NOM-06, TC-NOM-07, TC-ERR-06, TC-NOM-12 | metadata_tag présent, 32 bytes, puis obligatoire ; politique LEGACY phase 1 validée | Couvre création, migration et transitoire |
| INV-276-06-separation-cles | TC-INV-02 | Usage HKDF avec contexte strict | Contrôle crypto contractuel |
| INV-276-07-verify-before-access | TC-NOM-05, TC-ERR-07, TC-NEG-01 | Vérification préalable et refus sur invalidité (HTTP 422, <100ms) | Défense anti-substitution |
| INV-276-08-envelope-encryption | TC-INV-03 | Absence de secrets en clair dans contrôles probatoires | Couverture probatoire (statut explicite) |
| INV-276-09-prolog-facts | TC-NOM-08, TC-NOM-09, TC-ERR-08, TC-INV-04 | Faits requis présents, audit 24/24, consommation check_10/check_19/check_22 vérifiée | Passage checks 10/22/19 + robustesse hypothèse H-276-02 |
| INV-276-10-non-regression | TC-NOM-09, TC-ERR-09, TC-NR-01 | 21 checks antérieurs stables avec même statut OK/KO avant/après | Blocage livraison en baisse |
| INV-276-11-state-machine | TC-NOM-10, TC-NOM-13, TC-ERR-10, TC-ERR-11, TC-NEG-02 | Transitions autorisées/interdites observables | État terminal explicitement verrouillé, LEGACY->TAMPERED couvert |
6. Tests de non-régression
| Test ID | Objet | Observable | Commentaire |
| TC-NR-01 | Stabilité des 21 checks historiquement conformes | Comparatif baseline/candidate avec statut exact OK/KO identique pour chaque check | Bloquant si régression |
| TC-NR-02 | Stabilité des triggers existants de key_envelopes | Même comportement avant/après migration, adossé à baseline instrumentée | Toute divergence = anomalie bloquante |
| TC-NR-03 | Compatibilité phase transitoire LEGACY | Lecture seule autorisée, écriture non autorisée, warning loggé en phase 1 | Valide migration progressive déterministe |
| TC-NR-04 | Réversibilité migration répétable | Séquence up/down/up sans dérive de schéma | Garantit rollback opérable |
7. Tests négatifs et adversariaux
| Test ID | Entrée invalide / abus | Résultat attendu | Observable |
| TC-NEG-01 | Substitution inter-device (device_id modifié) | Refus immédiat d'accès (HTTP 422, <100ms) | Erreur sécurité + absence de restitution |
| TC-NEG-02 | Tentative downgrade BOUND vers LEGACY | Rejet de transition interdite | Machine à états inchangée |
| TC-NEG-03 | metadata_tag longueur != 32 bytes | Rejet de persistance/validation | Erreur de conformité de données |
| TC-NEG-04 | Paramètres Argon2 mixtes (min ok + 1 champ hors borne) | Rejet systématique | Validation atomique de tous les champs |
| TC-NEG-05 | Réponse endpoint config altérée par surcouche locale | Non-conformité détectée en test contrat | Écart entre contrat attendu et payload |
| TC-NEG-06 | Exécution audit avec règles Prolog modifiées | Test invalide, campagne rejetée | Contrôle d'intégrité des règles |
8. Observabilité requise pour les tests
- État système : schéma SQL (
information_schema/catalogue), état machine (LEGACY_NULL_TAG, BOUND_TAG_VALID, TAMPERED_TAG_INVALID), statut de migration (phase1, phase2). - Réponse API : code HTTP (
E-06 = 422), code erreur contractuel, payload de validation Argon2, payload endpoint configuration, absence de données exploitables sur refus sécurité. - Journal d’audit : événement horodaté de validation Argon2, vérification metadata_tag avant accès, rejet tampering/substitution, transition d'état, résultat audit Prolog.
- Événement signé / horodaté : entrée d'audit immuable pour opérations sécurité critiques (unwrap refusé, régression détectée, migration structurante).
- Export probatoire : rapport d'audit Prolog complet (24/24), trace baseline vs candidate, preuve de présence des faits requis, rapport de migration up/down.
- Mesure temporelle : horodatage
t_req/t_decision pour prouver la borne de rejet immédiat < 100 ms sur refus de binding.
9. Règles non testables et exigences probatoires
| Règle | Raison | Impact |
| INV-276-08 « Aucun secret temporaire en clair en base » (preuve absolue) | Une preuve exhaustive d'absence totale sur tous chemins d'exécution n'est pas démontrable par une campagne de tests finie; seuls des contrôles probatoires (scans + échantillonnage + audit) sont automatisables. | Majeur (traité via CA-276-12 probatoire) |
| E-06 mapping sécurité | Ambiguïté levée : code contractuel fixé à HTTP 422 ; test pleinement automatisable (incluant borne <100ms). | Clos |
| Politique LEGACY phase 1 | Ambiguïté levée : lecture seule autorisée + warning + rotation recommandée non forcée ; oracle de test unique défini. | Clos |
10. Verdict QA
- ✅ Testable contractuellement, avec une exigence explicitement probatoire (CA-276-12 / INV-276-08) et non interprétée comme preuve exhaustive.
- Couverture contractuelle complète des invariants et critères fournie ; ambiguïtés Q-276-02 et Q-276-03 levées, référence épique alignée sur PD-189.
- Vérification renforcée de robustesse Prolog : alignement strict des 3 faits nouveaux avec
check_10, check_19, check_22, et protocole baseline OK/KO avant/après déploiement pour les 21 checks historiques.