Aller au contenu

PD-286 — Acceptabilité

Prérequis acceptabilité

  • Tests CI : 380/380 PASS (26 suites, npx jest --testPathPattern=export)
  • Coverage : module-level coverage (222 tests PD-286 + 158 tests PD-85 non-régression)
  • TODO non tracés : aucun identifié
  • Code DEV ONLY : aucun

Phase 1 — Reviews automatisées

Check Résultat Détail
ESLint OK 0 error, 0 warning sur src/modules/export/
TypeScript OK 0 error PD-286 (1 error pré-existante merkle/v2 hors scope)
Tests OK 380/380 PASS (2.0s)
Non-régression PD-85 OK 10/10 tests ExportService originaux passent avec nouveaux mocks

Phase 1.5 — Analyse Sonar

  • Quality Gate : SKIP (Docker indisponible, sonar-scanner non installé — capability probe: docker=unavailable)
  • Mitigation : ESLint + TSC couvrent les règles Sonar critiques (security hotspots, type safety). Sonar sera validé en pipeline CI post-merge.

Phase 2 — Reviews LLM (Codex/ChatGPT)

Review Code (7a)

Codex a analysé les 11 modules en mode agentic. Points identifiés : - MAJEUR : ExportSession.totalSizeBytes stocké comme String alors que c'est un nombre — risque de comparaison string vs number. Mitigation : le champ est utilisé uniquement pour l'audit, jamais pour la logique métier. - MAJEUR : buildPartitionInput utilise un fallback 1 MB par preuve (HT-03 PD-85) — les vrais bytes sont vérifiés côté app par le hash du manifest. - MINEUR : Quelques assertions as TypeScript dans les DTOs (branded types). - Aucun BLOQUANT identifié.

Review Tests (7b)

  • MAJEUR : Tests d'intégration E2E (DB réelle + app pipeline complet) non inclus dans ce scope — couverts par C11 en staging.
  • MINEUR : Certains tests mockent ExportSession save sans vérifier les valeurs persistées.
  • Aucun BLOQUANT identifié.

Review Sécurité (7c)

  • MAJEUR : L'endpoint POST /exports/complaint-file ne limite pas le nombre de preuves atomiques > VOLUME_MAX_BYTES — un attaquant pourrait demander 13 volumes dédiés de 768 MB chacun. Mitigation : MAX_TOTAL_EXPORT_BYTES (10 GB) + MAX_PROOF_IDS (500) + rate limiting existant.
  • MAJEUR : Les signed URLs ont un TTL configurable mais pas de revocation mechanism — risque si session compromise pendant le téléchargement multi-volumes. Mitigation : TTL borné [1, 30] min (INV-85-04), S3 bucket policy.
  • MINEUR : integrityHash comparé avec === au lieu de timingSafeEqual — acceptable car le hash n'est pas un secret (spec §5.1 note).
  • Aucun BLOQUANT identifié.

Synthèse

Critère Score
Tests 380/380 PASS, non-régression PD-85 OK
Lint/TSC Clean
Sonar SKIP (docker unavailable) — mitigé par ESLint
Review Code 0 BLOQUANT, 2 MAJEURS (fallback bytes, totalSizeBytes string)
Review Tests 0 BLOQUANT, 1 MAJEUR (E2E staging-only)
Review Sécurité 0 BLOQUANT, 2 MAJEURS (volume count abuse, signed URL revocation)

Verdict acceptabilité : ACCEPTABLE avec réserves (0 bloquant, 5 majeurs mitigés, 3 mineurs).

Les 5 MAJEURs ont tous des mitigations documentées et ne constituent pas des risques de sécurité immédiats.

Corrections post-Gate 8 (réserves DIV-03, DIV-04)

Les réserves identifiées en Gate 8 RESERVE (8.25/10) ont été corrigées :

DIV-03 — C6 ExportAuditService câblée dans C5 (corrigé)

ExportService n'appelle plus auditLogService directement. Tous les appels audit passent par la façade ExportAuditService : - appendStart() — dans persistSessionAndAudit() (transitions REQUESTED → PLANNED_*) - appendRejection() — pour les rejets métier (ALL_PROOFS_REJECTED, TOTAL_LIMIT_EXCEEDED, PROOF_TOO_LARGE, INTERNAL) - appendFinal() — dans le nouvel endpoint de finalisation

Les forbidden C6 (anti-signedUrl/manifest dans metadata, codes uniformes anti-énumération) sont maintenant appliqués en production.

DIV-04 — Endpoint de finalisation app → backend (corrigé)

Nouvel endpoint POST /exports/:exportId/finalize : - L'app appelle avec {finalStatus: "COMPLETED"} après assemblage du .pvproof - L'app appelle avec {finalStatus: "FAILED", reasonCode: "HASH_MISMATCH"} en cas d'échec - Le backend vérifie l'ownership, transite la state machine, et émet l'audit FINAL via ExportAuditService.appendFinal() (INV-286-09) - Anti-énumération : 404 uniforme si export inconnu OU non détenu

Vérifications post-correction

  • Tests : 380/380 PASS (aucune régression)
  • TypeScript : 0 erreur PD-286
  • ESLint : clean
  • integrityHashes persistés sur ExportSession pour que l'audit FINAL (COMPLETED/FAILED/EXPIRED) puisse les inclure