""" ISMS Audit Execution (Findings, CAPA, Reviews, Internal Audit, Readiness) Pydantic schemas — extracted from compliance/api/schemas.py. Phase 1 Step 3: the monolithic ``compliance.api.schemas`` module is being split per domain under ``compliance.schemas``. This module is re-exported from ``compliance.api.schemas`` for backwards compatibility. """ from datetime import datetime, date from typing import Optional, List, Any, Dict from pydantic import BaseModel, ConfigDict, Field from compliance.schemas.common import ( PaginationMeta, RegulationType, ControlType, ControlDomain, ControlStatus, RiskLevel, EvidenceStatus, ) class AuditFindingBase(BaseModel): """Base schema for Audit Finding.""" finding_type: str # "major", "minor", "ofi", "positive" iso_chapter: Optional[str] = None annex_a_control: Optional[str] = None title: str description: str objective_evidence: str impact_description: Optional[str] = None affected_processes: Optional[List[str]] = None affected_assets: Optional[List[str]] = None owner: Optional[str] = None due_date: Optional[date] = None class AuditFindingCreate(AuditFindingBase): """Schema for creating Audit Finding.""" audit_session_id: Optional[str] = None internal_audit_id: Optional[str] = None auditor: str class AuditFindingUpdate(BaseModel): """Schema for updating Audit Finding.""" title: Optional[str] = None description: Optional[str] = None root_cause: Optional[str] = None root_cause_method: Optional[str] = None owner: Optional[str] = None due_date: Optional[date] = None status: Optional[str] = None class AuditFindingResponse(AuditFindingBase): """Response schema for Audit Finding.""" id: str finding_id: str audit_session_id: Optional[str] = None internal_audit_id: Optional[str] = None root_cause: Optional[str] = None root_cause_method: Optional[str] = None status: str auditor: Optional[str] = None identified_date: date closed_date: Optional[date] = None verification_method: Optional[str] = None verified_by: Optional[str] = None verified_at: Optional[datetime] = None closure_notes: Optional[str] = None closed_by: Optional[str] = None is_blocking: bool created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class AuditFindingListResponse(BaseModel): """List response for Audit Findings.""" findings: List[AuditFindingResponse] total: int major_count: int minor_count: int ofi_count: int open_count: int class AuditFindingCloseRequest(BaseModel): """Request to close an Audit Finding.""" closure_notes: str closed_by: str verification_method: str verification_evidence: str # --- Corrective Actions (CAPA) --- class CorrectiveActionBase(BaseModel): """Base schema for Corrective Action.""" capa_type: str # "corrective", "preventive", "both" title: str description: str expected_outcome: Optional[str] = None assigned_to: str planned_completion: date effectiveness_criteria: Optional[str] = None estimated_effort_hours: Optional[int] = None resources_required: Optional[str] = None class CorrectiveActionCreate(CorrectiveActionBase): """Schema for creating Corrective Action.""" finding_id: str planned_start: Optional[date] = None class CorrectiveActionUpdate(BaseModel): """Schema for updating Corrective Action.""" title: Optional[str] = None description: Optional[str] = None assigned_to: Optional[str] = None planned_completion: Optional[date] = None status: Optional[str] = None progress_percentage: Optional[int] = None implementation_evidence: Optional[str] = None class CorrectiveActionResponse(CorrectiveActionBase): """Response schema for Corrective Action.""" id: str capa_id: str finding_id: str planned_start: Optional[date] = None actual_completion: Optional[date] = None status: str progress_percentage: int approved_by: Optional[str] = None actual_effort_hours: Optional[int] = None implementation_evidence: Optional[str] = None evidence_ids: Optional[List[str]] = None effectiveness_verified: bool effectiveness_verification_date: Optional[date] = None effectiveness_notes: Optional[str] = None created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class CorrectiveActionListResponse(BaseModel): """List response for Corrective Actions.""" actions: List[CorrectiveActionResponse] total: int class CAPAVerifyRequest(BaseModel): """Request to verify CAPA effectiveness.""" verified_by: str effectiveness_notes: str is_effective: bool # --- Management Review (ISO 27001 9.3) --- class ReviewAttendee(BaseModel): """Single attendee in management review.""" name: str role: str class ReviewActionItem(BaseModel): """Single action item from management review.""" action: str owner: str due_date: date class ManagementReviewBase(BaseModel): """Base schema for Management Review.""" title: str review_date: date review_period_start: Optional[date] = None review_period_end: Optional[date] = None chairperson: str attendees: Optional[List[ReviewAttendee]] = None class ManagementReviewCreate(ManagementReviewBase): """Schema for creating Management Review.""" pass class ManagementReviewUpdate(BaseModel): """Schema for updating Management Review.""" # Inputs (9.3) input_previous_actions: Optional[str] = None input_isms_changes: Optional[str] = None input_security_performance: Optional[str] = None input_interested_party_feedback: Optional[str] = None input_risk_assessment_results: Optional[str] = None input_improvement_opportunities: Optional[str] = None input_policy_effectiveness: Optional[str] = None input_objective_achievement: Optional[str] = None input_resource_adequacy: Optional[str] = None # Outputs (9.3) output_improvement_decisions: Optional[str] = None output_isms_changes: Optional[str] = None output_resource_needs: Optional[str] = None # Action items action_items: Optional[List[ReviewActionItem]] = None # Assessment isms_effectiveness_rating: Optional[str] = None key_decisions: Optional[str] = None status: Optional[str] = None class ManagementReviewResponse(ManagementReviewBase): """Response schema for Management Review.""" id: str review_id: str input_previous_actions: Optional[str] = None input_isms_changes: Optional[str] = None input_security_performance: Optional[str] = None input_interested_party_feedback: Optional[str] = None input_risk_assessment_results: Optional[str] = None input_improvement_opportunities: Optional[str] = None input_policy_effectiveness: Optional[str] = None input_objective_achievement: Optional[str] = None input_resource_adequacy: Optional[str] = None output_improvement_decisions: Optional[str] = None output_isms_changes: Optional[str] = None output_resource_needs: Optional[str] = None action_items: Optional[List[ReviewActionItem]] = None isms_effectiveness_rating: Optional[str] = None key_decisions: Optional[str] = None status: str approved_by: Optional[str] = None approved_at: Optional[datetime] = None minutes_document_path: Optional[str] = None next_review_date: Optional[date] = None created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class ManagementReviewListResponse(BaseModel): """List response for Management Reviews.""" reviews: List[ManagementReviewResponse] total: int class ManagementReviewApproveRequest(BaseModel): """Request to approve Management Review.""" approved_by: str next_review_date: date minutes_document_path: Optional[str] = None # --- Internal Audit (ISO 27001 9.2) --- class InternalAuditBase(BaseModel): """Base schema for Internal Audit.""" title: str audit_type: str # "scheduled", "surveillance", "special" scope_description: str iso_chapters_covered: Optional[List[str]] = None annex_a_controls_covered: Optional[List[str]] = None processes_covered: Optional[List[str]] = None departments_covered: Optional[List[str]] = None criteria: Optional[str] = None planned_date: date lead_auditor: str audit_team: Optional[List[str]] = None class InternalAuditCreate(InternalAuditBase): """Schema for creating Internal Audit.""" pass class InternalAuditUpdate(BaseModel): """Schema for updating Internal Audit.""" title: Optional[str] = None scope_description: Optional[str] = None actual_start_date: Optional[date] = None actual_end_date: Optional[date] = None auditee_representatives: Optional[List[str]] = None status: Optional[str] = None audit_conclusion: Optional[str] = None overall_assessment: Optional[str] = None class InternalAuditResponse(InternalAuditBase): """Response schema for Internal Audit.""" id: str audit_id: str actual_start_date: Optional[date] = None actual_end_date: Optional[date] = None auditee_representatives: Optional[List[str]] = None status: str total_findings: int major_findings: int minor_findings: int ofi_count: int positive_observations: int audit_conclusion: Optional[str] = None overall_assessment: Optional[str] = None report_date: Optional[date] = None report_document_path: Optional[str] = None report_approved_by: Optional[str] = None report_approved_at: Optional[datetime] = None follow_up_audit_required: bool created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class InternalAuditListResponse(BaseModel): """List response for Internal Audits.""" audits: List[InternalAuditResponse] total: int class InternalAuditCompleteRequest(BaseModel): """Request to complete Internal Audit.""" audit_conclusion: str overall_assessment: str # "conforming", "minor_nc", "major_nc" follow_up_audit_required: bool # --- ISMS Readiness Check --- class PotentialFinding(BaseModel): """Potential finding from readiness check.""" check: str status: str # "pass", "fail", "warning" recommendation: str iso_reference: Optional[str] = None class ISMSReadinessCheckResponse(BaseModel): """Response for ISMS Readiness Check.""" id: str check_date: datetime triggered_by: Optional[str] = None overall_status: str # "ready", "at_risk", "not_ready" certification_possible: bool # Chapter statuses chapter_4_status: Optional[str] = None chapter_5_status: Optional[str] = None chapter_6_status: Optional[str] = None chapter_7_status: Optional[str] = None chapter_8_status: Optional[str] = None chapter_9_status: Optional[str] = None chapter_10_status: Optional[str] = None # Findings potential_majors: List[PotentialFinding] potential_minors: List[PotentialFinding] improvement_opportunities: List[PotentialFinding] # Scores readiness_score: float documentation_score: Optional[float] = None implementation_score: Optional[float] = None evidence_score: Optional[float] = None # Priority actions priority_actions: List[str] model_config = ConfigDict(from_attributes=True) class ISMSReadinessCheckRequest(BaseModel): """Request to run ISMS Readiness Check.""" triggered_by: str = "manual" # --- Audit Trail --- class AuditTrailEntry(BaseModel): """Single audit trail entry.""" id: str entity_type: str entity_id: str entity_name: Optional[str] = None action: str field_changed: Optional[str] = None old_value: Optional[str] = None new_value: Optional[str] = None change_summary: Optional[str] = None performed_by: str performed_at: datetime model_config = ConfigDict(from_attributes=True) class AuditTrailResponse(BaseModel): """Response for Audit Trail query.""" entries: List[AuditTrailEntry] total: int pagination: PaginationMeta # --- ISO 27001 Chapter Status Overview --- class ISO27001ChapterStatus(BaseModel): """Status of a single ISO 27001 chapter.""" chapter: str title: str status: str # "compliant", "partial", "non_compliant", "not_started" completion_percentage: float open_findings: int key_documents: List[str] last_reviewed: Optional[datetime] = None class ISO27001OverviewResponse(BaseModel): """Complete ISO 27001 status overview.""" overall_status: str # "ready", "at_risk", "not_ready", "not_started" certification_readiness: float # 0-100 chapters: List[ISO27001ChapterStatus] scope_approved: bool soa_approved: bool last_management_review: Optional[datetime] = None last_internal_audit: Optional[datetime] = None open_major_findings: int open_minor_findings: int policies_count: int policies_approved: int objectives_count: int objectives_achieved: int