Cybersecurity-Projects/PROJECTS/intermediate/dlp-scanner/src/dlp_scanner/models.py

113 lines
2.9 KiB
Python

"""
©AngelaMos | 2026
models.py
"""
import uuid
from dataclasses import dataclass, field
from datetime import datetime, UTC
from dlp_scanner.constants import Severity
@dataclass(frozen = True, slots = True)
class Location:
"""
Where a finding was detected
"""
source_type: str
uri: str
line: int | None = None
column: int | None = None
byte_offset: int | None = None
table_name: str | None = None
column_name: str | None = None
sheet_name: str | None = None
@dataclass(slots = True)
class Finding:
"""
A fully scored and classified detection result
"""
finding_id: str = field(
default_factory = lambda: uuid.uuid4().hex[: 12]
)
rule_id: str = ""
rule_name: str = ""
severity: Severity = "low"
confidence: float = 0.0
location: Location = field(
default_factory = lambda: Location(
source_type = "unknown",
uri = "",)
)
redacted_snippet: str = ""
compliance_frameworks: list[str] = field(default_factory = list)
remediation: str = ""
detected_at: datetime = field(
default_factory = lambda: datetime.now(UTC)
)
@dataclass(slots = True)
class ScanResult:
"""
Aggregated results from a complete scan run
"""
scan_id: str = field(default_factory = lambda: uuid.uuid4().hex[: 16])
tool_version: str = "0.1.0"
scan_started_at: datetime = field(
default_factory = lambda: datetime.now(UTC)
)
scan_completed_at: datetime | None = None
targets_scanned: int = 0
findings: list[Finding] = field(default_factory = list)
errors: list[str] = field(default_factory = list)
@property
def findings_by_severity(self) -> dict[str, int]:
"""
Count findings grouped by severity level
"""
counts: dict[str,
int] = {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
}
for f in self.findings:
counts[f.severity] = counts.get(f.severity, 0) + 1
return counts
@property
def findings_by_rule(self) -> dict[str, int]:
"""
Count findings grouped by rule ID
"""
counts: dict[str, int] = {}
for f in self.findings:
counts[f.rule_id] = counts.get(f.rule_id, 0) + 1
return counts
@property
def findings_by_framework(self) -> dict[str, int]:
"""
Count findings grouped by compliance framework
"""
counts: dict[str, int] = {}
for f in self.findings:
for fw in f.compliance_frameworks:
counts[fw] = counts.get(fw, 0) + 1
return counts
@dataclass(frozen = True, slots = True)
class TextChunk:
"""
A piece of extracted text with its source location
"""
text: str
location: Location