Aller au contenu

Spécification canonique contractuelle — PD-63

Story : PD-63 Endpoint : GET /documents/:id/download Epic : PD-192 (DOCS-API)

1. Objectif

Permettre à un utilisateur authentifié d'obtenir un accès temporaire au blob chiffré d'un document dont il est légitimement détenteur, en garantissant simultanément :

  • le respect strict du modèle zero-knowledge,
  • la non-divulgation de toute clé de chiffrement,
  • la traçabilité probatoire complète de la demande d'accès,
  • l'application des règles de révocation et de délégation,
  • la compatibilité avec l'architecture multi-cloud (OVH + AWS Glacier).

2. Périmètre / Hors périmètre

2.1 Périmètre

  • Vérification d'authentification de l'appelant.
  • Vérification de légitimité d'accès au document (owner ou délégation/enveloppe valide).
  • Émission d'un accès temporaire au contenu chiffré (TTL 5 minutes).
  • La réponse succès retourne un JSON contenant une URL pré-signée S3.
  • Journalisation probatoire de chaque demande de téléchargement (succès et rejet).
  • Respect des règles de révocation au moment de la demande d'accès.
  • Comportement homogène sur les verticales B2C, RH, Mineurs, B2B2C, PRE Legal.

2.2 Hors périmètre

  • Déchiffrement côté serveur.
  • Exposition de clés (K_doc, K_master, clés dérivées).
  • Quotas de téléchargement.
  • Streaming de fichiers > 1 Go.
  • Reprise partielle (Range requests).
  • Téléchargement batch (ZIP).
  • Politique UX client de téléchargement.
  • Règles non testables techniquement dans cet endpoint : hors périmètre (cf. section 10).

3. Définitions

  • Document chiffré : objet binaire stocké chiffré, jamais manipulé en clair par le backend.
  • Téléchargement (dans PD-63) : action d'obtenir un droit d'accès temporaire au blob chiffré.
  • Légitimité d'accès : possession d'un droit valide (propriété, co-détention, enveloppe/délégation active).
  • Révocation : invalidation d'un droit d'accès; bloque toute nouvelle autorisation.
  • Traçabilité probatoire : enregistrement auditable append-only de l'événement de demande.
  • TTL : durée maximale de validité de l'accès temporaire, fixée à 5 minutes (configurable par environnement).
  • Accès implicite/latéral : accès non explicitement accordé par les règles de détention/délégation.
  • Suppression logique : état métier où le document reste référencé mais n'est plus téléchargeable; champ modèle requis : deleted_at (timestamp nullable) et deletion_reason (enum/code).
  • Verrouillage juridique : état bloquant temporaire imposé par contrainte légale/probatoire; champ modèle requis : legal_lock (bool), legal_lock_reason (code), legal_lock_until (timestamp nullable).

3.1 Statuts document autorisés

Statut document Téléchargeable
PENDING Non (attente validation)
SEALED Oui
EXPIRED Non (rétention dépassée)
ARCHIVED Oui (si restauré)

4. Invariants (non négociables)

ID Règle Justification
INV-63-01 Le serveur ne voit jamais le document en clair, avant, pendant ou après la demande de téléchargement. Zero-knowledge contractuel.
INV-63-02 Le serveur n'expose jamais K_doc, K_master ni aucune clé dérivée dans les réponses, logs, erreurs ou métadonnées. Confidentialité cryptographique.
INV-63-03 L'accès délivré est strictement temporel (TTL nominal 5 min). L'URL pré-signée est réutilisable durant la fenêtre TTL (comportement S3 natif) et devient invalide après expiration du TTL. Réduction de surface d'attaque.
INV-63-04 Aucun téléchargement n'est autorisé sans authentification valide. Contrôle d'accès minimal.
INV-63-05 Chaque demande de téléchargement (acceptée ou rejetée) produit un événement journalisé probatoire; si la journalisation probatoire échoue, la requête est rejetée (fail-closed). Auditabilité et non-répudiation.
INV-63-06 Toute révocation effective bloque immédiatement l'émission d'un nouvel accès temporaire. Sécurité dynamique des droits.
INV-63-07 Le comportement contractuel est compatible multi-cloud (OVH + AWS Glacier) sans divergence de règles de sécurité. Portabilité réglementée.
INV-63-08 Aucun accès implicite/latéral n'est autorisé; seul un droit explicite valide ouvre l'accès. Prévention des accès abusifs.
INV-63-09 L'endpoint ne modifie ni le contenu ni l'état WORM du document. Intégrité légale de conservation.
INV-63-10 Les réponses d'erreur ne divulguent ni clés, ni chemin de stockage, ni informations excessives sur la politique d'accès. Réduction des fuites d'information.

5. Flux nominaux

5.1 Flux A — Owner (B2C)

  1. Utilisateur authentifié appelle GET /documents/:id/download.
  2. Le système vérifie que l'utilisateur est détenteur propriétaire du document.
  3. Le système vérifie absence de révocation bloquante.
  4. Le système journalise l'événement probatoire de demande d'accès.
  5. Si la journalisation probatoire échoue, le système rejette la requête (fail-closed, ERR-63-11).
  6. Le système émet un accès temporaire au blob chiffré (TTL conforme).
  7. Réponse de succès JSON avec URL pré-signée S3, sans exposition de clé ni contenu en clair.

5.2 Flux B — Partage actif (délégation / PRE / transfert)

  1. Utilisateur authentifié appelle l'endpoint.
  2. Le système vérifie l'existence d'un droit de partage/délégation valide et non expiré.
  3. Le système vérifie absence de révocation.
  4. Le système journalise l'événement probatoire avec contexte de délégation.
  5. Si la journalisation probatoire échoue, le système rejette la requête (fail-closed, ERR-63-11).
  6. Le système émet un accès temporaire chiffré (même règles de sécurité que Owner).
  7. Réponse de succès JSON avec URL pré-signée S3, sans fuite de secrets.

5.3 Flux C — B2B (co-détention)

  1. Utilisateur authentifié appelle l'endpoint.
  2. Le système vérifie co-détention explicite active sur le document.
  3. Le système applique les mêmes contrôles de révocation et TTL.
  4. Le système journalise l'événement probatoire avec contexte B2B.
  5. Si la journalisation probatoire échoue, le système rejette la requête (fail-closed, ERR-63-11).
  6. Le système émet l'accès temporaire au blob chiffré.
  7. Réponse de succès JSON avec URL pré-signée S3, homogène (pas d'exception logique verticale).

5bis. Diagrammes

5bis.1 Diagramme d'états — Statut document et téléchargeabilité

Réf. : INV-63-09 (l'endpoint ne modifie ni le contenu ni l'état WORM), section 3.1.

stateDiagram-v2
    [*] --> PENDING : Upload initié
    PENDING --> SEALED : Validation complète
    SEALED --> EXPIRED : Rétention dépassée
    SEALED --> ARCHIVED : Archivage froid (Glacier)
    ARCHIVED --> SEALED : Restauration

    state PENDING {
        note right of PENDING
            Téléchargement INTERDIT
            (attente validation)
        end note
    }
    state SEALED {
        note right of SEALED
            Téléchargement AUTORISÉ
            (INV-63-03 : TTL 5 min)
        end note
    }
    state EXPIRED {
        note right of EXPIRED
            Téléchargement INTERDIT
            (rétention dépassée)
        end note
    }
    state ARCHIVED {
        note right of ARCHIVED
            Téléchargement AUTORISÉ
            si restauré (INV-63-07)
        end note
    }

    note left of [*]
        INV-63-09 : PD-63 ne modifie
        jamais l'état du document
    end note

5bis.2 Diagramme de séquence — Flux nominal Owner (Flux A)

Réf. : INV-63-01 (zero-knowledge), INV-63-02 (aucune clé exposée), INV-63-03 (TTL 5 min), INV-63-04 (auth obligatoire), INV-63-05 (audit fail-closed), INV-63-06 (révocation), INV-63-08 (droit explicite), INV-63-10 (pas de fuite d'info).

sequenceDiagram
    actor Client
    participant API as GET /documents/:id/download
    participant Auth as Auth Guard
    participant ACL as Access Control
    participant Audit as Audit Probatoire
    participant S3 as OVH/AWS S3

    Client->>API: GET /documents/:id/download (Bearer token)
    activate API

    API->>Auth: Vérifier authentification
    Note right of Auth: INV-63-04 : auth obligatoire
    alt Token absent/invalide/expiré
        Auth-->>API: 401 (ERR-63-02)
        API->>Audit: Journaliser rejet (DENY)
        API-->>Client: 401 Unauthorized
    end
    Auth-->>API: userId, tenantId

    API->>ACL: Vérifier droit explicite (owner/délégation/co-détention)
    Note right of ACL: INV-63-08 : droit explicite requis
    ACL->>ACL: Vérifier absence de révocation
    Note right of ACL: INV-63-06 : révocation bloquante
    alt Pas de droit / droit révoqué
        ACL-->>API: DENY
        API->>Audit: Journaliser rejet (DENY, reason)
        API-->>Client: 403 Forbidden (ERR-63-03/04)
        Note right of Client: INV-63-10 : message uniforme (anti-énumération)
    end
    ACL-->>API: ALLOW

    API->>Audit: Journaliser demande (ALLOW)
    Note right of Audit: INV-63-05 : fail-closed
    alt Audit indisponible
        Audit-->>API: Échec
        API-->>Client: 503 (ERR-63-11) — aucun accès délivré
    end
    Audit-->>API: OK (correlation_id, timestamp_utc)

    API->>S3: Générer URL pré-signée (TTL 5 min)
    Note right of S3: INV-63-03 : TTL borné<br/>INV-63-07 : multi-cloud<br/>INV-63-01 : blob chiffré uniquement
    alt S3 indisponible
        S3-->>API: Échec
        API-->>Client: 503 (ERR-63-10)
    end
    S3-->>API: presigned_url (blob chiffré)

    API-->>Client: 200 JSON { presigned_url }
    deactivate API
    Note over Client,S3: INV-63-02 : aucune clé (K_doc, K_master) dans la réponse<br/>INV-63-09 : aucune modification du document/WORM

6. Cas d'erreur

ID Code HTTP Condition Réponse attendue
ERR-63-01 400 :id invalide (format non conforme) Erreur structurée, aucune donnée sensible.
ERR-63-02 401 Authentification absente/invalide/expirée Erreur d'authentification standardisée.
ERR-63-03 403 Authentifié mais sans droit explicite valide (owner/délégation/co-détention), y compris document existant mais non autorisé Erreur d'autorisation sans divulgation de secrets (anti-énumération).
ERR-63-04 403 Droit révoqué Erreur d'autorisation, accès refusé.
ERR-63-05 404 Document réellement introuvable (identifiant inexistant) Erreur de non-disponibilité sans metadata sensible.
ERR-63-06 410 Document supprimé logiquement ou indisponible définitivement selon politique de conservation Erreur explicite de non-disponibilité définitive.
ERR-63-07 423 Document temporairement verrouillé (conflit d'état juridique/probatoire) Erreur de verrouillage avec message neutre.
ERR-63-08 429 Limitation de débit (si activée globalement par plateforme) Erreur de throttling standard; optionnelle si feature active.
ERR-63-09 500 Erreur interne non qualifiée Erreur générique sans information sensible.
ERR-63-10 503 Dépendance de délivrance d'accès temporaire indisponible Erreur de service indisponible, retry possible côté client.
ERR-63-11 503 Journalisation probatoire indisponible/échouée Requête rejetée en fail-closed; aucun accès temporaire délivré.

Note de compatibilité des codes d'erreur : Les codes ERR-63-* remplacent les codes ERR-46-* pour cet endpoint. Mapping de référence : ERR-46-01→ERR-63-02, ERR-46-02→ERR-63-03, ERR-46-03→ERR-63-04, ERR-46-04→ERR-63-05, ERR-46-05→ERR-63-10.

7. Critères d'acceptation (testables)

ID Critère Observable
CA-63-01 Un utilisateur authentifié propriétaire reçoit une réponse succès avec accès temporaire au blob chiffré. HTTP 2xx + JSON contenant une URL pré-signée S3 + absence de clé.
CA-63-02 Un utilisateur non authentifié est systématiquement rejeté. HTTP 401.
CA-63-03 Un utilisateur authentifié sans droit explicite est rejeté. HTTP 403.
CA-63-04 Un droit révoqué bloque l'accès, même si antérieurement valide. HTTP 403 après révocation.
CA-63-05 La validité de l'accès temporaire est bornée à 5 minutes (ou valeur d'environnement documentée). Accès valide dans TTL, invalide après TTL.
CA-63-06 Aucune réponse succès/erreur n'expose de clés cryptographiques ni contenu en clair. Inspection payload/headers/logs : aucune clé/cleartext.
CA-63-07 Chaque demande produit une trace probatoire append-only consultable a posteriori. Événement audit présent pour succès et rejet avec champs obligatoires : actor_id, document_id, tenant_id, decision (ALLOW/DENY), reason, timestamp_utc, correlation_id.
CA-63-08 L'endpoint n'altère pas le document ni son statut WORM. État stockage identique avant/après appel.
CA-63-09 Les 3 flux nominaux (Owner, Partage actif, B2B) passent avec règles identiques de sécurité. Jeux de tests verticaux homogènes.
CA-63-10 Le comportement contractuel est identique quel que soit le backend de stockage cloud. Résultats de tests contractuels équivalents OVH/AWS.

8. Scénarios de test (Given/When/Then)

8.1 Nominal

ID Given When Then
ST-63-01 Utilisateur owner authentifié, document existant, non révoqué Appel GET /documents/:id/download 2xx + accès temporaire chiffré + audit créé
ST-63-02 Utilisateur avec délégation active authentifié Appel endpoint 2xx + accès temporaire + audit avec contexte délégation
ST-63-03 Utilisateur co-détenteur B2B authentifié Appel endpoint 2xx + accès temporaire + audit B2B
ST-63-04 Accès délivré, horloge dans fenêtre TTL Consommation de l'accès Accès accepté
ST-63-05 Accès délivré, horloge hors TTL Consommation de l'accès Accès refusé

8.2 Sécurité / droits

ID Given When Then
ST-63-06 Requête sans authentification Appel endpoint 401
ST-63-07 Authentifié sans droit explicite Appel endpoint 403 + pas de métadonnée sensible
ST-63-08 Droit révoqué avant appel Appel endpoint 403
ST-63-09 Tentative d'accès latéral inter-tenant Appel endpoint 403 (anti-énumération), audit rejet
ST-63-10 Réponse succès et erreur collectées Analyse payload/log Aucune clé, aucun cleartext

8.3 Traçabilité / conformité

ID Given When Then
ST-63-11 Appel succès Traitement complet 1 événement probatoire append-only créé
ST-63-12 Appel rejeté (401/403/404) Traitement complet 1 événement probatoire append-only créé
ST-63-13 Série d'appels sur même document Vérification audit Événements horodatés, ordonnés, non modifiables
ST-63-14 Appel endpoint répété Comparaison état stockage Aucun changement WORM

8.4 Résilience

ID Given When Then
ST-63-15 Service de délivrance d'accès temporaire indisponible Appel endpoint 503 + pas de fuite sensible + audit rejet
ST-63-16 Erreur interne non qualifiée Appel endpoint 500 générique + audit rejet
ST-63-17 Service audit indisponible Appel endpoint 503 (fail-closed) + aucun accès délivré

9. Hypothèses explicites

ID Hypothèse
H-63-01 Le mécanisme de délivrance d'accès temporaire sécurisé de PD-46 est disponible et contractuellement stable.
H-63-02 Les règles de légitimité (owner, délégation, co-détention) sont déterminables de façon univoque au moment de l'appel.
H-63-03 Les événements probatoires d'accès (succès/rejet) sont admissibles dans la chaîne de preuve composite et sont signés via PD-37 (HSM audit signature) ou chaînés cryptographiquement selon l'architecture cible.
H-63-04 Le TTL nominal est de 5 minutes, avec possibilité de variation par environnement sans changer la sémantique de sécurité.
H-63-05 La politique de révocation est déjà définie au niveau domaine et exposable à cet endpoint en lecture décisionnelle.
H-63-06 Les exigences RGPD applicables à cet endpoint se limitent à minimisation des données retournées et auditabilité d'accès.
H-63-07 Les guards de vérification partage/co-détention sont implémentés et testables.

10. Points à clarifier

  1. Code attendu pour document archivé/gelé : 410 vs 423 selon statut métier/légal.
  2. Niveau minimal de métadonnées retournées en succès (ex. nom logique, type MIME) pour conformité RGPD (minimisation).
  3. Compatibilité AWS Glacier : contraintes de latence/récupération froide et impact contractuel sur SLA de l'endpoint.
  4. Événements "hors périmètre" non testables ici : preuve cryptographique composite finale (assemblage inter-services) à cadrer dans une spec transverse.

Règles marquées hors périmètre (non testables dans PD-63 seul)

  • Validation juridique complète de la preuve composite bout-en-bout inter-systèmes.
  • Performance/latence garanties sous restauration Glacier (dépend d'opérations de tier externe).
  • Contrôle réglementaire documentaire hors API (exigences organisationnelles non observables par tests endpoint).

Généré par : ChatGPT (OpenCode, gpt-5.3-codex) Date : 2026-02-20 Version : v2 — Corrections Gate 3 v1