"""Phase 11: Knowledge Management schemas — Playbooks + Lessons Learned.""" from datetime import datetime from typing import List, Optional from uuid import UUID from pydantic import BaseModel, ConfigDict, field_validator # ── Constants ───────────────────────────────────────────────────────────────── VALID_PLAYBOOK_TYPES = ["attack", "detect", "investigate", "respond", "hunt"] VALID_SEVERITIES = ["critical", "high", "medium", "low", "info"] VALID_ENTITY_TYPES = ["test", "campaign", "attack_path", "manual"] # ══════════════════════════════════════════════════════════════════════════════ # Playbook schemas # ══════════════════════════════════════════════════════════════════════════════ class PlaybookCreate(BaseModel): technique_id: UUID playbook_type: str title: str content: str = "" tools: List[str] = [] prerequisites: List[str] = [] change_note: Optional[str] = None @field_validator("playbook_type") @classmethod def validate_playbook_type(cls, v: str) -> str: if v not in VALID_PLAYBOOK_TYPES: raise ValueError( f"Invalid playbook_type '{v}'. Must be one of: {VALID_PLAYBOOK_TYPES}" ) return v class PlaybookUpdate(BaseModel): title: Optional[str] = None content: Optional[str] = None tools: Optional[List[str]] = None prerequisites: Optional[List[str]] = None change_note: Optional[str] = None class PlaybookVersionOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: UUID playbook_id: UUID version: int title: str content: str tools: List[str] = [] prerequisites: List[str] = [] changed_by: Optional[UUID] change_note: Optional[str] created_at: datetime class PlaybookOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: UUID technique_id: UUID playbook_type: str title: str content: str version: int tools: List[str] = [] prerequisites: List[str] = [] created_by: Optional[UUID] updated_by: Optional[UUID] created_at: datetime updated_at: datetime is_active: bool # ══════════════════════════════════════════════════════════════════════════════ # Lesson Learned schemas # ══════════════════════════════════════════════════════════════════════════════ class LessonLearnedCreate(BaseModel): title: str what_happened: str root_cause: str fix_applied: Optional[str] = None severity: str = "medium" entity_type: str = "manual" entity_id: Optional[UUID] = None technique_ids: List[str] = [] tags: List[str] = [] @field_validator("severity") @classmethod def validate_severity(cls, v: str) -> str: if v not in VALID_SEVERITIES: raise ValueError( f"Invalid severity '{v}'. Must be one of: {VALID_SEVERITIES}" ) return v @field_validator("entity_type") @classmethod def validate_entity_type(cls, v: str) -> str: if v not in VALID_ENTITY_TYPES: raise ValueError( f"Invalid entity_type '{v}'. Must be one of: {VALID_ENTITY_TYPES}" ) return v class LessonLearnedUpdate(BaseModel): title: Optional[str] = None what_happened: Optional[str] = None root_cause: Optional[str] = None fix_applied: Optional[str] = None severity: Optional[str] = None technique_ids: Optional[List[str]] = None tags: Optional[List[str]] = None @field_validator("severity") @classmethod def validate_severity(cls, v: Optional[str]) -> Optional[str]: if v is not None and v not in VALID_SEVERITIES: raise ValueError( f"Invalid severity '{v}'. Must be one of: {VALID_SEVERITIES}" ) return v class LessonLearnedOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: UUID title: str what_happened: str root_cause: str fix_applied: Optional[str] severity: str entity_type: str entity_id: Optional[UUID] technique_ids: List[str] = [] tags: List[str] = [] created_by: Optional[UUID] created_at: datetime updated_at: datetime is_active: bool