Aller au contenu

PD-82 — Décomposition en tâches agents

Date : 2026-02-17 Branche : feature/PD-82-dual-validation Total tâches : 10


Vue d'ensemble

Phase Tâches Description
Foundation 1-3 Entités, State Machine, Signature Verification
Core Logic 4-6 Service principal, Audit, Scheduler
API & Tests 7-10 Controller, DTOs, Tests

Tâche 1 — Entities + Enums + Module setup

Agent : agent-developer Contract : CC-82-01 Dépendances : Aucune

Fichiers à produire :

src/modules/dual-validation/
├── dual-validation.module.ts
├── entities/
│   ├── dual-validation-request.entity.ts
│   └── validation-record.entity.ts
└── enums/
    ├── validation-state.enum.ts
    └── validation-event-type.enum.ts

Invariants couverts : INV-82-06, INV-82-07, INV-82-09, INV-82-10 CA couverts : CA-82-04, CA-82-05

Contraintes : - Schema vault_secure - Timestamps precision 3 (ms) - Signature as bytea (Buffer) - eIDAS level: substantial | high only - tsr_blob: bytea pour preuve RFC 3161 (amélioration Gate 5)


Tâche 2 — State Machine Service

Agent : agent-developer Contract : CC-82-02 Dépendances : Tâche 1 (enums)

Fichiers à produire :

src/modules/dual-validation/services/
└── dual-validation-state-machine.service.ts

Invariants couverts : INV-82-01, INV-82-02, INV-82-03, INV-82-04, INV-82-08 CA couverts : CA-82-01, CA-82-02, CA-82-03, CA-82-06, CA-82-10

Contraintes : - ACTIVATED only with 2 valid, non-revoked validations - No implicit transitions (no auto-approve) - TTL = 168 hours UTC from firstValidationAt - Terminal states: ACTIVATED, REJECTED, EXPIRED (no outbound) - Order agnostic: parent/authority symmetric

State transitions :

PENDING_BOTH → PENDING_AUTHORITY (parent validates)
PENDING_BOTH → PENDING_PARENT (authority validates)
PENDING_AUTHORITY → ACTIVATED (authority validates)
PENDING_PARENT → ACTIVATED (parent validates)
PENDING_* → REJECTED (revocation)
PENDING_* → EXPIRED (TTL exceeded)


Tâche 3 — Signature Verification Service

Agent : agent-developer Contract : CC-82-04 Dépendances : Tâche 1 (entities)

Fichiers à produire :

src/modules/dual-validation/services/
├── signature-verification.service.ts
└── tsa-client.service.ts  # Amélioration Gate 5

Invariants couverts : INV-82-09, INV-82-10 CA couverts : CA-82-04, CA-82-05

Contraintes : - Verify signature against certificate public key - Validate X.509v3 certificate chain (root CA trusted) - Check eIDAS level >= substantial - Reject expired/revoked certificates (OCSP with 1h cache, fallback CRL) - Log verification failures to audit - TSA client for RFC 3161 timestamp requests


Tâche 4 — Dual Validation Service

Agent : agent-developer Contract : CC-82-03 Dépendances : Tâches 1, 2, 3

Fichiers à produire :

src/modules/dual-validation/services/
└── dual-validation.service.ts
src/modules/dual-validation/interfaces/
├── dual-validation.interfaces.ts
└── validation-event.interfaces.ts

Invariants couverts : INV-82-01, INV-82-05, INV-82-11, INV-82-12 CA couverts : CA-82-01, CA-82-07, CA-82-08, CA-82-09

Contraintes : - activatePRE(delegationId) called only when state === ACTIVATED - activatePRE called exactly once per request (idempotency check) - All events logged via AuthAuditWriterService - Platform cannot bypass validation requirement - Authority resolved from internal registry (never from user input)

Methods :

createRequest(params): Promise<DualValidationRequest>
submitValidation(params): Promise<ValidationResult>
revokeValidation(params): Promise<RevocationResult>
getRequestStatus(requestId): Promise<RequestStatusDto>


Tâche 5 — Audit Log Integration

Agent : agent-developer Contract : CC-82-05 Dépendances : Tâche 4

Fichiers à modifier :

src/modules/auth-audit/interfaces/auth-audit.interfaces.ts  # Add event types
src/modules/dual-validation/services/dual-validation.service.ts  # Audit calls

Invariants couverts : INV-82-12 CA couverts : CA-82-08, CA-82-09

Contraintes : - Every state transition logged append-only - Invalid attempts logged with reason - Activation event references both validation IDs - Hash chain integrity (via PD-31)

Event types to add : - DVAL_REQUEST_CREATED - DVAL_PARENT_VALIDATED - DVAL_AUTHORITY_VALIDATED - DVAL_VALIDATION_REVOKED - DVAL_REQUEST_ACTIVATED - DVAL_REQUEST_EXPIRED - DVAL_INVALID_ATTEMPT


Tâche 6 — TTL Expiration Scheduler

Agent : agent-developer Contract : CC-82-07 Dépendances : Tâches 1, 4, 5

Fichiers à produire :

src/modules/dual-validation/schedulers/
└── expiration.scheduler.ts

Invariants couverts : INV-82-02, INV-82-03 CA couverts : CA-82-03

Contraintes : - Cron job runs every 5 minutes - Transitions PENDING_* to EXPIRED if now > expiresAt - No implicit validation (explicit expiration only) - Logs expiration events via audit


Tâche 7 — Controller + DTOs + Guards

Agent : agent-developer Contract : CC-82-06 Dépendances : Tâche 4

Fichiers à produire :

src/modules/dual-validation/
├── controllers/
│   └── dual-validation.controller.ts
├── dto/
│   ├── create-validation-request.dto.ts
│   ├── submit-validation.dto.ts
│   ├── revoke-validation.dto.ts
│   └── validation-response.dto.ts
├── guards/
│   └── validator-identity.guard.ts
└── decorators/
    └── validator-role.decorator.ts

Invariants couverts : INV-82-05, INV-82-07 CA couverts : CA-82-07

Endpoints : - POST /dual-validation/requests - create request - POST /dual-validation/requests/:id/validations - submit validation - DELETE /dual-validation/validations/:id - revoke own validation - GET /dual-validation/requests/:id - status

Contraintes : - Guard ensures validator identity matches JWT token - Authority ID never from user input - class-validator decorators for all DTOs


Tâche 8 — Unit Tests (State Machine + Service)

Agent : agent-qa-unit Contract : CC-82-08 Dépendances : Tâches 1-6

Fichiers à produire :

src/modules/dual-validation/__tests__/
├── state-machine.spec.ts
└── dual-validation.service.spec.ts

CA couverts : CA-82-01, CA-82-02, CA-82-03, CA-82-06, CA-82-10

Tests nominaux : - TC-NOM-01: Single validation does not activate - TC-NOM-02: Parent→Authority activation succeeds - TC-NOM-03: Authority→Parent activation succeeds - TC-NOM-04: Probatory trail complete after activation

Tests erreurs : - TC-ERR-01: Activation attempt with single validation → rejected - TC-ERR-02: Validation after TTL expiry → EXPIRED - TC-ERR-03: Revocation by non-author → rejected - TC-ERR-04: Revocation after ACTIVATED → rejected

Tests TTL boundary (amélioration Gate 5) : - TC-TTL-01: Validation at 167h59m → accepted - TC-TTL-02: Validation at 168h01m → rejected


Tâche 9 — Integration Tests (PD-41, PD-31)

Agent : agent-qa-unit Contract : CC-82-08 Dépendances : Tâches 1-7

Fichiers à produire :

src/modules/dual-validation/__tests__/
└── dual-validation.integration.spec.ts

CA couverts : CA-82-08, CA-82-09

Tests : - TC-INT-01: activatePRE called exactly once after 2 validations - TC-INT-02: Audit events written for each transition - TC-INT-03: Hash chain integrity maintained - TC-INT-04: Activation event references both validation IDs

Mocks : - PreService.activatePRE (PD-41) - AuthAuditWriterService.write (PD-31)


Tâche 10 — E2E Tests (API endpoints)

Agent : agent-qa-unit Contract : CC-82-08 Dépendances : Tâches 1-7

Fichiers à produire :

src/modules/dual-validation/__tests__/e2e/
└── dual-validation.e2e-spec.ts

CA couverts : CA-82-07, CA-82-04, CA-82-05

Tests : - TC-E2E-01: Full flow parent→authority via HTTP - TC-E2E-02: Full flow authority→parent via HTTP - TC-E2E-03: Revocation via DELETE endpoint - TC-E2E-04: Unauthorized access rejected - TC-E2E-05: Invalid signature rejected


Migration SQL

À exécuter après Tâche 1 :

-- File: migrations/XXXXXX-create-dual-validation-tables.ts
CREATE SCHEMA IF NOT EXISTS vault_secure;

CREATE TABLE vault_secure.dual_validation_request (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  delegation_id UUID NOT NULL UNIQUE,
  minor_vault_id UUID NOT NULL,
  parent_user_id UUID NOT NULL,
  authority_id UUID,
  state VARCHAR(20) NOT NULL DEFAULT 'PENDING_BOTH',
  created_at TIMESTAMPTZ(3) NOT NULL DEFAULT NOW(),
  first_validation_at TIMESTAMPTZ(3),
  activated_at TIMESTAMPTZ(3),
  expires_at TIMESTAMPTZ(3),
  CONSTRAINT chk_state CHECK (state IN (
    'PENDING_BOTH', 'PENDING_AUTHORITY', 'PENDING_PARENT',
    'ACTIVATED', 'REJECTED', 'EXPIRED'
  ))
);

CREATE TABLE vault_secure.validation_record (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  request_id UUID NOT NULL REFERENCES vault_secure.dual_validation_request(id),
  validator_type VARCHAR(20) NOT NULL,
  validator_id UUID NOT NULL,
  validated_at TIMESTAMPTZ(3) NOT NULL,
  signature BYTEA NOT NULL,
  signature_algorithm VARCHAR(32) NOT NULL,
  certificate_chain TEXT NOT NULL,
  eidas_level VARCHAR(20) NOT NULL,
  tsr_blob BYTEA,  -- RFC 3161 timestamp response
  revoked BOOLEAN NOT NULL DEFAULT FALSE,
  revoked_at TIMESTAMPTZ(3),
  event_hash CHAR(64) NOT NULL,
  CONSTRAINT chk_validator_type CHECK (validator_type IN ('PARENT', 'AUTHORITY')),
  CONSTRAINT chk_eidas_level CHECK (eidas_level IN ('substantial', 'high'))
);

CREATE INDEX idx_dval_request_state ON vault_secure.dual_validation_request(state);
CREATE INDEX idx_dval_request_expires ON vault_secure.dual_validation_request(expires_at)
  WHERE state IN ('PENDING_AUTHORITY', 'PENDING_PARENT');
CREATE INDEX idx_validation_request ON vault_secure.validation_record(request_id);

-- Append-only trigger
CREATE OR REPLACE FUNCTION vault_secure.prevent_validation_mutation()
RETURNS TRIGGER AS $$
BEGIN
  IF TG_OP = 'DELETE' THEN
    RAISE EXCEPTION 'DELETE not allowed on validation_record (append-only)';
  END IF;
  IF TG_OP = 'UPDATE' AND OLD.id IS NOT NULL THEN
    IF NEW.signature != OLD.signature OR NEW.certificate_chain != OLD.certificate_chain THEN
      RAISE EXCEPTION 'UPDATE not allowed on immutable fields (append-only)';
    END IF;
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_validation_append_only
BEFORE UPDATE OR DELETE ON vault_secure.validation_record
FOR EACH ROW EXECUTE FUNCTION vault_secure.prevent_validation_mutation();

Ordre d'exécution

Tâche 1 (Entities) ─────┬─── Tâche 2 (State Machine)
                        ├─── Tâche 3 (Signature Verification)
                        └─── Tâche 4 (Service) ───┬─── Tâche 5 (Audit)
                                                  ├─── Tâche 6 (Scheduler)
                                                  └─── Tâche 7 (Controller)
                                                              └─── Tâches 8, 9, 10 (Tests)

Décomposition effectuée le 2026-02-17 Workflow de gouvernance ProbatioVault