PD-254 — Protocole formel de migration probatoire verifiable¶
1. Objectif¶
La User Story PD-254 doit definir un protocole contractuel, auditable et reproductible pour toute migration probatoire de stockage (support, provider, region), afin de garantir simultanement :
- l'integrite cryptographique des objets probatoires (SHA-3, Merkle, ancrage blockchain),
- la lisibilite post-migration,
- la tracabilite complete via manifest pre-migration, rapport de verification et attestation signee HSM,
- la conformite demonstrable a NF Z42-013:2020 §12.1.
Le protocole couvre la verification et la preuve de conformite de migration.
L'execution technique de migration de donnees n'est pas incluse dans cette story.
2. Perimetre / Hors perimetre¶
Inclus¶
- Definition d'un protocole pas-a-pas pour 3 types de migration : support, provider, region.
- Generation d'un
manifest.jsonpre-migration (golden dataset), protege par hash SHA-3 et signature HSM. - Verification pre/post migration :
- inventaire source/cible,
- SHA-3 objet,
- coherence racines Merkle,
- coherence ancrages blockchain,
- lisibilite sur echantillon aleatoire.
- Calcul et comparaison du
Global Root Hashavant/apres. - Generation d'un rapport differentiel JSON exploitable CI.
- Mode
--dry-run(verification sans migration). - Generation d'une attestation
migration_attestation.jsonsignee HSM. - Integration CI/CD avec quality gate bloquant et notification DevOps.
Exclu¶
- Migration effective des donnees (orchestration de copie, bascule reseau, operations runbook de production).
- Changement de format probatoire (couvert par PD-245).
- Migration de schema base de donnees (TypeORM/migrations DDL existantes).
- Reconciliation de litiges juridiques ex-post migration (hors perimetre operationnel de la story).
3. Definitions¶
- Migration probatoire : transfert d'objets et metadonnees de preuve sans alteration de chaine de preuve.
- Manifest pre-migration : jeu de reference immuable des objets a migrer, protege par un hash SHA-3 (
manifest_hash) et une signature HSM (manifest_signature). - Global Root Hash (GRH) :
SHA3-256(concatenation triee des merkle_root). L'ordre de tri est lexicographique sur la chaine hex lowercase desmerkle_root(comparaison caractere par caractere, code ASCII croissant). Exemple :0a1b...<0a2c...<ff00.... - Precheck : controles avant migration (inventaire, hash, Merkle, ancrage, lisibilite).
- Postcheck : memes controles apres migration + comparaison pre/post + revalidation du manifest.
- Attestation de migration : preuve probatoire signee HSM des resultats.
- Dry-run : execution complete des verifications sans action de migration. En mode F3 (postcheck), le dry-run compare le dataset source avec lui-meme (source/source) pour valider la chaine de verification sans migration effective.
- Etat terminal : etat sans transition sortante autorisee.
- KO : echec bloquant interdisant la bascule.
- Lisibilite : un objet est considere « lisible » si les trois criteres suivants sont satisfaits simultanement : (a) le fichier s'ouvre sans erreur I/O, (b) le type MIME detecte correspond au type MIME enregistre dans les metadonnees, © les 1024 premiers octets sont decodables sans erreur selon l'encodage attendu.
- Artefacts logiques : ensemble constitue du verdict (GO/KO), de la liste des ecarts detectes, et du hash des objets verifies. Sont exclus des artefacts logiques : timestamps d'execution, identifiants de job, et metadonnees d'execution.
- Initiateur : identifiant du service account ou de l'utilisateur authentifie qui declenche la campagne de migration. L'initiateur est trace dans le journal d'audit et soumis au rate-limiting.
- Codes d'erreur metier : codes de rejet retournes par le protocole lorsqu'une precondition ou validation echoue. Ces codes (
INVALID_INPUT,INVALID_MANIFEST,CONCURRENT_EXECUTION_DENIED,ATTESTATION_FAILED,PRECHECK_EXPIRED) ne sont pas des etats de la machine d'etats formelle (§5.2) mais des codes de reponse metier qui empechent ou provoquent une transition. Voir §6 pour le detail de chaque code.
4. Invariants (non negociables)¶
| ID | Regle | Justification |
|---|---|---|
| INV-254-01-integrite-objet | Pour chaque doc_id, sha3_before == sha3_after obligatoire. Toute divergence rend la migration KO. | NF Z42-013 §12.1 |
| INV-254-02-merkle | Pour chaque objet, merkle_root_before == merkle_root_after obligatoire. | Integrite chaine de preuve |
| INV-254-03-global-root-hash | hash_global_before == hash_global_after obligatoire. Le GRH est calcule par tri lexicographique des merkle_root hex lowercase puis concatenation et SHA3-256. | Verification macroscopique N objets |
| INV-254-04-blockchain-anchor | Chaque tx_hash d'ancrage reference est present et coherent dans le registre cible. | ISO 14641 / non-alteration preuve |
| INV-254-05-lisibilite | Taux de succes lisibilite echantillon >= seuil contractuel (voir §5.3). La lisibilite est evaluee selon les 3 criteres definis en §3. | NF Z42-013 §12.1 (lisibilite) |
| INV-254-06-worm | Aucune suppression/alteration d'objet verrouille WORM avant retention expiry. | Contrainte WORM PD-44 |
| INV-254-07-rollback | Un plan de rollback declaratif et executable doit exister avant bascule. | Securite operationnelle |
| INV-254-08-attestation | Toute migration validee produit une attestation signee HSM archivee. | Preuve audit |
| INV-254-09-reproductibilite | A parametres identiques et dataset identique, le resultat de verification est deterministe. Les artefacts logiques (verdict, ecarts, hash objets) sont identiques. | Fiabilite CI/CD |
| INV-254-10-transitions | Toute transition d'etat doit etre explicitement autorisee ou interdite (aucune implicite). | Robustesse machine a etats |
| INV-254-12-manifest-integrity | Le manifest est protege par un hash SHA-3 (manifest_hash) et une signature HSM (manifest_signature). Toute alteration du manifest est detectee et rend la campagne KO. | Integrite du jeu de reference |
Note INV-254-11 : L'invariant INV-254-11 (envelope encryption) initialement envisage a ete retire du perimetre de PD-254. Aucun DEK, fragment, cle de session ou material de rekey n'est genere par ce protocole. Le chiffrement au repos des objets probatoires est couvert par les stories existantes (PD-44, PD-4). La numerotation saute de 10 a 12 pour eviter toute confusion avec d'anciennes references.
5. Flux nominaux¶
5.1 Modele de donnees contractuel (formats et validations)¶
| Donnee | Format / Encodage | Taille | Jeu caracteres / Case | Regex | Comportement si invalide |
|---|---|---|---|---|---|
migration_id | UUID v4 texte | 36 caracteres | ASCII, case-insensitive en entree, normalise lowercase | ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$ | Rejet de la campagne (code d'erreur metier INVALID_INPUT, aucune transition d'etat) |
doc_id | UUID v4 texte | 36 | ASCII, case-insensitive en entree, normalise lowercase | idem migration_id | Objet marque INVALID_METADATA, migration KO si >0 |
sha3 | hex SHA3-256 | 64 | [a-f0-9], case-sensitive (lowercase impose) | ^[a-f0-9]{64}$ | Objet KO, migration KO |
merkle_root | hex SHA3-256 | 64 | [a-f0-9], case-sensitive | ^[a-f0-9]{64}$ | Objet KO, migration KO |
tx_hash | hash blockchain hex prefixe | 66 | [a-f0-9x], case-sensitive (lowercase impose) | ^0x[a-f0-9]{64}$ | Objet KO, migration KO |
s3_object_key | UTF-8 path key | 1..1024 | UTF-8, case-sensitive | hors regex globale (validation longueur + UTF-8 valide) | Objet exclu du lot, migration KO |
size | entier non signe bytes | 1..5,497,558,138,880 | numerique | ^[0-9]{1,13}$ | Objet KO, migration KO |
timestamp | RFC3339 UTC | 20..35 | ASCII, case-sensitive (Z) | ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$ | Objet KO, migration KO |
hash_global_before/after | hex SHA3-256 | 64 | [a-f0-9], case-sensitive | ^[a-f0-9]{64}$ | Verification globale KO |
signature_hsm | base64 standard | 88..684 | [A-Za-z0-9+/=], case-sensitive | ^[A-Za-z0-9+/=]+$ | Attestation invalide, code d'erreur metier ATTESTATION_FAILED |
readability_sample_pass_rate | decimal string | 0.0000..1.0000 | numerique + . | ^(0(\.\d{1,4})?|1(\.0{1,4})?)$ | Rapport KO |
manifest_hash | hex SHA3-256 | 64 | [a-f0-9], case-sensitive | ^[a-f0-9]{64}$ | Campagne KO, rejet cutover ou postcheck |
manifest_signature | base64 standard | 88..684 | [A-Za-z0-9+/=], case-sensitive | ^[A-Za-z0-9+/=]+$ | Campagne KO, manifest considere non fiable |
protocol_version | semver | 5..14 | ASCII | ^\d+\.\d+\.\d+$ | Rejet campagne (incompatibilite protocole) |
source_object_count | entier non signe | 1..999999999 | numerique | ^[0-9]{1,9}$ | Revalidation manifest echouee |
Ordre de tri du Global Root Hash : les merkle_root sont tries par ordre lexicographique croissant sur leur representation hex lowercase (64 caracteres). La concatenation des chaines triees est ensuite hashee par SHA3-256 pour produire le GRH.
5.2 Etats et transitions (avec transitions retour explicites)¶
Etats formels :
DRAFT, PRECHECK_RUNNING, PRECHECK_PASSED, PRECHECK_FAILED, CUTOVER_AUTHORIZED, POSTCHECK_RUNNING, VERIFIED, ATTESTED, ROLLED_BACK, RECONCILIATION_FAILED.
Codes d'erreur metier (distincts des etats formels, voir §3) :
INVALID_INPUT, INVALID_MANIFEST, CONCURRENT_EXECUTION_DENIED, ATTESTATION_FAILED, PRECHECK_EXPIRED.
- DRAFT
DRAFT -> PRECHECK_RUNNING: AUTORISEE (preconditions satisfaites)DRAFT -> *autre : INTERDITE (ordre de processus)- PRECHECK_RUNNING
-> PRECHECK_PASSED: AUTORISEE (tous controles OK)-> PRECHECK_FAILED: AUTORISEE (au moins un controle KO)-> DRAFT: INTERDITE (etat execution)- PRECHECK_PASSED
-> CUTOVER_AUTHORIZED: AUTORISEE (si precheck non expire, TTL <= 168h)-> PRECHECK_RUNNING: AUTORISEE (revalidation explicite)-> DRAFT: AUTORISEE (si precheck expire au-dela du TTL, code metierPRECHECK_EXPIREDemis avant retour)- PRECHECK_FAILED
-> PRECHECK_RUNNING: AUTORISEE (correction puis relance)-> CUTOVER_AUTHORIZED: INTERDITE (gate integrite non valide)- CUTOVER_AUTHORIZED
-> POSTCHECK_RUNNING: AUTORISEE (migration executee puis controle)-> PRECHECK_PASSED: AUTORISEE (retour arriere avant execution, conserve le manifest initial, aucun ecrasement)-> ROLLED_BACK: AUTORISEE (annulation operationnelle)- POSTCHECK_RUNNING
-> VERIFIED: AUTORISEE (tous controles OK)-> ROLLED_BACK: AUTORISEE (echec postcheck)-> RECONCILIATION_FAILED: AUTORISEE (timeouts/retries epuises)- VERIFIED
-> ATTESTED: AUTORISEE (attestation generee et signee dans SLA)-> ROLLED_BACK: AUTORISEE (si attestation impossible dans SLA)- ATTESTED (terminal succes)
-> *: INTERDITE (etat terminal, resolution manuelle uniquement)- Transition retour
ATTESTED -> VERIFIED: INTERDITE (attestation immuable) - ROLLED_BACK (terminal echec maitrise)
-> *: INTERDITE (etat terminal, resolution manuelle uniquement)- Retour
VERIFIED -> ROLLED_BACKconserve toutes preuves d'echec, interdit purge - RECONCILIATION_FAILED (terminal echec technique)
-> *: INTERDITE (etat terminal, resolution manuelle uniquement)
Regles generales :
- Quotas/limites de securite sont reappliques immediatement lors de tout retour non terminal.
- Les codes d'erreur metier (
INVALID_INPUT,INVALID_MANIFEST,CONCURRENT_EXECUTION_DENIED) n'entrainent aucune transition d'etat : la campagne reste dans son etat courant et le code est retourne a l'appelant. ATTESTATION_FAILEDest emis quand la signature HSM echoue ; la campagne enVERIFIEDest alors transitionee versROLLED_BACK.PRECHECK_EXPIREDest emis quand le TTL du precheck est depasse ; la campagne enPRECHECK_PASSEDest retournee aDRAFT.
5.3 Bornes numeriques contractuelles¶
| Parametre | Defaut | Min | Max | Unite | Contexte | Percentile | Hors bornes |
|---|---|---|---|---|---|---|---|
precheck_ttl | 72 | 1 | 168 | heures | campagne migration | n/a | Rejet autorisation cutover, code metier PRECHECK_EXPIRED, retour DRAFT |
cutover_window | 2 | 0.25 | 24 | heures | fenetre bascule | n/a | Rejet planification |
rollback_target | 4 | 0.5 | 8 | heures | runbook rollback | P95 | KO readiness gate |
readability_sample_count | 1000 | 100 | 10000 | objets | lot migration | P95 temps traitement | Clamp au max + trace |
readability_pass_threshold | 1.0000 | 0.9900 | 1.0000 | ratio | lot migration | n/a | Migration KO |
verification_timeout | 7200 | 300 | 14400 | secondes | job CI | P95 | Echec job |
lock_ttl | 600 | 60 | 3600 | secondes | lock distribue campagne | n/a | Rejet execution |
idempotency_ttl | 168 | 1 | 720 | heures | dedup jobs | n/a | Rejet demarrage |
reconciliation_interval | 5 | 1 | 60 | minutes | cron reconciliation | n/a | Rejet config |
orphan_threshold | 15 | 5 | 180 | minutes | detection jobs orphelins | n/a | Rejet config |
notify_sla | 5 | 1 | 30 | minutes | alerte DevOps | P95 | Incident observabilite |
clearing_cycles | 3 | 2 | 10 | cycles | clearing conditionnel | n/a | Clearing refuse |
5.4 SLA temporels (transitions a deadline)¶
| Transition / SLA | Defaut | Min | Max | Configurabilite | Comportement expiration |
|---|---|---|---|---|---|
Precheck valide avant cutover (PRECHECK_PASSED valide) | 72h | 1h | 7j | Parametre pipeline | Code metier PRECHECK_EXPIRED, retour DRAFT obligatoire |
Emission attestation apres VERIFIED | 15min | 1min | 4h | Parametre service attestation | Code metier ATTESTATION_FAILED, rollback obligatoire |
| Delai max resolution rollback | 4h | 30min | 8h | Runbook | Incident majeur + etat terminal ROLLED_BACK |
5.5 Flux F1 — Preparation¶
- Initialiser campagne
migration_iden etatDRAFTavecprotocol_version(ex:1.0.0). - Verifier preconditions : acces source/cible, acces registre ancrage, acces HSM, runbook rollback present.
- Verifier que la campagne n'est pas dupliquee (idempotence sur
migration_id).
Resultat attendu : passage a PRECHECK_RUNNING.
5.6 Flux F2 — Precheck et manifest de reference¶
- Generer
manifest.jsonavec chaque objet (doc_id,sha3,merkle_root,s3_object_key,size,timestamp,tx_hash) et le champprotocol_version. - Calculer
manifest_hash= SHA3-256 du contenu serialise du manifest (JSON canonique, cles triees). - Signer le manifest via HSM pour produire
manifest_signature. - Stocker
manifest_hashetmanifest_signaturedans un registre independant du manifest lui-meme. - Enregistrer
source_object_count= nombre total d'objets dans le manifest. - Calculer
hash_global_before(GRH, voir §3 pour l'ordre de tri). - Executer controles precheck (integrite, Merkle, ancrage, lisibilite echantillon selon les 3 criteres de §3).
- Produire rapport precheck JSON.
Resultat attendu :
- si 100% invariants satisfaits ->
PRECHECK_PASSED, - sinon ->
PRECHECK_FAILED.
5.7 Flux F3 — Postcheck apres migration¶
- Charger manifest de reference immuable.
- Revalidation du manifest : recalculer SHA3-256 du manifest charge et comparer avec
manifest_hashstocke. Verifiermanifest_signaturevia HSM. Si divergence -> campagne KO immediate. - Revalidation du nombre d'objets source : verifier que le nombre d'objets actuellement en source correspond a
source_object_countenregistre au precheck. Si divergence (ajout ou suppression d'objets entre precheck et postcheck) -> campagne KO, code metierMANIFEST_STALE. - Relever dataset cible post-migration.
- Calculer
hash_global_after(meme algorithme de tri que §3). - Comparer pre/post :
- objet par objet (
sha3,merkle_root,size, presence), - verification ancrages blockchain,
- lisibilite echantillon post-migration (3 criteres de §3).
- Produire rapport differentiel JSON.
Resultat attendu :
- si invariants OK ->
VERIFIED, - sinon ->
ROLLED_BACK(ouRECONCILIATION_FAILEDsi recuperation impossible).
5.8 Flux F4 — Attestation probatoire¶
- Generer
migration_attestation.jsonavec les champs contractuels, incluantprotocol_version. - Signer attestation via HSM.
- Archiver attestation comme objet probatoire.
- Notifier DevOps/TechLead/PO du verdict.
Resultat attendu : ATTESTED (terminal succes).
5.9 Flux F5 — Dry-run¶
- Executer F1, F2 et simulation F3 sans aucune operation de migration.
- En mode dry-run, le postcheck (F3) compare le dataset source avec lui-meme (source/source) pour valider que la chaine de verification fonctionne correctement, sans verifier une migration effective.
- Interdire toute transition vers execution effective.
- Produire rapport dry-run avec code retour CI explicite.
Resultat attendu : readiness GO ou NO_GO sans modification de donnees.
5.10 Mecanismes de protection distribuee¶
- Lock distribue
- Scope : par
migration_id. - Cle :
migration:lock:{migration_id}. - TTL : voir
lock_ttl. - Si lock non acquis : execution refusee, code d'erreur metier
CONCURRENT_EXECUTION_DENIED(aucune transition d'etat). - Idempotence
- Cle :
migration_id+phase(precheck,postcheck,attestation). - Duree dedup :
idempotency_ttl. - Replay : doit retourner le meme verdict et les memes artefacts logiques (verdict, ecarts, hash objets — hors timestamps et metadonnees d'execution).
- Reconciliation
- Cron :
reconciliation_interval. - Orphelin : campagne non terminale sans activite >
orphan_threshold. - Strategie : reprise de phase idempotente, sinon
RECONCILIATION_FAILED. - Rate-limiting
- Granularite : par
migration_idet par initiateur (voir §3). - Quota : max 3 lancements/heure/initiateur.
- Depassement : rejet explicite.
- Clearing conditionnel
- Retour a statut operationnel normal seulement apres
clearing_cycles(defaut 3) cycles de reconciliation conformes consecutifs. - Compteur persiste par
migration_id. - Un seul cycle non conforme remet le compteur a zero.
5.11 Atomicite multi-composant¶
Aucune ecriture transactionnelle DB suivie d'un append-only journal/queue n'est definie dans le perimetre de PD-254.
Aucune exigence d'atomicite multi-composant additionnelle applicable dans cette story.
5.12 Strategie migration DDL¶
La story exclut explicitement toute migration de schema DB.
Aucune strategie de migration DDL applicable dans PD-254.
5.13 Contraintes inter-modules¶
Le protocole depend de donnees issues des modules archives, preuves Merkle, ancrage blockchain et attestation HSM.
- Donnees inter-modules requises :
- identite objet (
doc_id,s3_object_key,size,timestamp), - empreintes (
sha3,merkle_root), - ancrages (
tx_hash), - signature (
signature_hsm). - Regle : absence d'une donnee obligatoire d'un module tiers => campagne KO.
- Aucun guard de route cross-module n'est dans le perimetre de cette story (composant protocolaire/offline).
5.14 Schemas JSON contractuels¶
Schema du manifest (manifest.json)¶
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "PD-254 Migration Manifest",
"type": "object",
"required": ["migration_id", "protocol_version", "created_at", "source_object_count", "objects", "hash_global_before"],
"properties": {
"migration_id": {
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
},
"protocol_version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"created_at": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,6})?Z$"
},
"source_object_count": {
"type": "integer",
"minimum": 1
},
"hash_global_before": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"objects": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["doc_id", "sha3", "merkle_root", "s3_object_key", "size", "timestamp", "tx_hash"],
"properties": {
"doc_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" },
"sha3": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"merkle_root": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"s3_object_key": { "type": "string", "minLength": 1, "maxLength": 1024 },
"size": { "type": "integer", "minimum": 1, "maximum": 5497558138880 },
"timestamp": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,6})?Z$" },
"tx_hash": { "type": "string", "pattern": "^0x[a-f0-9]{64}$" }
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}
Schema de l'attestation (migration_attestation.json)¶
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "PD-254 Migration Attestation",
"type": "object",
"required": ["migration_id", "protocol_version", "attested_at", "hash_global_before", "hash_global_after", "total_objects", "readability_sample_count", "readability_pass_rate", "anchor_verification_rate", "manifest_hash", "verdict", "signature_hsm"],
"properties": {
"migration_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" },
"protocol_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
"attested_at": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,6})?Z$" },
"hash_global_before": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"hash_global_after": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"total_objects": { "type": "integer", "minimum": 1 },
"readability_sample_count": { "type": "integer", "minimum": 100, "maximum": 10000 },
"readability_pass_rate": { "type": "string", "pattern": "^(0(\\.\\d{1,4})?|1(\\.0{1,4})?)$" },
"anchor_verification_rate": { "type": "string", "pattern": "^1\\.0000$" },
"manifest_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"verdict": { "type": "string", "enum": ["GO", "KO"] },
"signature_hsm": { "type": "string", "pattern": "^[A-Za-z0-9+/=]+$", "minLength": 88, "maxLength": 684 }
},
"additionalProperties": false
}
5bis. Diagrammes¶
5bis.1 Machine d'etats (state diagram)¶
stateDiagram-v2
[*] --> DRAFT
DRAFT --> PRECHECK_RUNNING : Preconditions OK
PRECHECK_RUNNING --> PRECHECK_PASSED : Tous controles OK
PRECHECK_RUNNING --> PRECHECK_FAILED : >= 1 controle KO
PRECHECK_PASSED --> CUTOVER_AUTHORIZED : TTL precheck valide (<= 168h)
PRECHECK_PASSED --> PRECHECK_RUNNING : Revalidation explicite
PRECHECK_PASSED --> DRAFT : TTL expire (PRECHECK_EXPIRED)
PRECHECK_FAILED --> PRECHECK_RUNNING : Correction puis relance
CUTOVER_AUTHORIZED --> POSTCHECK_RUNNING : Migration executee
CUTOVER_AUTHORIZED --> PRECHECK_PASSED : Retour avant execution
CUTOVER_AUTHORIZED --> ROLLED_BACK : Annulation operationnelle
POSTCHECK_RUNNING --> VERIFIED : Tous controles OK
POSTCHECK_RUNNING --> ROLLED_BACK : Echec postcheck
POSTCHECK_RUNNING --> RECONCILIATION_FAILED : Timeouts / retries epuises
VERIFIED --> ATTESTED : Attestation signee HSM dans SLA
VERIFIED --> ROLLED_BACK : Attestation impossible (ATTESTATION_FAILED)
ATTESTED --> [*]
ROLLED_BACK --> [*]
RECONCILIATION_FAILED --> [*]
note right of ATTESTED : Terminal succes\nAucune transition sortante
note right of ROLLED_BACK : Terminal echec maitrise\nPreuves conservees
note right of RECONCILIATION_FAILED : Terminal echec technique\nResolution manuelle Transitions interdites notables (INV-254-10) :
PRECHECK_RUNNING -> DRAFT(etat d'execution, pas de retour)PRECHECK_FAILED -> CUTOVER_AUTHORIZED(gate integrite non valide)ATTESTED -> *(terminal, immuable)ROLLED_BACK -> *(terminal)RECONCILIATION_FAILED -> *(terminal)
Codes d'erreur metier (distincts des etats, aucune transition d'etat) :
INVALID_INPUT: rejet validation format, campagne reste dans son etat courantINVALID_MANIFEST: manifest incomplet, campagne reste dans son etat courantCONCURRENT_EXECUTION_DENIED: lock actif, campagne reste dans son etat courant
5bis.2 Flux nominal multi-service (sequence diagram)¶
sequenceDiagram
participant CI as Pipeline CI/CD
participant PS as ProtocolService
participant S3src as S3 Source
participant S3dst as S3 Cible
participant BC as Blockchain Registry
participant HSM as HSM (PKCS#11)
participant DB as PostgreSQL
rect rgb(230, 245, 255)
note over CI,DB: F1 — Preparation (DRAFT)
CI->>PS: initCampaign(migration_id, protocol_version)
PS->>DB: INSERT campaign (DRAFT)
PS->>S3src: Verify access
PS->>S3dst: Verify access
PS->>BC: Verify access
PS->>HSM: Verify access
PS-->>CI: DRAFT confirmed
end
rect rgb(230, 255, 230)
note over CI,DB: F2 — Precheck & Manifest (DRAFT -> PRECHECK_RUNNING -> PRECHECK_PASSED)
CI->>PS: runPrecheck(migration_id)
PS->>DB: UPDATE state = PRECHECK_RUNNING
PS->>S3src: List objects (inventory)
S3src-->>PS: objects[]
loop Pour chaque objet
PS->>S3src: GET object
S3src-->>PS: object data
note right of PS: Calcul SHA3-256(object)
end
PS->>BC: Verify tx_hash pour chaque objet
BC-->>PS: anchor confirmations
note right of PS: Echantillon lisibilite :<br/>I/O + MIME + decodage 1024 octets
note right of PS: Tri lexicographique merkle_root hex lowercase<br/>Concatenation -> SHA3-256 = GRH (hash_global_before)
PS->>PS: Generer manifest.json (JSON canonique)
note right of PS: manifest_hash = SHA3-256(manifest)
PS->>HSM: Sign(manifest_hash)
HSM-->>PS: manifest_signature
PS->>DB: Store manifest_hash, manifest_signature, source_object_count
PS->>DB: UPDATE state = PRECHECK_PASSED
PS-->>CI: Precheck report JSON
end
rect rgb(255, 245, 230)
note over CI,DB: F3 — Postcheck (CUTOVER_AUTHORIZED -> POSTCHECK_RUNNING -> VERIFIED)
CI->>PS: runPostcheck(migration_id)
PS->>DB: UPDATE state = POSTCHECK_RUNNING
PS->>DB: Load manifest_hash, manifest_signature
PS->>PS: Recalcul SHA3-256(manifest)
note right of PS: Comparaison manifest_hash<br/>(INV-254-12)
PS->>HSM: Verify(manifest_signature)
HSM-->>PS: signature OK
PS->>S3src: Count objects
note right of PS: Comparaison source_object_count<br/>(ERR-12 MANIFEST_STALE)
PS->>S3dst: List objects (inventory cible)
S3dst-->>PS: objects[]
loop Pour chaque objet
PS->>S3dst: GET object
S3dst-->>PS: object data
note right of PS: sha3_after = SHA3-256(object)<br/>Compare sha3_before (INV-254-01)
end
note right of PS: merkle_root_before == merkle_root_after (INV-254-02)
PS->>BC: Verify tx_hash cible
BC-->>PS: anchor OK (INV-254-04)
note right of PS: Lisibilite echantillon post (INV-254-05)
note right of PS: hash_global_after = GRH cible<br/>Compare hash_global_before (INV-254-03)
PS->>DB: UPDATE state = VERIFIED
PS-->>CI: Differential report JSON
end
rect rgb(245, 230, 255)
note over CI,DB: F4 — Attestation (VERIFIED -> ATTESTED)
CI->>PS: generateAttestation(migration_id)
PS->>PS: Build migration_attestation.json
PS->>HSM: Sign(attestation)
HSM-->>PS: signature_hsm
PS->>S3dst: Archive attestation (objet probatoire)
PS->>DB: UPDATE state = ATTESTED
PS-->>CI: ATTESTED — attestation archivee
CI->>CI: Notify DevOps/TechLead/PO
end 6. Cas d'erreur¶
| ID | Cas | Detection | Reponse attendue |
|---|---|---|---|
| ERR-01 | Manifest incomplet | Champ obligatoire absent | Echec immediate, code metier INVALID_MANIFEST, pas de cutover, aucune transition d'etat |
| ERR-02 | Hash objet mismatch | sha3_before != sha3_after | KO migration, rollback obligatoire |
| ERR-03 | Merkle mismatch | merkle_root_before != merkle_root_after | KO migration, rollback obligatoire |
| ERR-04 | Ancrage blockchain incoherent | tx_hash introuvable/invalide | KO migration, rollback obligatoire |
| ERR-05 | Lisibilite sous seuil | pass_rate < readability_pass_threshold | KO migration, rollback obligatoire |
| ERR-06 | Lock non acquis | lock actif existant | Rejet lancement, code metier CONCURRENT_EXECUTION_DENIED, aucune transition d'etat |
| ERR-07 | Time-out verification | depassement verification_timeout | Echec job, entree reconciliation |
| ERR-08 | Signature HSM indisponible/invalide | signature absente ou regex invalide | Code metier ATTESTATION_FAILED, rollback ou incident majeur |
| ERR-09 | WORM violation detectee | tentative suppression objet retenu | Arret immediate, incident securite, evenement WORM_VIOLATION_BLOCKED emis |
| ERR-10 | Donnee inter-module manquante | reference orpheline | KO migration, correction prealable requise |
| ERR-11 | Manifest altere | manifest_hash recalcule != manifest_hash stocke ou manifest_signature invalide | Campagne KO immediate, rollback obligatoire |
| ERR-12 | Manifest perime (TOCTOU) | source_object_count actuel != source_object_count enregistre | Campagne KO, code metier MANIFEST_STALE, retour DRAFT |
7. Criteres d'acceptation (testables)¶
| ID | Critere | Observable |
|---|---|---|
| CA-01 | Le protocole de migration est publie en Markdown avec les 3 types de migration | Fichier present + sections obligatoires |
| CA-02 | Un manifest pre-migration est genere avec schema contractuel complet, incluant protocol_version | manifest.json valide contre schema §5.14 |
| CA-03 | Le precheck compare SHA-3 objet avec reference et bloque a la moindre divergence | Rapport precheck + verdict KO si mismatch |
| CA-04 | Le postcheck valide egalite des merkle_root pre/post | Rapport postcheck sans ecart |
| CA-05 | Le Global Root Hash est calcule par tri lexicographique hex lowercase des merkle_root avant/apres et doit etre identique | hash_global_before == hash_global_after |
| CA-06 | Les ancrages blockchain sont verifies pour 100% des objets du lot | Rapport inclut taux verification = 100% |
| CA-07 | Le controle de lisibilite applique les 3 criteres (I/O, MIME, decodage 1024 octets) sur readability_sample_count objets avec seuil contractuel | Rapport inclut sample_count et pass_rate |
| CA-08 | Le mode --dry-run execute les controles en comparant source/source sans migration effective | Logs/rapport sans operation de migration |
| CA-09 | Une attestation signee HSM est generee apres verification reussie, incluant protocol_version et manifest_hash | migration_attestation.json signe, valide contre schema §5.14 et archive |
| CA-10 | Le pipeline CI bloque la campagne sur tout invariant KO | Job status = failed si invariant viole |
| CA-11 | Le protocole inclut un rollback cible <= rollback_target | Runbook + mesure de delai en exercice |
| CA-12 | Les mecanismes lock/idempotence/reconciliation sont actifs et testables | Tests de concurrence/replay/orphelin passes |
| CA-13 | Toutes transitions d'etat autorisees/interdites sont documentees, codes d'erreur metier distincts des etats | Table transitions complete + table codes metier |
| CA-14 | Les etats terminaux interdisent explicitement toute transition sortante | Presence -> * : INTERDITE pour etats terminaux |
| CA-15 | La conformite NF Z42-013 §12.1 est demontree par artefacts de campagne | Dossier audit (manifest + rapports + attestation) complet |
| CA-16 | Le manifest est protege par hash SHA-3 et signature HSM, verifies au debut du postcheck | manifest_hash et manifest_signature presents et valides |
| CA-17 | Le postcheck revalide que le nombre d'objets source n'a pas change depuis le precheck | Comparaison source_object_count actuel vs enregistre |
| CA-18 | Le clearing conditionnel exige N cycles conformes consecutifs avant retour normal | Compteur persiste et verifie |
8. Scenarios de test (Given / When / Then)¶
- SCN-01 Nominal complet
- Given une campagne
DRAFTavec acces source/cible/registre/HSM valides - When precheck puis postcheck sont executes avec zero ecart
-
Then la campagne atteint
ATTESTEDet l'attestation signee est archivee avecprotocol_versionetmanifest_hash -
SCN-02 Mismatch SHA-3
- Given une campagne en
POSTCHECK_RUNNING - When un objet presente
sha3_after != sha3_before -
Then la campagne est KO et termine en
ROLLED_BACK -
SCN-03 Dry-run
- Given une campagne prete
- When execution en mode
--dry-run -
Then le postcheck compare source/source, aucun transfert/migration n'est effectue et un verdict readiness est produit
-
SCN-04 Concurrence
- Given un lock actif sur
migration_id - When une seconde execution est lancee
-
Then la seconde execution est rejetee avec code metier
CONCURRENT_EXECUTION_DENIED, aucune transition d'etat -
SCN-05 Attestation impossible
- Given campagne
VERIFIED - When HSM indisponible au-dela du SLA d'attestation
-
Then code metier
ATTESTATION_FAILEDpuis rollback obligatoire -
SCN-06 Reconciliation orphelin
- Given campagne non terminale sans activite >
orphan_threshold - When le cron de reconciliation s'execute
-
Then reprise idempotente ou etat terminal
RECONCILIATION_FAILED -
SCN-07 WORM
- Given un objet en retention WORM active
- When une suppression est tentee pendant la campagne
-
Then l'operation est refusee, evenement
WORM_VIOLATION_BLOCKEDemis et la campagne est stoppee -
SCN-08 Transition interdite
- Given campagne
ATTESTED - When une transition sortante est demandee
-
Then la transition est refusee car etat terminal
-
SCN-09 Manifest altere
- Given un manifest dont le contenu a ete modifie apres le precheck
- When le postcheck demarre et recalcule le hash du manifest
-
Then
manifest_hashdiverge, la campagne est KO immediate -
SCN-10 Clearing conditionnel
- Given une campagne en reconciliation
- When 1 cycle conforme suivi d'1 cycle non conforme puis 3 cycles conformes consecutifs
- Then le clearing est refuse apres le 1er cycle, refuse apres le cycle non conforme (compteur remis a zero), autorise apres les 3 cycles conformes
9. Hypotheses explicites¶
| ID | Hypothese | Impact si faux |
|---|---|---|
| H-01 | Les metadonnees de reference (sha3, merkle_root, tx_hash) existent pour 100% des objets cibles de la campagne | Impossible de prouver l'integrite de bout en bout |
| H-02 | L'acces en lecture au registre d'ancrage blockchain est disponible pendant precheck/postcheck | Verification ancrage impossible -> campagne KO |
| H-03 | Une cle HSM dediee a la signature d'attestation et de manifest est provisionnee | Attestation et protection manifest non produisibles -> non-conformite |
| H-04 | Les environnements source/cible exposent des inventaires coherents (pas de filtrage implicite) | Faux ecarts et faux positifs |
| H-05 | Le perimetre objets de migration est freeze pendant la campagne (valide par revalidation source_object_count au postcheck) | Comparaison pre/post non deterministe |
| H-06 | Le protocole est versionne via protocol_version (semver) dans le manifest et l'attestation | Evolution non maitrisee et auditabilite degradee |
10. Points a clarifier (et contraintes techniques)¶
10.1 Points a clarifier¶
| ID | Point | Donnee manquante / Decision requise |
|---|---|---|
| Q-01 | Reference epique exacte | Nom/ID epique non fourni |
| Q-02 | Seuil lisibilite final | Confirmer 1.0000 strict vs seuil inferieur tolere |
| Q-03 | Registre blockchain de reference | Endpoint(s) et politique de disponibilite |
| Q-04 | Politique de sampling | Tirage uniforme global ou stratifie par type MIME/taille |
| Q-05 | Canal de notification DevOps | Email, Slack, PagerDuty (et destinataires) |
| Q-06 | Codification officielle des codes retour CI | Mapping numerique attendu par pipeline |
| Q-07 | Localisation d'archivage attestation | Bucket/prefix probatoire cible contractuel |
| Q-08 | Exigence de double signature attestation | Signature unique HSM ou co-signature operationnelle |
10.2 Contraintes techniques (stack projet cible)¶
Projet cible retenu : ProbatioVault-backend
- Stack principale : NestJS + TypeORM + PostgreSQL
- Ecosysteme associe au besoin PD-254 :
- stockage objet compatible S3 (WORM Object Lock),
- verification outillee par script Python (outil de controle, non substitution stack backend),
- pipeline GitLab CI pour quality gate.
- Contraintes :
- aucune hypothese Swift/SwiftUI, Spring Boot ou autre stack non presente dans le projet cible,
- compatibilite stricte avec les artefacts backend existants de preuve et d'audit.
Aucune transition temporelle ou borne numerique supplementaire hors celles listees en §5.3 et §5.4.
References¶
- Epic : PD-217 — LEGAL & COMPLIANCE
- JIRA :
PD-254 - Repos concernes :
ProbatioVault-backend,ProbatioVault-infra,ProbatioVault-doc - Documents associes :
- NF Z42-013:2020 §12.1
- ISO 14641
- PD-244 (audit GAP-FINAL-018)
- PD-44 (WORM Object Lock)
- Learnings : PD-264, PD-278, PD-282, PD-98