PD-101 — Scénarios de tests contractuels
1. Références
- Spécification :
PD-101-specification.md - Epic :
EPIC-XX - JIRA :
PD-101
2. Matrice de couverture
| ID Invariant | ID Critère | ID Test | Couverture | Commentaire |
| INV-01-zero-knowledge | CA-03 | TC-INV-01 | Oui | Vérifie absence de payload clair en transit. |
| INV-02-pre-encryption | CA-03 | TC-INV-02 | Oui | Vérifie ordre strict chiffrement FILE-LEVEL avant upload. |
| INV-03-probatory-fidelity-default | CA-01 | TC-NOM-01 | Oui | Hash probatoire = hash fichier soumis (reçu par l'app) en mode fidèle. |
| INV-04-explicit-optimized-consent | CA-02 | TC-NOM-03 | Oui | Consentement explicite + traçabilité optimized=true + preuve §3.4. |
| INV-05-hash-functional-validation | CA-11 | TC-INV-05 | Oui | Validation fonctionnelle côté mobile (recalcul post-chiffrement). |
| INV-06-nonce-uniqueness | CA-04 | TC-INV-06 | Oui | Nonce unique par doc_id, un seul nonce FILE-LEVEL. |
| INV-07-sensitive-purge | CA-10 | TC-NOM-06 | Oui | purgeStale() exécuté avant chiffrement. Purge disque stricte, RAM best-effort (H-06). |
| INV-08-envelope-encryption | CA-13 | TC-INV-08 | Oui | Vérifie absence de secret en clair au repos en DB. |
| INV-09-state-transitions | CA-08, CA-09 | TC-INV-09 | Oui | Vérifie transitions autorisées/interdites UI+backend, y compris READY→CANCELLED. |
| INV-10-no-sensitive-logs | CA-14 | TC-INV-10 | Oui | Vérifie redaction logs sensibles. |
| — | CA-05 | TC-ERR-01 | Oui | Refus >500 MB avant chiffrement/upload. |
| — | CA-06 | TC-NOM-02 | Oui | Seuil 10 MB strict (9.99 simple / 10.00 multipart). |
| — | CA-07 | TC-ERR-03 | Oui | Retry simple global vs multipart par chunk. |
| — | CA-08 | TC-ERR-07 | Oui | Annulation orchestrée complète + état final. |
| — | CA-09 | TC-NOM-05 | Oui | Continuité background + unicité notification. |
| — | CA-12 | TC-NR-03 | Oui | Campagne perf P95 sur environnement contractuel. |
| — | CA-13 | TC-INV-08 | Oui | Aucun secret crypto en clair en DB. |
| — | CA-14 | TC-INV-10 | Oui | Aucun log avec plaintext/clé/nonce/hash corrélable. |
3. Scénarios de test – Flux nominaux
TEST-ID: TC-NOM-01
Référence spec: INV-03, CA-01, Flux 5.1
GIVEN
- Fichier de 20 MB valide (<= 500 MB), source File picker
- Mode par défaut actif (optimized=false)
- Connectivité réseau stable
WHEN
- L'utilisateur confirme le dépôt
THEN
- Le flux utilise multipart (>=10 MB)
- L'état UI final est COMPLETED
- Les états backend observés sont PENDING -> READY -> PENDING_SEAL
AND
- Le hash probatoire stocké est identique au hash du fichier soumis (reçu par l'app)
- Le chiffrement est FILE-LEVEL (un seul nonce pour tout le fichier)
TEST-ID: TC-NOM-02
Référence spec: CA-06, Flux 5.1, Paramètres 5.5
GIVEN
- Fichier A de 9 999 999 bytes (< 10 000 000 bytes)
- Fichier B de 10 000 000 bytes (= 10 MB SI base 10)
WHEN
- L'upload est lancé pour A puis pour B
THEN
- A est traité en upload simple
- B est traité en upload multipart
AND
- Aucun basculement de stratégie contraire au seuil fixe de 10 MB (SI base 10) n'est observé
TEST-ID: TC-NOM-03
Référence spec: INV-04, CA-02, Flux 5.2, §3.4
GIVEN
- Fichier valide
- Option "Capture optimisée" disponible mais inactive
WHEN
- L'utilisateur active le mode optimisé et confirme explicitement l'avertissement
THEN
- Le dépôt est marqué optimized=true
- Le hash probatoire correspond à la version transformée
AND
- Le journal d'audit contient la preuve de consentement explicite horodatée au format §3.4
- Les metadata backend contiennent la preuve de consentement au format §3.4
- Toute tentative de retour au mode fidèle pour ce dépôt est refusée
TEST-ID: TC-NOM-04
Référence spec: Flux 5.1 étape 4, ST-06
GIVEN
- Asset Photos iOS connu comme transcodé
- Parcours via Photos picker
WHEN
- L'utilisateur sélectionne l'asset et choisit de continuer malgré l'avertissement
THEN
- Un avertissement de transcodage est affiché avant poursuite
AND
- ios_transcoded=true est enregistré dans les metadata backend
- Le hash probatoire porte sur le fichier reçu par l'app (post-transcodage)
- Le choix utilisateur (continuer/changer de source) est journalisé dans le journal d'audit
TEST-ID: TC-NOM-05
Référence spec: CA-09, Flux 5.3
GIVEN
- Upload en état UPLOADING
- App passant en arrière-plan puis retour au premier plan
WHEN
- L'upload se termine pendant l'arrière-plan
THEN
- Une seule notification locale est émise (succès ou échec)
- Au retour foreground, l'état affiché correspond à l'état réel
AND
- Aucun doublon de notification ni perte de progression n'est observé
TEST-ID: TC-NOM-06
Référence spec: INV-07, CA-10, ST-07
GIVEN
- Présence d'artefacts sensibles obsolètes sur disque simulant un crash précédent
WHEN
- Un nouveau flux d'upload démarre
THEN
- purgeStale() est exécuté avant toute opération de chiffrement
AND
- Les artefacts obsolètes sur disque sont supprimés et tracés dans le journal d'audit
- Les références mémoire aux buffers sensibles sont nullifiées (best-effort Hermes, cf. H-06)
TEST-ID: TC-NOM-07
Référence spec: Flux 5.1 étape 5, ST-10
GIVEN
- Fichier contenant des métadonnées EXIF (photo JPEG avec géolocalisation, modèle appareil)
WHEN
- L'utilisateur sélectionne le fichier pour dépôt
THEN
- Un disclaimer EXIF est affiché indiquant que les métadonnées seront conservées dans le fichier probatoire
- L'upload ne peut PAS démarrer tant que l'utilisateur n'a pas confirmé explicitement
AND
- La confirmation EXIF est journalisée dans le journal d'audit
TEST-ID: TC-NOM-08
Référence spec: Flux 5.4, ST-09
GIVEN
- Un flux d'upload précédent terminé en état FAILED
WHEN
- L'utilisateur retente le dépôt du même fichier
THEN
- Un nouveau flux complet démarre avec un nouveau doc_id et un nouveau nonce
- L'ancien enregistrement backend reste inchangé (état PENDING/FAILED)
AND
- Aucune réutilisation de doc_id ou nonce de l'ancien flux
- Le nouveau flux suit le parcours nominal complet (chiffrement, upload, finalisation)
4. Scénarios de test – Cas d'erreur
TEST-ID: TC-ERR-01
Référence spec: ERR-01, CA-05
GIVEN
- Fichier de 700 MB
WHEN
- L'utilisateur tente le dépôt
THEN
- Rejet immédiat côté UX avec message explicite
- Aucun chiffrement déclenché
- Aucune initialisation backend/upload
AND
- L'état UI n'entre pas en UPLOADING
TEST-ID: TC-ERR-02
Référence spec: ERR-02, INV-02, INV-07
GIVEN
- Fichier valide
- Injection d'un échec chiffrement local
WHEN
- Le chiffrement est lancé
THEN
- Le flux est interrompu immédiatement
- L'état UI devient FAILED
AND
- Les artefacts sensibles sont purgés
- Aucune requête d'upload n'est émise
TEST-ID: TC-ERR-03
Référence spec: ERR-03/04/05, CA-07, Paramètres 5.5
GIVEN
- Cas A: upload simple avec erreur retryable
- Cas B: upload multipart avec erreur retryable sur un chunk
WHEN
- L'erreur survient
THEN
- Cas A: retry appliqué au niveau global du fichier
- Cas B: retry appliqué uniquement au chunk en échec
AND
- Nombre max de tentatives respecte Retry max configuré
- Backoff exponentiel 1/2/4 + jitter actif observé
TEST-ID: TC-ERR-04
Référence spec: ERR-06, ERR-09
GIVEN
- Requête API contenant métadonnée invalide (ex: sha3_256 non conforme)
WHEN
- La requête est soumise
THEN
- Réponse 400 est retournée
- L'état backend READY n'est jamais atteint
AND
- Le motif de validation est traçable dans le journal d'audit
TEST-ID: TC-ERR-05
Référence spec: ERR-08, CA-09
GIVEN
- Upload terminé en background
- Séquence de reprise foreground multiple
WHEN
- Les événements de reprise sont déclenchés
THEN
- Au plus une notification locale est émise pour la session d'upload
AND
- Aucune duplication d'état COMPLETED/FAILED n'est présentée en UI
TEST-ID: TC-ERR-06
Référence spec: ERR-06
GIVEN
- Upload en cours (simple ou multipart)
- Le backend retourne un HTTP 4xx fonctionnel (400, 403, 404, 409, 413, 422)
WHEN
- La réponse 4xx est reçue par le client
THEN
- Aucun retry n'est tenté (erreur non retryable)
- L'état UI passe immédiatement à FAILED
AND
- Un message d'erreur explicite mappé au code HTTP est affiché à l'utilisateur
- L'erreur est tracée dans le journal d'audit avec le code HTTP et le motif
TEST-ID: TC-ERR-07
Référence spec: ERR-07, CA-08, INV-09
GIVEN
- Upload multipart en cours avec parts actives
WHEN
- L'utilisateur annule explicitement
THEN
- L'envoi client s'arrête
- Le backend passe à CANCELLED
AND
- AbortMultipartUpload est déclenché (best-effort, cf. §5.9)
- Les parts multipart S3 restantes seront nettoyées par le job de réconciliation ou la lifecycle policy
- Aucun retour vers un état non terminal n'est observé
TEST-ID: TC-ERR-08
Référence spec: ERR-10, §5.7 race condition, ST-11
GIVEN
- Document en état backend READY
- Worker d'ancrage prêt à transitionner READY -> PENDING_SEAL
WHEN
- L'utilisateur demande l'annulation simultanément au worker d'ancrage
THEN
- Un seul des deux réussit (atomicité UPDATE WHERE status='READY')
- Si le worker gagne : l'annulation échoue, le client reçoit un message d'erreur explicite
- Si l'annulation gagne : le backend passe à CANCELLED, le worker ne trouve plus de document READY
AND
- Aucun état incohérent n'est observé (pas de CANCELLED + PENDING_SEAL simultanés)
5. Tests d'invariants (non négociables)
TEST-ID: TC-INV-01
Référence spec: INV-01-zero-knowledge, CA-03
GIVEN
- Fichier valide de 5 MB (upload simple)
- Fichier valide de 15 MB (upload multipart)
- Proxy d'inspection réseau actif entre le client et le backend/S3
WHEN
- Les deux uploads sont exécutés
THEN
- Aucun payload réseau ne contient le contenu document en clair
- Tous les payloads transmis sont du ciphertext AES-256-GCM
AND
- Le proxy confirme l'absence de tout octet du plaintext original dans les requêtes HTTP
TEST-ID: TC-INV-02
Référence spec: INV-02-pre-encryption, CA-03
GIVEN
- Fichier valide
- Instrumentation des appels réseau et du module de chiffrement (timestamps)
WHEN
- Le flux d'upload est exécuté
THEN
- Le timestamp de fin de chiffrement FILE-LEVEL est strictement antérieur au timestamp du premier appel réseau d'upload
AND
- Aucune requête d'upload n'est émise tant que le chiffrement n'est pas terminé
- Le chiffrement produit un seul ciphertext pour l'ensemble du fichier (FILE-LEVEL)
TEST-ID: TC-INV-03
Référence spec: INV-03-probatory-fidelity-default, CA-01
GIVEN
- Fichiers de formats variés (JPEG, PDF, DOCX, MP4) en mode par défaut
WHEN
- Chaque fichier est soumis au flux de dépôt
THEN
- Pour chaque fichier, le hash SHA3-256 du fichier soumis (reçu par l'app) est identique au hash probatoire stocké
AND
- Aucune transformation (compression, conversion, redimensionnement) n'est appliquée
TEST-ID: TC-INV-04
Référence spec: INV-04-explicit-optimized-consent, CA-02
GIVEN
- Fichier valide
- Mode optimisé désactivé par défaut
WHEN
- Tentative de dépôt en mode optimisé SANS confirmation explicite de l'avertissement
THEN
- Le dépôt est bloqué
- optimized reste false
AND
- Aucune transformation n'est appliquée au fichier
- Le journal d'audit ne contient pas de preuve de consentement
TEST-ID: TC-INV-05
Référence spec: INV-05-hash-functional-validation, CA-11
GIVEN
- Fichier valide dont le contenu est connu
- Corruption simulée : 1 bit modifié dans le plaintext après le premier calcul de hash
WHEN
- Le mobile effectue le recalcul de vérification (étape 7 du flux 5.1)
THEN
- La divergence entre le hash initial et le hash recalculé est détectée
- Le flux est aborté (ERR-02)
AND
- Le backend ne reçoit pas de requête d'upload
- L'erreur de vérification d'intégrité est tracée dans le journal d'audit
TEST-ID: TC-INV-06
Référence spec: INV-06-nonce-uniqueness, CA-04
GIVEN
- 100 dépôts successifs de fichiers valides (même fichier ou fichiers différents)
WHEN
- Le nonce AES-GCM est généré pour chaque dépôt
THEN
- Aucune collision de nonce n'est observée sur l'ensemble des 100 dépôts
AND
- Chaque nonce est exactement 12 bytes
- Un seul nonce est utilisé par fichier (chiffrement FILE-LEVEL, pas chunk-level)
TEST-ID: TC-INV-07
Référence spec: INV-07-sensitive-purge, CA-10
GIVEN
- Artefacts sensibles simulés sur disque (fichier clair, clé temporaire, buffer intermédiaire)
- Simulation de crash précédent (artefacts résiduels)
WHEN
- Un nouveau flux d'upload démarre
THEN
- purgeStale() est exécuté en premier, avant toute opération de chiffrement
- Tous les fichiers sensibles résiduels sur disque sont supprimés
AND
- Les suppressions sont tracées dans le journal d'audit
- Les références mémoire sont nullifiées (vérification best-effort sur Hermes, cf. H-06)
TEST-ID: TC-INV-08
Référence spec: INV-08-envelope-encryption, CA-13
GIVEN
- Un dépôt complété avec succès (état READY ou PENDING_SEAL)
- Accès lecture à la base de données backend
WHEN
- Inspection directe des colonnes contenant des données cryptographiques
THEN
- Aucune DEK, KEK ou nonce brut n'est stocké en clair
- Tous les secrets sont chiffrés par envelope encryption (AES-256-GCM ou HSM envelope)
AND
- La requête SQL `SELECT * FROM ... WHERE column LIKE '%plaintext_pattern%'` ne retourne aucun résultat pour les colonnes crypto
TEST-ID: TC-INV-09
Référence spec: INV-09-state-transitions, §5.7
GIVEN
- Machine à états UI (UPLOADING, FAILED, COMPLETED, CANCELLED)
- Machine à états backend (PENDING, READY, PENDING_SEAL, CANCELLED)
WHEN
- Tentative de chaque transition possible (autorisée et interdite) selon la table §5.7
THEN
- Toutes les transitions autorisées réussissent
- Toutes les transitions interdites sont rejetées
AND
- COMPLETED et CANCELLED (UI) sont terminaux : aucune sortie possible
- CANCELLED (backend) est terminal : aucune sortie possible
- READY -> CANCELLED est autorisée avec garde atomique (UPDATE WHERE status='READY')
- PENDING_SEAL -> CANCELLED est interdite
- FAILED -> UPLOADING crée un nouveau flux (nouveau doc_id, cf. §5.4)
TEST-ID: TC-INV-10
Référence spec: INV-10-no-sensitive-logs, CA-14
GIVEN
- Un flux d'upload complet (de la sélection à la finalisation)
- Collecte de tous les journaux applicatifs et d'audit
WHEN
- Scan automatisé des journaux avec patterns de détection :
- Plaintext du fichier original
- Clés de chiffrement (DEK, KEK)
- Nonces bruts (12 bytes en hex ou base64)
- Hash corrélable au contenu sans justification métier
THEN
- Aucun pattern sensible n'est détecté dans les journaux
AND
- Les identifiants de corrélation (doc_id, correlation_id) sont présents mais ne permettent pas de reconstituer le contenu
6. Tests de non-régression
| Test ID | Objet | Observable | Commentaire |
| TC-NR-01 | Seuil multipart fixe 10 MB (10 000 000 bytes SI) | Comportement inchangé 9 999 999 / 10 000 000 bytes | Empêche dérive de seuil produit. |
| TC-NR-02 | Règles de transitions terminales | Absence de sortie depuis COMPLETED/CANCELLED | Protection machine à états. |
| TC-NR-03 | Performance 100 MB P95 <= 30 s (WiFi iPhone 12/A14) | Rapport campagne P95 | Non bloquant métier mais suivi qualité. |
| TC-NR-04 | Retry + jitter | Backoff observé et jitter actif | Évite régression réseau/thundering herd. |
| TC-NR-05 | purgeStale au démarrage | Trace d'exécution systématique | Évite fuite post-crash au fil versions. |
| TC-NR-06 | Chiffrement FILE-LEVEL (un seul nonce par fichier) | Vérification qu'aucun chiffrement chunk-level n'est introduit | Empêche régression sécurité GCM. |
7. Tests négatifs et adversariaux
| Test ID | Entrée invalide / abus | Résultat attendu | Observable |
| TC-NEG-01 | doc_id non UUID v4 | Rejet 400 | Code retour + motif validation |
| TC-NEG-02 | sha3_256 uppercase ou longueur != 64 | Rejet 400 | Journal d'audit validation + absence READY |
| TC-NEG-03 | nonce longueur != 12 bytes | Échec chiffrement ou rejet 400 selon point de contrôle | Trace erreur crypto/validation |
| TC-NEG-04 | auth_tag longueur != 16 bytes | Rejet 400 | Réponse API déterministe |
| TC-NEG-05 | optimized non booléen ("true") | Rejet 400 | Contrôle type strict |
| TC-NEG-06 | mime_type invalide RFC | Rejet 400 | Absence de transition upload |
| TC-NEG-07 | Tentative transition backend PENDING_SEAL -> CANCELLED | Transition refusée | Journal d'audit état invariant |
| TC-NEG-08 | Désactivation jitter en configuration | Non-conformité contractuelle | Vérification config + exécution retry |
| TC-NEG-09 | Tentative upload en clair injectée | Rejet/échec conformité | Analyse trafic + journal d'audit sécurité |
| TC-NEG-10 | Logs incluant nonce brut/clé/hash sensible | Non-conformité sécurité | Scan journaux et rapport violation |
| TC-NEG-11 | Tentative de chiffrement chunk-level (nonce par chunk) | Rejet/non-conformité | Vérification qu'un seul nonce est utilisé par doc_id |
8. Observabilité requise pour les tests
- État système : machine d'états UI (
UPLOADING/FAILED/COMPLETED/CANCELLED) et backend (PENDING/READY/PENDING_SEAL/CANCELLED) horodatées. - Réponse API : codes HTTP, payload de validation, identifiants corrélables de session/test.
- Journal d'audit : consentement optimisé (format §3.4), confirmation EXIF, déclenchement annulation, transitions d'états, trace
purgeStale(), ios_transcoded, race condition READY→CANCELLED. - Événement signé / horodaté : finalisation upload, passage
READY -> PENDING_SEAL, notification background. - Export probatoire : métadonnées contractuelles (
doc_id, optimized, ios_transcoded, hash probatoire, taille, mime, timestamps). - Télémétrie réseau : inspection payload (absence clair), retries, backoff, jitter, latences.
- Télémétrie sécurité : détection secrets en logs et contrôle artefacts au repos.
- Télémétrie chiffrement : timestamps chiffrement, nombre de nonces générés par flux, vérification FILE-LEVEL.
9. Règles non testables
| Règle | Raison | Impact |
| TTL URL pré-signées (Q-02) | Paramètre contractuel absent (défaut/min/max/comportement expiration non défini) | Majeur |
| Liste blanche MIME/UTType (Q-03) | Politique d'acceptation non spécifiée | Majeur |
| Persistance états UI après redémarrage (Q-04) | Comportement cible non défini | Majeur |
| Contrat backend exact des champs probatoires (Q-05) | Schéma de vérité backend non fourni | Majeur |
| Exigence formelle de nettoyage mémoire RAM (Q-06) | Critère d'audit mesurable non défini ; purge RAM best-effort sur Hermes (H-06) | Majeur |
| Référence épique nominale (Q-01) | Référencement documentaire incomplet (non bloquant test exécutable) | Mineur |
10. Verdict QA
- ⚠️ Testable partiellement (avec réserves listées)
Motif : - Les invariants et critères d'acceptation sont couverts par des scénarios déterministes et automatisables. - Les tests d'invariants (TC-INV-01 à TC-INV-10) disposent désormais de scénarios GIVEN/WHEN/THEN complets. - La conformité complète reste conditionnée à la levée des points non testables (TTL, whitelist MIME, persistance UI, contrat backend, protocole d'audit mémoire).