Files
PROJECT-CONTORL/backend/app/models/audit_log.py
beabigegg 0ef78e13ff feat: implement audit trail module
- Backend (FastAPI):
  - AuditLog and AuditAlert models with Alembic migration
  - AuditService with SHA-256 checksum for log integrity
  - AuditMiddleware for request metadata extraction (IP, user_agent)
  - Integrated audit logging into Task, Project, Blocker APIs
  - Query API with filtering, pagination, CSV export
  - Integrity verification endpoint
  - Sensitive operation alerts with acknowledgement

- Frontend (React + Vite):
  - Admin AuditPage with filters and export
  - ResourceHistory component for change tracking
  - Audit service for API calls

- Testing:
  - 15 tests covering service and API endpoints

- OpenSpec:
  - add-audit-trail change archived

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 21:21:18 +08:00

78 lines
2.6 KiB
Python

import uuid
from sqlalchemy import Column, String, Text, DateTime, ForeignKey, Enum, Index, JSON
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from app.core.database import Base
import enum
class AuditAction(str, enum.Enum):
CREATE = "create"
UPDATE = "update"
DELETE = "delete"
RESTORE = "restore"
LOGIN = "login"
LOGOUT = "logout"
class SensitivityLevel(str, enum.Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
# Event type to sensitivity level mapping
EVENT_SENSITIVITY = {
"task.create": SensitivityLevel.LOW,
"task.update": SensitivityLevel.LOW,
"task.delete": SensitivityLevel.MEDIUM,
"task.assign": SensitivityLevel.LOW,
"task.blocker": SensitivityLevel.MEDIUM,
"project.create": SensitivityLevel.MEDIUM,
"project.update": SensitivityLevel.MEDIUM,
"project.delete": SensitivityLevel.HIGH,
"user.login": SensitivityLevel.LOW,
"user.logout": SensitivityLevel.LOW,
"user.permission_change": SensitivityLevel.CRITICAL,
"attachment.upload": SensitivityLevel.LOW,
"attachment.download": SensitivityLevel.LOW,
"attachment.delete": SensitivityLevel.MEDIUM,
}
# Events that should trigger alerts
ALERT_EVENTS = {"project.delete", "user.permission_change"}
class AuditLog(Base):
__tablename__ = "pjctrl_audit_logs"
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
event_type = Column(String(50), nullable=False)
resource_type = Column(String(50), nullable=False)
resource_id = Column(String(36), nullable=True)
user_id = Column(String(36), ForeignKey("pjctrl_users.id", ondelete="SET NULL"), nullable=True)
action = Column(
Enum("create", "update", "delete", "restore", "login", "logout", name="audit_action_enum"),
nullable=False
)
changes = Column(JSON, nullable=True)
request_metadata = Column(JSON, nullable=True)
sensitivity_level = Column(
Enum("low", "medium", "high", "critical", name="sensitivity_level_enum"),
default="low",
nullable=False
)
checksum = Column(String(64), nullable=False)
created_at = Column(DateTime, server_default=func.now(), nullable=False)
# Relationships
user = relationship("User", foreign_keys=[user_id])
alerts = relationship("AuditAlert", back_populates="audit_log", cascade="all, delete-orphan")
__table_args__ = (
Index("idx_audit_user", "user_id", "created_at"),
Index("idx_audit_resource", "resource_type", "resource_id", "created_at"),
Index("idx_audit_time", "created_at"),
)