Coverage for src / lexigram / contracts / admin / audit_entry.py: 100%

22 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-15 18:58 +0800

1"""AuditEntry value object and AuditOutcome enum for admin audit logging.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass, field 

6from enum import Enum 

7from typing import Any 

8 

9 

10class AuditOutcome(str, Enum): 

11 """Categorised outcome of an admin audit event.""" 

12 

13 SUCCESS = "success" 

14 DENIED = "denied" 

15 ERRORED = "errored" 

16 

17 

18@dataclass(frozen=True) 

19class AuditEntry: 

20 """Immutable audit entry representing a single admin audit event. 

21 

22 Captures who did what, to which resource, the outcome, request 

23 context metadata, and optional before/after state snapshots. 

24 

25 Args: 

26 admin_user_id: Identifier of the admin user performing the action. 

27 action: Action name (e.g. 'delete_user', 'update_role'). 

28 resource_type: Type of resource being acted upon. 

29 resource_id: Identifier of the specific resource instance. 

30 outcome: Categorised outcome — success, denied, or errored. 

31 before: Snapshot of resource state before the action. 

32 after: Snapshot of resource state after the action. 

33 correlation_id: Request correlation ID for tracing. 

34 request_id: Original request identifier. 

35 request_ip: Client IP address. 

36 metadata: Arbitrary supplementary metadata. 

37 """ 

38 

39 admin_user_id: str 

40 action: str 

41 resource_type: str 

42 resource_id: str | None 

43 outcome: AuditOutcome | str 

44 before: dict[str, Any] = field(default_factory=dict) 

45 after: dict[str, Any] = field(default_factory=dict) 

46 correlation_id: str | None = None 

47 request_id: str | None = None 

48 request_ip: str | None = None 

49 metadata: dict[str, Any] = field(default_factory=dict) 

50 

51 

52__all__ = [ 

53 "AuditEntry", 

54 "AuditOutcome", 

55]