PD-275 — Scenarios de tests contractuels
1. References
- Specification : PD-275-specification.md
- Epic : EPIC-XX
2. Matrice de couverture
| ID Invariant | ID Critere | ID Test | Couverture | Commentaire |
| INV-275-01-fail-closed | CA-02 | TC-NOM-02 | Oui | Refus explicite de finalisation si preconditions non satisfaites. |
| INV-275-01-fail-closed | CA-05 | TC-NOM-06 | Oui | Refus explicite de soumission signer REVOKED. |
| INV-275-01-fail-closed | CA-05 | TC-NOM-07 | Oui | Refus explicite de soumission signer inconnu. |
| INV-275-01-fail-closed | CA-04 | TC-ERR-06 | Oui | Refus de revocation si audit trail non persistant. |
| INV-275-02-finality-guard | CA-02 | TC-NOM-02 | Oui | Garde bloquante confirmation_count < FINALITY_DEPTH. |
| INV-275-02-finality-guard | CA-02b | TC-NOM-03 | Oui | Chemin nominal autorise a seuil atteint. |
| INV-275-03-confirmation-persistence | CA-01 | TC-NOM-01 | Oui | Persistance et mise a jour du compteur. |
| INV-275-03-confirmation-persistence | CA-01 | TC-ERR-01 | Oui | Rejet des valeurs hors bornes contractuelles. |
| INV-275-04-signer-status-authority | CA-03 | TC-NOM-04 | Oui | Statut derive du registre pour transition de revocation. |
| INV-275-04-signer-status-authority | CA-05 | TC-NOM-06 | Oui | Registre fait foi pour refus signer REVOKED. |
| INV-275-04-signer-status-authority | CA-05 | TC-NOM-07 | Oui | Registre fait foi pour refus signer absent. |
| INV-275-05-revocation-atomic-audited | CA-04 | TC-NOM-04 | Oui | Transition atomique + revokedAt + revokedBy. |
| INV-275-05-revocation-atomic-audited | CA-04 | TC-NOM-05 | Oui | Double revocation refusee sans mutation d'etat. |
| INV-275-05-revocation-atomic-audited | CA-04 | TC-ERR-06 | Oui | Absence de trace audit bloque la transition. |
| INV-275-06-terminal-state-revoked | CA-04 | TC-INV-06 | Oui | Interdiction explicite de toute transition sortante depuis REVOKED. |
| INV-275-07-state-machine-complete | CA-04 | TC-INV-07A | Oui | Couverture des transitions signer autorisees/interdites. |
| INV-275-07-state-machine-complete | CA-02 | TC-INV-07B | Oui | Couverture des transitions batch autorisees/interdites. |
| INV-275-08-envelope-encryption | CA-07 | TC-INV-08 | Oui | Verification d'absence de secrets en clair sur artefacts temporaires eventuels. |
| INV-275-03-confirmation-persistence | CA-08 | TC-NOM-09 | Oui | Reversibilite up/down/up preserve contraintes attendues. |
| INV-275-02-finality-guard | CA-06 | TC-NOM-08 | Oui | Audit Prolog confirme checks 28-32 et score global 32/32. |
| INV-275-01-fail-closed | CA-07 | TC-NR-01 | Oui | Preuve de couverture des 5 nouveaux comportements en test report. |
| INV-275-09-revoke-authorization | CA-04b | TC-ERR-08 | Oui | Refus revokeSigner() sans role ADMIN/SIGNER_ADMIN. |
| INV-275-10-revokedBy-auth-derived | CA-04c | TC-ERR-09 | Oui | revokedBy derive JWT, injection refusee. |
| INV-275-11-signer-concurrency-serialization | CA-05b | TC-NOM-10 | Oui | SELECT FOR UPDATE serialise revoke/submit concurrents. |
| INV-275-12-single-revocation-audit-event | CA-05b | TC-NOM-11 | Oui | Double revoke concurrent : un seul succes. |
3. Scenarios de test - Flux nominaux
TEST-ID: TC-NOM-01
Reference spec: INV-275-03-confirmation-persistence, CA-01, Flux F1
GIVEN
- Une base de test avec un `anchor_batch` existant et `confirmation_count = 0`
- Le batch est dans un etat non finalise
WHEN
- Une mise a jour de confirmations valide est appliquee avec `n = 3`
THEN
- La lecture persistante du batch retourne `confirmation_count = 3`
AND
- Le type persiste est entier
- Aucun changement d'etat du batch n'est observe
TEST-ID: TC-NOM-02
Reference spec: INV-275-01-fail-closed, INV-275-02-finality-guard, CA-02, Flux F2
GIVEN
- `FINALITY_DEPTH = D` (D >= 1)
- Un batch non finalise avec `confirmation_count = D-1`
WHEN
- `finalizeBatch()` est invoque
THEN
- La requete est refusee avec `ERR-FINALITY-INSUFFICIENT`
AND
- L'etat du batch reste non finalise
- Aucun marqueur de finalisation n'est persiste
TEST-ID: TC-NOM-03
Reference spec: INV-275-02-finality-guard, CA-02b, Flux F2
GIVEN
- `FINALITY_DEPTH = D` (D >= 1)
- Un batch non finalise avec `confirmation_count = D`
WHEN
- `finalizeBatch()` est invoque
THEN
- La requete est acceptee
AND
- Le batch passe a `FINALIZED`
- La transition inverse `FINALIZED -> *` n'est pas creee implicitement
TEST-ID: TC-NOM-04
Reference spec: INV-275-04-signer-status-authority, INV-275-05-revocation-atomic-audited, CA-03, CA-04, Flux F3
GIVEN
- Une entree `signer_registry` existante avec `status = ACTIVE`
- L'appelant est authentifie avec un JWT valide portant le role `ADMIN`
WHEN
- `revokeSigner(address)` est invoque
THEN
- Le statut devient `REVOKED`
AND
- `revokedAt` est non nul et horodate
- `revokedBy` est non nul et attribue
- La transition est atomique (pas d'etat intermediaire observable)
TEST-ID: TC-NOM-05
Reference spec: INV-275-05-revocation-atomic-audited, CA-04, Cas d'erreur ERR-SIGNER-ALREADY-REVOKED
GIVEN
- Une entree `signer_registry` avec `status = REVOKED`
- `revokedAt` et `revokedBy` deja renseignes
WHEN
- `revokeSigner(address)` est invoque une seconde fois
THEN
- La requete est refusee avec `ERR-SIGNER-ALREADY-REVOKED`
AND
- Les champs `status`, `revokedAt`, `revokedBy` restent inchanges
TEST-ID: TC-NOM-06
Reference spec: INV-275-01-fail-closed, INV-275-04-signer-status-authority, CA-05, Flux F4
GIVEN
- Une entree `signer_registry` existante avec `status = REVOKED`
- Une requete `submitBatch()` pour ce signer
WHEN
- La soumission est evaluee
THEN
- La requete est refusee avec `ERR-SIGNER-REVOKED`
AND
- Aucun batch n'est cree
- Aucun effet de bord de soumission n'est emis
TEST-ID: TC-NOM-07
Reference spec: INV-275-01-fail-closed, INV-275-04-signer-status-authority, CA-05, Flux F4
GIVEN
- Aucune entree `signer_registry` pour l'adresse fournie
WHEN
- `submitBatch()` est invoque
THEN
- La requete est refusee avec `ERR-SIGNER-NOT-FOUND`
AND
- Aucun batch n'est cree
- Aucun effet de bord de soumission n'est emis
TEST-ID: TC-NOM-08
Reference spec: CA-06, Cas d'erreur ERR-COMPLIANCE-NOT-MET
GIVEN
- Le code et les migrations PD-275 sont deployee(s) en environnement de verification
- Les faits Prolog sont regeneres a partir de l'etat courant
WHEN
- L'audit PV Anchor est execute
THEN
- Le rapport affiche `32/32 OK`, `0 KO`, `0 WARN`
AND
- Les checks 28, 29, 30, 31, 32 sont `OK`
- Le rapport est archive comme preuve verifiable
TEST-ID: TC-NOM-09
Reference spec: CA-08, Flux F1/F3/F4 (schema), section 10.4
GIVEN
- Un environnement de test avec donnees representatives
WHEN
- La migration DDL est executee en sequence `up`, puis `down`, puis `up`
THEN
- Les objets `anchor_batch.confirmation_count` et `signer_registry` sont presents apres re-`up`
AND
- Les contraintes contractuelles (types, defauts, enum statuts, unicite attendue) sont restaurees
- Aucune derive de schema non contractuelle n'est detectee
TEST-ID: TC-NOM-10
Reference spec: INV-275-11-signer-concurrency-serialization, CA-05b
GIVEN
- Une entree `signer_registry` existante avec `status = ACTIVE`
- Deux transactions concurrentes : `revokeSigner(address)` et `submitBatch()` pour le meme signer
WHEN
- Les deux transactions sont executees simultanement
THEN
- La serialisation via `SELECT ... FOR UPDATE` garantit un ordre deterministe
AND
- Si `revokeSigner()` acquiert le verrou en premier : `submitBatch()` recoit `ERR-SIGNER-REVOKED`
- Aucun batch n'est cree pour un signer revoque
- Un seul evenement d'audit de revocation est emis
TEST-ID: TC-NOM-11
Reference spec: INV-275-12-single-revocation-audit-event, CA-05b
GIVEN
- Une entree `signer_registry` existante avec `status = ACTIVE`
- Deux transactions concurrentes : `revokeSigner(address)` emises simultanement
WHEN
- Les deux transactions sont executees
THEN
- Un seul appel reussit (transition `ACTIVE -> REVOKED` + audit trail)
AND
- Le second appel recoit `ERR-SIGNER-ALREADY-REVOKED`
- Un seul evenement d'audit de revocation est persiste
- Les champs `revokedAt` et `revokedBy` refletent uniquement la premiere transaction
4. Scenarios de test - Cas d'erreur
TEST-ID: TC-ERR-01
Reference spec: ERR-CONFIRMATION-COUNT-INVALID, INV-275-03-confirmation-persistence
GIVEN
- Un batch existant
WHEN
- Une mise a jour de `confirmation_count` est demandee avec valeur hors bornes (`< 0` ou `> 2147483647`)
THEN
- La mise a jour est rejetee avec `ERR-CONFIRMATION-COUNT-INVALID`
- La valeur persistante precedente est conservee
TEST-ID: TC-ERR-02
Reference spec: ERR-FINALITY-INSUFFICIENT, INV-275-02-finality-guard
GIVEN
- `FINALITY_DEPTH = D`
- `confirmation_count = D-1`
WHEN
- `finalizeBatch()` est invoque
THEN
- Refus explicite `ERR-FINALITY-INSUFFICIENT`
- Aucun passage a `FINALIZED`
TEST-ID: TC-ERR-03
Reference spec: ERR-SIGNER-NOT-FOUND, INV-275-01-fail-closed
GIVEN
- Adresse signer absente du registre
WHEN
- `revokeSigner(address)` est invoque
THEN
- Refus explicite `ERR-SIGNER-NOT-FOUND`
- Aucun enregistrement de revocation n'est cree
TEST-ID: TC-ERR-04
Reference spec: ERR-SIGNER-NOT-FOUND, INV-275-01-fail-closed
GIVEN
- Adresse signer absente du registre
WHEN
- `submitBatch()` est invoque
THEN
- Refus explicite `ERR-SIGNER-NOT-FOUND`
- Aucun effet secondaire de soumission
TEST-ID: TC-ERR-05
Reference spec: ERR-SIGNER-REVOKED, INV-275-04-signer-status-authority
GIVEN
- Signer present avec `status = REVOKED`
WHEN
- `submitBatch()` est invoque
THEN
- Refus explicite `ERR-SIGNER-REVOKED`
- Aucun effet secondaire de soumission
TEST-ID: TC-ERR-06
Reference spec: ERR-AUDIT-TRAIL-MISSING, INV-275-05-revocation-atomic-audited
GIVEN
- Signer `ACTIVE` existant
- Le contexte force l'echec de persistance de `revokedAt` ou `revokedBy`
WHEN
- `revokeSigner(address)` est invoque
THEN
- L'operation est invalidee avec `ERR-AUDIT-TRAIL-MISSING`
- Le statut reste `ACTIVE`
- Aucun etat partiellement revoque n'est persiste
TEST-ID: TC-ERR-07
Reference spec: ERR-COMPLIANCE-NOT-MET, CA-06
GIVEN
- Un rapport d'audit Prolog dont le score est `< 32/32`
WHEN
- Le gate de conformite est evalue pour la livraison
THEN
- Verdict `ERR-COMPLIANCE-NOT-MET`
- Livraison marquee non conforme
TEST-ID: TC-ERR-08
Reference spec: ERR-REVOKE-UNAUTHORIZED, INV-275-09-revoke-authorization, CA-04b
GIVEN
- Un signer `ACTIVE` existant dans `signer_registry`
- L'appelant est authentifie avec un JWT valide portant un role autre que `ADMIN` ou `SIGNER_ADMIN`
WHEN
- `revokeSigner(address)` est invoque
THEN
- La requete est refusee avec `ERR-REVOKE-UNAUTHORIZED`
- Le statut du signer reste `ACTIVE`
- Aucun evenement d'audit de revocation n'est emis
TEST-ID: TC-ERR-09
Reference spec: ERR-REVOKEDBY-SPOOFING, INV-275-10-revokedBy-auth-derived, CA-04c
GIVEN
- Un signer `ACTIVE` existant dans `signer_registry`
- L'appelant est authentifie avec un JWT valide portant le role `ADMIN`
- Le payload de la requete contient un champ `revokedBy` explicite (tentative d'injection)
WHEN
- `revokeSigner(address)` est invoque
THEN
- La requete est refusee avec `ERR-REVOKEDBY-SPOOFING` ou le champ `revokedBy` est ignore
AND
- Le `revokedBy` persiste est derive du JWT `sub` de l'appelant, jamais du payload
- Si refus : aucune mutation d'etat ni evenement d'audit
5. Tests d'invariants (non negociables)
| Invariant | Test(s) dedies | Observable | Commentaire |
| INV-275-01-fail-closed | TC-NOM-02, TC-NOM-06, TC-NOM-07, TC-ERR-03, TC-ERR-04 | Refus explicite + absence d'effets secondaires | Le deny-by-default est verifie sur les 3 decisions de securite. |
| INV-275-02-finality-guard | TC-NOM-02, TC-NOM-03, TC-ERR-02 | Etat batch avant/apres + code erreur | Couvre refus sous seuil et acceptation au seuil. |
| INV-275-03-confirmation-persistence | TC-NOM-01, TC-ERR-01 | Valeur persistante, type entier, bornes | Couvre defaut, mise a jour, rejection hors bornes. |
| INV-275-04-signer-status-authority | TC-NOM-04, TC-NOM-06, TC-NOM-07, TC-ERR-05 | Source de statut = signer_registry | Valide autorite unique pour decision de soumission/revocation. |
| INV-275-05-revocation-atomic-audited | TC-NOM-04, TC-NOM-05, TC-ERR-06 | status, revokedAt, revokedBy, atomicite | Verifie audit trail obligatoire et idempotence metier stricte. |
| INV-275-06-terminal-state-revoked | TC-INV-06 | Rejet de toute transition sortante depuis REVOKED | Test dedie sur terminalite explicite. |
| INV-275-07-state-machine-complete | TC-INV-07A, TC-INV-07B | Presence de transitions autorisees/interdites pour chaque etat identifie | Verifie exhaustivite du modele declare. |
| INV-275-08-envelope-encryption | TC-INV-08 | Absence de secret crypto en clair dans artefacts temporaires eventuels | Test de non-divulgation sur perimetre PD-275. |
| INV-275-09-revoke-authorization | TC-ERR-08 | Refus avec ERR-REVOKE-UNAUTHORIZED | Moindre privilege sur revocation — seuls ADMIN/SIGNER_ADMIN autorises. |
| INV-275-10-revokedBy-auth-derived | TC-ERR-09 | revokedBy = JWT sub, pas input | Anti-usurpation audit trail. |
| INV-275-11-signer-concurrency-serialization | TC-NOM-10 | Serialisation prouvee par resultat deterministe | Elimine race condition revoke/submit et revoke/revoke. |
| INV-275-12-single-revocation-audit-event | TC-NOM-11 | Un seul audit event pour double tentative concurrente | Unicite transition + audit. |
TEST-ID: TC-INV-06
Reference spec: INV-275-06-terminal-state-revoked
GIVEN
- Un signer en etat `REVOKED`
WHEN
- Toute action de changement de statut est demandee (dont retour `REVOKED -> ACTIVE`)
THEN
- La transition est refusee
AND
- L'etat `REVOKED` reste inchange
TEST-ID: TC-INV-07A
Reference spec: INV-275-07-state-machine-complete (signer)
GIVEN
- Le modele d'etats signer contractuel
WHEN
- Les transitions sortantes de `ACTIVE` et `REVOKED` sont verifiees
THEN
- `ACTIVE -> REVOKED` est autorisee
- `REVOKED -> ACTIVE` et `REVOKED -> *` sont explicitement interdites
TEST-ID: TC-INV-07B
Reference spec: INV-275-07-state-machine-complete (batch)
GIVEN
- Le modele d'etats batch contractuel partiel
WHEN
- Les transitions sortantes de `NON_FINALIZED` et `FINALIZED` sont verifiees
THEN
- `NON_FINALIZED -> FINALIZED` est autorisee uniquement sous garde de finalite
- `FINALIZED -> *` est explicitement interdite
TEST-ID: TC-INV-08
Reference spec: INV-275-08-envelope-encryption
GIVEN
- Les flux PD-275 executes (mise a jour confirmations, revocation, soumission)
WHEN
- Les artefacts temporaires eventuels produits par ces flux sont inspectes dans les stockages persistants accessibles
THEN
- Aucun secret cryptographique en clair n'est present
AND
- Si un artefact cryptographique temporaire existe, il est chiffre au repos (AES-256-GCM ou envelope HSM)
6. Tests de non-regression
| Test ID | Objet | Observable | Commentaire |
| TC-NR-01 | Couverture des 5 comportements nouveaux (checks 28-32) | Rapport de tests mappe vers TC-NOM-01/02/04/05/06/07/08 | Couvre CA-07. |
| TC-NR-02 | Non-regression des checks Prolog deja conformes (1-27) | Rapport Prolog post-changement conserve OK sur checks historiques | Garantit absence d'impact collateral de PD-275. |
| TC-NR-03 | Soumission nominale signer ACTIVE intacte | submitBatch() accepte un signer ACTIVE valide | Verifie que le guard n'introduit pas de faux refus. |
| TC-NR-04 | Finalisation nominale au seuil intacte | finalizeBatch() accepte quand confirmation_count >= FINALITY_DEPTH | Evite regression bloquante du flux metier. |
| TC-NR-05 | Integrite schema apres cycle up/down/up | Colonnes/contraintes attendues presentes apres reapplication | Verifie stabilite migration reversible. |
7. Tests negatifs et adversariaux
| Test ID | Entree invalide / abus | Resultat attendu | Observable |
| TC-NEG-01 | confirmation_count = -1 | Rejet ERR-CONFIRMATION-COUNT-INVALID | Valeur persistante inchangee |
| TC-NEG-02 | confirmation_count = 2147483648 | Rejet ERR-CONFIRMATION-COUNT-INVALID | Valeur persistante inchangee |
| TC-NEG-03 | submitBatch() avec adresse inconnue | Rejet fail-closed ERR-SIGNER-NOT-FOUND | Aucun batch cree |
| TC-NEG-04 | submitBatch() avec signer REVOKED | Rejet ERR-SIGNER-REVOKED | Aucun effet de bord |
| TC-NEG-05 | Double revocation meme adresse | Rejet ERR-SIGNER-ALREADY-REVOKED | Audit trail d'origine inchange |
| TC-NEG-06 | Tentative de reactivation REVOKED -> ACTIVE | Transition refusee | Statut reste REVOKED |
| TC-NEG-07 | Finalisation avec confirmation_count nul et FINALITY_DEPTH >= 1 | Rejet ERR-FINALITY-INSUFFICIENT | Etat batch inchange |
| TC-NEG-08 | Echec de persistence audit pendant revocation | Rejet ERR-AUDIT-TRAIL-MISSING | Aucune mutation partielle |
8. Observabilite requise pour les tests
- Etat systeme : lecture deterministe de
anchor_batch (etat + confirmation_count) et signer_registry (status, revokedAt, revokedBy, contraintes schema). - Reponse API : code d'acceptation/refus et code erreur metier explicite (
ERR-*) pour chaque appel. - Journal d'audit : trace datee et attribuee de chaque revocation reussie, plus trace de refus sur erreurs de securite.
- Evenement signe / horodate : horodatage verifiable de
revokedAt et horodatage du rapport Prolog archive. - Export probatoire : artefacts horodates et consultables (rapport de tests, rapport Prolog, etat schema/migrations) permettant re-execution et verification tierce.
9. Regles non testables
| Regle | Raison | Impact |
Politique normative exacte de revokedBy (Q-04) | Le format impose (user id vs service account vs cle technique) n'est pas contractualise dans la specification. | Majeur |
Valeur par defaut officielle de FINALITY_DEPTH par environnement (Q-01) | Le seuil est testable en parametre, mais la conformite de la valeur par environnement n'est pas verifiable sans decision de reference. | Majeur |
| Normalisation/collision d'adresse signer (Q-03) | Regles de checksum/casse non figees, impossible d'assertion definitive sur unicite metier multi-format. | Majeur |
Exhaustivite des etats anchor_batch hors FINALIZED (Q-02) | Le modele fourni est partiel; la couverture de toutes transitions sortantes globales reste incompletable sans liste canonique. | Bloquant |
10. Verdict QA
- ⚠️ Testable partiellement (avec reserves listees)
- Motif : les flux PD-275 et les invariants centraux sont testables et automatisables, mais les ambiguities Q-01/Q-02/Q-03/Q-04 empechent un verdict "testable integralement".
- Condition de levee des reserves : figer les decisions de specification manquantes puis rejouer les tests TC-INV-07B, TC-NEG-03/04, TC-NOM-02/03 avec referentiels valides.