72 lines
2.0 KiB
Python
72 lines
2.0 KiB
Python
"""Compliance domain entities with coverage calculation logic.
|
|
|
|
Pure domain logic — no framework imports.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import enum
|
|
import uuid
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
class ControlCoverageStatus(str, enum.Enum):
|
|
covered = "covered"
|
|
partially_covered = "partially_covered"
|
|
not_covered = "not_covered"
|
|
|
|
|
|
@dataclass
|
|
class ComplianceControlEntity:
|
|
control_id: str
|
|
title: str
|
|
id: uuid.UUID | None = None
|
|
description: str | None = None
|
|
category: str | None = None
|
|
technique_statuses: list[str] = field(default_factory=list)
|
|
|
|
@property
|
|
def coverage_status(self) -> ControlCoverageStatus:
|
|
if not self.technique_statuses:
|
|
return ControlCoverageStatus.not_covered
|
|
covered_statuses = {"validated", "partial"}
|
|
covered = [s for s in self.technique_statuses if s in covered_statuses]
|
|
if len(covered) == len(self.technique_statuses):
|
|
return ControlCoverageStatus.covered
|
|
elif len(covered) > 0:
|
|
return ControlCoverageStatus.partially_covered
|
|
return ControlCoverageStatus.not_covered
|
|
|
|
|
|
@dataclass
|
|
class ComplianceFrameworkEntity:
|
|
name: str
|
|
id: uuid.UUID | None = None
|
|
version: str | None = None
|
|
description: str | None = None
|
|
is_active: bool = True
|
|
controls: list[ComplianceControlEntity] = field(default_factory=list)
|
|
|
|
@property
|
|
def total_controls(self) -> int:
|
|
return len(self.controls)
|
|
|
|
@property
|
|
def covered_controls(self) -> int:
|
|
return sum(
|
|
1 for c in self.controls
|
|
if c.coverage_status == ControlCoverageStatus.covered
|
|
)
|
|
|
|
@property
|
|
def coverage_pct(self) -> float:
|
|
if self.total_controls == 0:
|
|
return 0.0
|
|
return round(self.covered_controls / self.total_controls * 100, 1)
|
|
|
|
def get_gap_controls(self) -> list[ComplianceControlEntity]:
|
|
return [
|
|
c for c in self.controls
|
|
if c.coverage_status != ControlCoverageStatus.covered
|
|
]
|