"""MitreId — validated MITRE ATT&CK technique identifier. Immutable value object that ensures the identifier follows the ATT&CK format: ``T`` followed by 4 digits, optionally a dot and 3 more digits for sub-techniques (e.g. ``T1059``, ``T1059.001``). """ from __future__ import annotations import re from dataclasses import dataclass _MITRE_ID_RE = re.compile(r"^T\d{4}(\.\d{3})?$") @dataclass(frozen=True, slots=True) class MitreId: """Validated MITRE ATT&CK technique identifier.""" value: str def __post_init__(self) -> None: if not _MITRE_ID_RE.match(self.value): raise ValueError( f"Invalid MITRE ATT&CK ID '{self.value}'. " "Expected format: T1234 or T1234.001" ) @property def is_subtechnique(self) -> bool: return "." in self.value @property def parent_id(self) -> str | None: """Return the parent technique ID (e.g. T1059 for T1059.001).""" if not self.is_subtechnique: return None return self.value.split(".")[0] def __str__(self) -> str: return self.value def __eq__(self, other: object) -> bool: if isinstance(other, MitreId): return self.value == other.value if isinstance(other, str): return self.value == other return NotImplemented def __hash__(self) -> int: return hash(self.value)