43 lines
1.1 KiB
Python
43 lines
1.1 KiB
Python
"""GitOps change archive and drift audit engine."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import asdict, dataclass, field
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
|
|
def utc_now() -> str:
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ChangeAuditReport:
|
|
status: str
|
|
workspace_dirty: bool
|
|
missing_metadata: list[str]
|
|
drift_items: list[str]
|
|
checked_at: str = field(default_factory=utc_now)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return asdict(self)
|
|
|
|
|
|
class GitOpsChangeAuditor:
|
|
def audit(
|
|
self,
|
|
workspace_dirty: bool,
|
|
metadata: dict[str, Any],
|
|
baseline_diff: list[str],
|
|
) -> ChangeAuditReport:
|
|
required = ["actor", "timestamp", "reason", "branch", "commit"]
|
|
missing = [key for key in required if not metadata.get(key)]
|
|
drift = list(baseline_diff)
|
|
status = "healthy"
|
|
if workspace_dirty or missing or drift:
|
|
status = "attention_required"
|
|
return ChangeAuditReport(status, workspace_dirty, missing, drift)
|
|
|
|
|
|
__all__ = ["ChangeAuditReport", "GitOpsChangeAuditor"]
|