===================================== Authorization — Workflows d'Approbation ===================================== Le système d'approbation permet de soumettre des actions à un processus de validation multi-approbateur avec quorum configurable. Module : ``src.module.authorization.application.approval_service`` .. module:: src.module.authorization.application.approval_service :synopsis: Orchestration des workflows d'approbation Modèles ======= .. class:: ApprovalRequest(models.Model) Demande d'approbation créée quand une politique ABAC a ``requires_approval=True``. .. attribute:: policy_id :type: UUIDField Politique ayant déclenché la demande. .. attribute:: policy_name :type: CharField .. attribute:: requester_id :type: UUIDField Utilisateur ayant initié l'action. .. attribute:: tenant_id :type: UUIDField Fixé à la création — l'auto-exécution utilise ce tenant. .. attribute:: action :type: CharField Action demandée (ex: ``"delete"``). .. attribute:: resource_type :type: CharField .. attribute:: resource_id :type: UUIDField (nullable) .. attribute:: status :type: CharField ``pending`` → ``approved`` / ``rejected`` / ``expired`` / ``cancelled`` .. attribute:: request_data :type: JSONField Contexte au moment de la demande. .. attribute:: approval_config_snapshot :type: JSONField Snapshot de la configuration d'approbation au moment de la création. .. attribute:: required_approvals :type: IntegerField Nombre d'approbations requises (quorum). .. attribute:: current_approvals :type: IntegerField Nombre d'approbations reçues. .. attribute:: expires_at :type: DateTimeField .. class:: ApprovalDecision(models.Model) Décision individuelle d'un approbateur. .. attribute:: approval_request :type: ForeignKey → ApprovalRequest .. attribute:: approver_id :type: UUIDField .. attribute:: decision :type: CharField ``"approved"`` ou ``"rejected"`` .. attribute:: comment :type: TextField (nullable) ApprovalOrchestrationService ============================= .. class:: ApprovalOrchestrationService Orchestre le cycle de vie complet des demandes d'approbation. .. method:: create_request(policy, requester, action, resource_type, resource_id, request_data) -> ApprovalRequest Crée une nouvelle demande d'approbation. Émet ``ApprovalRequested``. .. method:: approve(request_id, approver_id, comment=None) -> ApprovalDecision Enregistre une décision d'approbation. - Vérifie que l'approbateur est autorisé - Vérifie que l'approbateur n'est pas le demandeur (``SelfApprovalError``) - Incrémente ``current_approvals`` - Si quorum atteint → statut ``approved``, émet ``ApprovalGranted`` - Si ``auto_execute=True`` → exécute l'action automatiquement :raises SelfApprovalError: Auto-approbation interdite :raises UnauthorizedApproverError: Approbateur non autorisé :raises ApprovalNotPendingError: Demande déjà résolue .. method:: reject(request_id, approver_id, comment=None) -> ApprovalDecision Rejette une demande. Émet ``ApprovalRejected``. .. method:: cancel(request_id, requester_id) -> None Annule une demande (par le demandeur). Émet ``ApprovalCancelled``. .. method:: expire_pending() -> int Expire les demandes dont ``expires_at`` est passé. Émet ``ApprovalExpired`` pour chaque demande. Retourne le nombre de demandes expirées. Flux d'approbation ================== .. code-block:: text Utilisateur PEP Approval Service │ │ │ ├── DELETE /invoices/123 ────►│ │ │ ├── PDP: requires_approval ──│ │ │ │ │ │◄── ApprovalRequiredError ──┤ │ │ (approval_request_id) │ │ │ │ │◄── 202 Accepted ──────────┤ │ │ {approval_request_id} │ │ │ │ │ │ │ │ Approver │ │ │ │ │ ├── POST /approval-requests//approve/ ───────────────►│ │ │ │ ├── Quorum atteint ? │ │ │ ├── Oui → auto_execute │ │ │ └── Non → attente │ │ │ │ │◄── 200 OK ─────────────────┤ │ Tâches Celery ============= Module : ``src.module.authorization.tasks`` .. function:: execute_approved_action(request_id: str) -> None Exécute l'action approuvée dans le contexte du tenant original. .. function:: expire_pending_approvals() -> None Expire les demandes d'approbation passées. À planifier via Celery Beat. .. function:: send_approval_notification(request_id: str) -> None Envoie une notification aux approbateurs. .. function:: cleanup_expired_approvals() -> None Nettoie les demandes d'approbation anciennes. API REST ======== .. code-block:: text GET /api/v1/approval-requests/ Liste les demandes GET /api/v1/approval-requests// Détail d'une demande POST /api/v1/approval-requests//approve/ Approuver POST /api/v1/approval-requests//reject/ Rejeter POST /api/v1/approval-requests//cancel/ Annuler GET /api/v1/approval-requests/pending/ Demandes en attente Configuration ============= .. code-block:: python MULTITENANT = { 'APPROVAL_ENABLED': True, 'APPROVAL_DEFAULT_EXPIRATION_HOURS': 72, 'APPROVAL_DEFAULT_REQUIRED_APPROVALS': 1, 'APPROVAL_AUTO_EXECUTE_DEFAULT': True, }