""" Credential audit log model for tracking credential access and modifications. This model provides a comprehensive audit trail for all credential-related operations including views, updates, rotations, and decryptions. """ from datetime import datetime from typing import Optional from sqlalchemy import CHAR, CheckConstraint, ForeignKey, Index, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.sql import func from api.models.base import Base, UUIDMixin class CredentialAuditLog(UUIDMixin, Base): """ Audit trail for credential access and modifications. Records all operations performed on credentials including who accessed them, when, from where, and what action was performed. Attributes: id: UUID primary key credential_id: Reference to the credential action: Type of action performed (view, create, update, delete, rotate, decrypt) user_id: User who performed the action (JWT sub claim) ip_address: IP address of the user user_agent: Browser/client user agent details: JSON string with additional context about the action timestamp: When the action was performed """ __tablename__ = "credential_audit_log" # Foreign keys credential_id: Mapped[str] = mapped_column( CHAR(36), ForeignKey("credentials.id", ondelete="CASCADE"), nullable=False, doc="Reference to credential", ) # Action details action: Mapped[str] = mapped_column( String(50), nullable=False, doc="Type of action performed", ) user_id: Mapped[str] = mapped_column( String(255), nullable=False, doc="User who performed the action (JWT sub claim)", ) # Context information ip_address: Mapped[Optional[str]] = mapped_column( String(45), nullable=True, doc="IP address (IPv4 or IPv6)", ) user_agent: Mapped[Optional[str]] = mapped_column( Text, nullable=True, doc="Browser/client user agent string", ) details: Mapped[Optional[str]] = mapped_column( Text, nullable=True, doc="JSON string with additional context (what changed, why, etc.)", ) # Timestamp timestamp: Mapped[datetime] = mapped_column( nullable=False, server_default=func.now(), doc="When the action was performed", ) # Table constraints __table_args__ = ( CheckConstraint( "action IN ('view', 'create', 'update', 'delete', 'rotate', 'decrypt')", name="ck_credential_audit_action", ), Index("idx_cred_audit_credential", "credential_id"), Index("idx_cred_audit_user", "user_id"), Index("idx_cred_audit_timestamp", "timestamp"), ) def __repr__(self) -> str: """String representation of the audit log entry.""" return f""