Aller au contenu

PD-43 — Créer service upload OVH S3 avec streaming (multipart)

1. Objectif

Mettre à disposition un service d’upload de fichiers volumineux vers un stockage OVH Object Storage S3-compatible, en multipart et streaming, avec calcul d’empreinte cryptographique pendant l’upload, afin de : - réduire la consommation mémoire serveur (streaming), - supporter des fichiers de grande taille, - produire une empreinte vérifiable du contenu uploadé, - garantir robustesse, reprise et traçabilité.

1.1 Distinction empreinte de transport / empreinte probatoire

L’empreinte calculée par ce service est une empreinte de transport visant à garantir l’intégrité du flux uploadé.

Elle est calculée selon un algorithme, un format et une portée normatifs, afin d’être testable et reproductible.

Cette empreinte peut être réutilisée ou recalculée dans les étapes ultérieures du cycle ProbatioVault (chiffrement applicatif, stockage WORM, ancrage blockchain), mais ne constitue pas à elle seule une preuve probatoire au sens du cycle complet de preuve ProbatioVault.

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

Périmètre

  • Upload d’un objet vers OVH S3 via multipart upload.
  • Transmission en streaming (le service ne doit pas nécessiter de charger le fichier entier en mémoire).
  • Calcul d’empreinte du flux (pendant l’upload) et restitution de cette empreinte dans la réponse finale.
  • Gestion des états d’upload : initialisation, envoi de parts, complétion, abandon.
  • Contrôles d’accès et quotas applicatifs (au minimum : authentification + autorisation).
  • Gestion d’erreurs et conditions de reprise.

Hors périmètre

  • Chiffrement côté client / serveur : hors périmètre (aucune exigence explicite fournie).
  • Antimalware / DLP / analyse de contenu : hors périmètre.
  • Cycle de vie probatoire (WORM/Object Lock), horodatage, ancrage blockchain : hors périmètre.
  • Téléchargement (download), partage, PRE : hors périmètre.
  • UI/UX applicative : hors périmètre.

3. Définitions

  • S3 : API de stockage objet compatible Amazon S3.
  • OVH S3 : Object Storage OVH compatible S3.
  • Multipart Upload : protocole S3 permettant de découper un objet en parts (segments), uploadées indépendamment puis assemblées lors d’une étape de complétion.
  • Streaming : traitement du flux entrant au fil de l’eau, sans stockage complet préalable.
  • Empreinte / Hash : valeur cryptographique calculée selon l’algorithme SHA3-256, encodée en hexadécimal, sur la concaténation canonique des octets du fichier final reconstruit après complétion multipart.
  • Session d’upload : identifiant serveur représentant un multipart upload en cours.
  • Part : segment numéroté d’un multipart upload.
  • Utilisateur : identité authentifiée effectuant une requête.
  • Tenant : périmètre logique d’isolement regroupant un ou plusieurs utilisateurs.
  • Propriétaire de session : utilisateur et tenant au nom desquels une session d’upload est créée.

4. Invariants (non négociables)

  1. Aucun contenu en clair ne doit être journalisé (logs, traces, erreurs) : seuls des identifiants, tailles, et empreintes peuvent apparaître.
  2. Le service doit supporter le streaming : il est interdit d’exiger le chargement complet du fichier en mémoire côté service.
  3. L’empreinte doit être calculée sur exactement les octets effectivement uploadés, dans l’ordre logique du fichier final reconstruit.
  4. Une session d’upload ne peut être complétée qu’une seule fois, ou échouer explicitement (état final terminal).
  5. Une session d’upload doit être abortable (abandon) tant qu’elle n’est pas complétée.
  6. Les opérations doivent être authentifiées et autorisées ; aucun upload anonyme n’est autorisé.
  7. Les règles de validation (taille, nombre de parts, expirations, quotas) doivent être déterministes et testables.
  8. En cas d’erreur, l’état de la session doit rester cohérent (pas de complétion partielle silencieuse).
  9. L’algorithme, le format et la portée de l’empreinte sont normatifs et uniques afin de garantir la testabilité et la reproductibilité des vérifications.
  10. L’intégrité de l’objet stocké côté OVH S3 doit être vérifiée à la complétion à l’aide d’un mécanisme fournissant une garantie d’intégrité cryptographique, afin de garantir la cohérence entre le contenu hashé par le service et l’objet effectivement persisté.

    Un mécanisme fondé uniquement sur un identifiant non cryptographique (ex. ETag multipart seul) n’est pas suffisant. 11. Les opérations d’upload de part, de complétion et d’abandon doivent être idempotentes ou explicitement rejetées selon des règles déterministes définies ci-dessous, afin d’éviter tout effet de bord en cas de retry. 12. Chaque session d’upload est strictement rattachée à un tenant et à un propriétaire de session. Toute opération sur une session doit être refusée si le contexte d’authentification ne correspond pas à ce périmètre.

Règles de validation normatives

Les paramètres de validation suivants sont obligatoires, déterministes et testables, même s’ils sont configurables par politique applicative :

  • taille minimale de part,
  • taille maximale de part,
  • nombre maximal de parts par upload,
  • taille maximale de fichier,
  • durée maximale de validité d’une session,
  • métriques de quota applicables (taille cumulée, nombre d’uploads, débit).

Ces paramètres : - doivent être explicitement définis dans la configuration active du service, - doivent être identiques pour toute requête donnée dans un même contexte (tenant, plan), - doivent être consultables à des fins de test et d’audit, - doivent être publiés avant toute opération d’upload.

Les valeurs effectives de validation et de quota doivent être consultables via au minimum l’un des moyens suivants : - documentation versionnée, - endpoint de lecture des paramètres, - export de configuration auditable.

Toute déviation par rapport aux valeurs normatives par défaut définies en Annexe D doit être explicitement documentée.

Règles d’idempotence et de reprise

Les règles suivantes sont normatives, déterministes et testables :

  • Re-soumission d’une part identique (même numéro de part, contenu strictement identique) :
  • la requête est acceptée sans effet (idempotence stricte) ;
  • l’état de la session est inchangé ;
  • la réponse retournée est identique à celle de la première soumission réussie.

  • Re-soumission d’une part différente avec le même numéro :

  • la requête est rejetée explicitement (part invalide).

  • Re-demande de complétion :

  • si la session est déjà en état terminal (COMPLÉTÉE ou ABANDONNÉE), la requête retourne le même état terminal sans effet secondaire ;
  • aucune recomposition ou écriture supplémentaire n’est effectuée.

  • Retry après interruption réseau :

  • une requête partiellement reçue n’est jamais validée ;
  • le client peut renvoyer la requête sans provoquer de duplication.

Règles d’autorisation et d’isolement

Les règles suivantes sont normatives, déterministes et testables :

  • Une session d’upload ne peut être créée que dans le contexte d’un tenant donné.
  • Seuls les utilisateurs appartenant à ce tenant peuvent interagir avec la session.
  • Par défaut, et en l’absence de toute règle explicite de délégation définie dans une politique de sécurité applicable, seul le propriétaire de la session est autorisé à :
  • uploader des parts,
  • demander la complétion,
  • demander l’abandon.
  • En l’absence de règle explicite de délégation documentée, aucune autre opération n’est autorisée sur une session, y compris pour d’autres utilisateurs du même tenant.
  • Toute délégation de droits (ex. accès par un autre utilisateur du tenant) doit être :
  • explicitement définie dans une politique de sécurité,
  • documentée,
  • et testable. À défaut, elle est réputée inexistante.
  • Toute requête émise hors de ce périmètre normatif est refusée comme non autorisée.

Consultabilité de l’état et des parts

Les règles suivantes sont normatives, déterministes et testables :

  • Pour toute session en cours ou terminale, le service doit fournir :
  • l’état courant de la session,
  • la liste exhaustive des parts validées (numéros de part).

  • Cette liste fait foi pour déterminer les parts déjà reçues et validées.

  • Un client peut reprendre un upload sans ré-uploader les parts déjà validées en s’appuyant sur cette liste.

  • L’exploitation de cette capacité de reprise côté client relève de la politique applicative, mais la capacité serveur à permettre une reprise sans re-upload est obligatoire.

  • Toute re-soumission d’une part déjà validée suit les règles d’idempotence strictes définies par la spécification.

5. Flux nominaux

Flux N1 — Initialiser un upload multipart

  1. Le client demande l’ouverture d’une session d’upload pour un objet cible (nom logique, type MIME, taille attendue si connue).
  2. Le service valide l’autorisation et les limites applicatives.
  3. Le service crée une session d’upload et retourne :
  4. un identifiant de session,
  5. les paramètres nécessaires à l’upload des parts (ex. contraintes de numérotation, taille minimale de part si applicable),
  6. une date/heure d’expiration de la session.

Flux N2 — Uploader une part (streaming)

  1. Le client envoie une part n (numéro de part) associée à une session.
  2. Le service lit la requête en streaming.
  3. Le service transfère la part vers OVH S3, sans matérialiser l’intégralité du fichier en mémoire.
  4. Le service met à jour l’état de session (part reçue, taille, identifiant/ETag S3 si applicable).
  5. Le service renvoie un accusé de réception de part.

Flux N3 — Compléter l’upload

  1. Le client demande la complétion de la session.
  2. Le service vérifie :
  3. la session est en état « en cours »,
  4. les parts nécessaires sont présentes conformément aux règles définies,
  5. la session n’est pas expirée.
  6. Le service déclenche l’assemblage multipart côté S3. 3bis. Le service récupère les métadonnées d’intégrité retournées par le stockage (ETag, checksum ou équivalent).
  7. Le service vérifie la cohérence entre l’empreinte applicative calculée et l’intégrité de l’objet stocké. En cas d’incohérence, la complétion échoue explicitement.
  8. Le service retourne :
  9. l’identifiant de l’objet final (clé S3/logique),
  10. la taille finale,
  11. l’empreinte calculée,
  12. l’état final (succès).

Flux N4 — Abandonner un upload

  1. Le client demande l’abandon de la session.
  2. Le service vérifie l’autorisation.
  3. Le service déclenche l’abandon multipart côté S3.
  4. Le service marque la session en état final « abandonnée ».

5bis. Diagrammes

5bis.1 Diagramme d’états — Session d’upload

Les cinq états terminaux et transitoires d’une session d’upload, avec les transitions autorisées. Référence : INV-4 (complétion unique, état terminal), INV-5 (abandon avant complétion), INV-8 (cohérence d’état en cas d’erreur).

stateDiagram-v2
    [*] --> EN_COURS : Initialisation (Flux N1)

    EN_COURS --> EN_COURS : Upload part (Flux N2)\n[INV-11 idempotence]
    EN_COURS --> COMPLETEE : Complétion réussie (Flux N3)\n[INV-4 complétion unique]
    EN_COURS --> ABANDONNEE : Abandon (Flux N4)\n[INV-5 abortable]
    EN_COURS --> ECHOUEE : Erreur S3 / Incohérence intégrité\n[INV-8 cohérence, INV-10 intégrité]
    EN_COURS --> EXPIREE : Expiration session\n[INV-7 règles déterministes]

    COMPLETEE --> [*]
    ABANDONNEE --> [*]
    ECHOUEE --> [*]
    EXPIREE --> [*]

    note right of COMPLETEE : État terminal —\naucune transition possible\n(CA6)
    note right of ABANDONNEE : État terminal —\nne peut plus être complétée\n(CA7)
    note right of EXPIREE : État terminal —\nne peut plus être complétée\n(CA8)

5bis.2 Diagramme de séquence — Upload multipart complet (Flux N1→N3)

Interactions entre le client, le service d’upload et OVH S3, incluant le calcul d’empreinte en streaming. Référence : INV-2 (streaming obligatoire), INV-3 (empreinte sur octets exacts), INV-6 (authentification), INV-10 (vérification intégrité stockage), INV-12 (isolement tenant/propriétaire).

sequenceDiagram
    actor Client
    participant Service as Service Upload
    participant S3 as OVH S3

    Note over Client,S3: Flux N1 — Initialisation [INV-6 auth, INV-12 tenant]
    Client->>Service: POST /uploads (nom, MIME, taille attendue)
    Service->>Service: Vérifier auth + quotas [INV-7]
    Service->>S3: CreateMultipartUpload
    S3-->>Service: uploadId
    Service-->>Client: sessionId, contraintes, expiration

    Note over Client,S3: Flux N2 — Upload parts en streaming [INV-2, INV-3]
    loop Pour chaque part n
        Client->>Service: PUT /uploads/{sessionId}/parts/{n} (stream)
        Service->>Service: Lire stream + alimenter SHA3-256 [INV-3]
        Service->>S3: UploadPart(uploadId, n, stream) [INV-2]
        S3-->>Service: ETag part
        Service-->>Client: Accusé réception (partNumber, ETag)
    end

    Note over Client,S3: Flux N3 — Complétion [INV-4, INV-10]
    Client->>Service: POST /uploads/{sessionId}/complete
    Service->>Service: Vérifier parts présentes + session valide [INV-8]
    Service->>S3: CompleteMultipartUpload(uploadId, parts)
    S3-->>Service: ETag final + checksum
    Service->>Service: Vérifier intégrité cryptographique [INV-10]
    Service->>Service: Finaliser empreinte SHA3-256(hex) [INV-3]
    Service-->>Client: objectKey, taille, empreinte, état=COMPLETEE

5bis.3 Diagramme de séquence — Abandon (Flux N4)

Référence : INV-5 (abortable), INV-6 (authentification), INV-12 (isolement).

sequenceDiagram
    actor Client
    participant Service as Service Upload
    participant S3 as OVH S3

    Client->>Service: DELETE /uploads/{sessionId}
    Service->>Service: Vérifier auth + propriétaire [INV-6, INV-12]
    Service->>Service: Vérifier état != terminal [INV-4]
    Service->>S3: AbortMultipartUpload(uploadId)
    S3-->>Service: OK
    Service->>Service: Marquer session ABANDONNEE [INV-5]
    Service-->>Client: état=ABANDONNEE

6. Cas d’erreur

Chaque cas d’erreur ci-dessous doit retourner un code d’erreur stable, documenté et testable, ainsi qu’un message non sensible.

E1. Non authentifié / non autorisé : requête émise par un utilisateur non authentifié ou n’appartenant pas au tenant propriétaire de la session. - Effet : aucune modification d’état.

E2. Session inconnue : identifiant invalide ou session inexistante. - Effet : aucune modification d’état.

E3. Session expirée : opération sur session après expiration. - Effet : session reste non complétable ; abandon possible si techniquement disponible.

E4. Part invalide : numéro hors plage, doublon non autorisé, ou violation d’une règle de validation normative (taille minimale/maximale de part, nombre maximal de parts). - Effet : la part est rejetée ; l’état de session ne doit pas indiquer part reçue. - Les seuils applicables sont ceux publiés pour le contexte courant, ou à défaut ceux définis en Annexe D.

E5. Erreur S3 : échec lors de l’upload d’une part, de la complétion ou de l’abandon. - Effet : état de session mis à jour pour refléter l’échec ; aucune complétion silencieuse.

E6. Incohérence de complétion : tentative de complétion sans toutes les parts attendues. - Effet : complétion refusée.

E7. Session déjà terminale : tentative d’action sur une session déjà complétée/abandonnée/échouée. - Effet : rejet.

E8. Quota dépassé : dépassement d’un seuil de quota normatif défini pour le contexte applicatif (taille cumulée, nombre d’uploads, débit ou équivalent). - Effet : upload refusé (initialisation ou part). - Les seuils applicables sont ceux publiés pour le contexte courant, ou à défaut ceux définis en Annexe D.

E9. Timeout / interruption réseau côté client : requête partiellement reçue ou interrompue. - Effet : aucune validation partielle ; la requête peut être renvoyée conformément aux règles d’idempotence.

E10. Échec de vérification d’intégrité stockage : incohérence détectée ou mécanisme d’intégrité non conforme aux exigences cryptographiques définies par la spécification. - Effet : session marquée en échec ; objet non référencé comme valide.

7. Critères d’acceptation (testables)

Sécurité / confidentialité

CA1. Aucune réponse d’erreur ne contient d’octets du contenu uploadé. CA2. Les logs et traces applicatives ne contiennent pas de contenu uploadé (uniquement : identifiants, tailles, codes, empreintes). CA3. Toute requête émise hors du périmètre d’isolement (tenant / propriétaire de session) est refusée sans modifier l’état d’une session.

Streaming / performance

CA4. Le service accepte l’upload d’un fichier dont la taille dépasse la RAM disponible du service, sans échec dû à un buffering complet. CA5. Lorsque le protocole utilisé pour l’upload permet la transmission du corps de requête sans longueur totale connue à l’avance (ex. streaming / chunked), le service accepte l’upload sans exiger de Content-Length.

 Lorsque le protocole utilisé impose la fourniture d’une longueur totale, l’exigence de Content-Length relève de ce protocole et n’est pas contrôlée par le service.

Multipart / robustesse

CA6. Une session d’upload ne peut être complétée qu’une seule fois ; toute tentative ultérieure retourne un état terminal cohérent. CA7. Une session abortée ne peut plus être complétée. CA8. Une session expirée ne peut plus être complétée.

Empreinte (hash)

CA9. L’empreinte retournée à la complétion est égale à SHA3-256 (hex) calculée sur la concaténation canonique des octets du fichier final reconstruit. CA10. À contenu binaire identique, l’empreinte est strictement identique ; à contenu différent, la probabilité de collision est négligeable au regard des propriétés cryptographiques de SHA3-256.

Traçabilité minimale

CA11. Pour chaque session, il existe un état consultable (au minimum : EN_COURS / COMPLETEE / ABANDONNEE / ECHOUEE / EXPIREE) et une liste consultable des parts validées.

CA12. Pour un contexte donné (tenant, plan, configuration active), les règles de validation et de quota applicables sont celles publiées pour le contexte courant et restent inchangées pour toute requête identique, garantissant un comportement déterministe.

CA13. À la complétion, l’objet final n’est considéré valide que si une vérification d’intégrité cryptographiquement robuste a réussi entre le contenu hashé par le service et l’objet effectivement stocké côté S3.

CA14. La répétition d’une même requête (retry), dans un même contexte et avec les mêmes paramètres, conduit toujours à un résultat identique sans effet de bord observable.

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

S1 — Upload nominal complet

Given un utilisateur authentifié avec quota suffisant When il initialise une session, upload 3 parts valides, puis complète Then la session est en état COMPLETEE, l’objet final existe côté S3, et une empreinte est retournée.

S2 — Upload d’une part en streaming (grand fichier)

Given un fichier de taille > RAM du service When le client upload une part en flux continu Then l’upload réussit sans erreur d’allocation mémoire et la part est marquée reçue.

S3 — Part invalide (doublon)

Given une session en cours avec la part #2 déjà reçue When le client renvoie la part #2 Then le service retourne une erreur Part invalide (doublon) et l’état ne change pas.

S4 — Complétion sans toutes les parts

Given une session en cours avec parts #1 et #3 reçues mais #2 manquante When le client demande la complétion Then la complétion est refusée avec l’erreur Incohérence de complétion.

S5 — Abandon

Given une session en cours avec au moins une part reçue When le client demande l’abandon Then la session passe à ABANDONNEE et ne peut plus être complétée.

S6 — Accès non autorisé

Given une session appartenant à un autre utilisateur/tenant When un utilisateur authentifié mais non autorisé tente d’uploader une part Then la requête est refusée et aucune donnée n’est écrite.

S7 — Expiration

Given une session en cours arrivée à expiration When le client tente une complétion Then la complétion est refusée avec l’erreur Session expirée.

S8 — Cohérence de l’empreinte

Given un fichier F When F est uploadé en multipart (parts quelconques) et complété Then l’empreinte retournée est égale à SHA3-256(hex) calculée indépendamment sur F.

9. Hypothèses explicites

H1. Le stockage cible est OVH Object Storage S3-compatible. H2. Le besoin inclut explicitement multipart et streaming. H3. Le calcul d’empreinte est requis « pendant upload » et peut être implémenté de manière incrémentale.

10. Points à clarifier

  1. Politique d’idempotence avancée (au-delà des règles normatives) : clés d’idempotence applicatives, corrélation de requêtes.
  2. Multi-tenant avancé : extensions possibles du modèle d’isolement (rôles, délégations, partage contrôlé de session).
  3. Modalités de consultation des paramètres de validation et de quota à des fins d’audit (API, documentation, export).
  4. Le mécanisme exact de vérification d’intégrité S3 (checksum natif, recalcul applicatif, etc.) est défini par environnement, sous réserve de respecter les exigences cryptographiques minimales définies par la présente spécification.
  5. Les protocoles d’upload effectivement supportés (HTTP/1.1 chunked, HTTP/2, SDK présigné, etc.) et leurs contraintes associées relèvent de la politique technique et doivent être documentés par environnement.