ops-mason/src/ops_mason/audit.py

49 lines
1.2 KiB
Python
Raw Normal View History

"""Metadata-only audit trail for what ops-mason built.
Same invariant as ops-warden's own audit trail (`warden activity`):
object names and plan references only, never secret material.
"""
from __future__ import annotations
import json
from dataclasses import asdict, dataclass
from datetime import UTC, datetime
from pathlib import Path
_DEFAULT_LOG = Path(__file__).resolve().parents[2] / "audit" / "build-log.jsonl"
@dataclass
class BuildRecord:
plan_id: str
plan_path: str
approved_by: str
approved_at: str
objects: dict[str, str]
built_at: str
def record_build(
*,
plan_id: str,
plan_path: str,
approved_by: str,
approved_at: str,
objects: dict[str, str],
log_path: Path | None = None,
) -> BuildRecord:
record = BuildRecord(
plan_id=plan_id,
plan_path=plan_path,
approved_by=approved_by,
approved_at=approved_at,
objects=objects,
built_at=datetime.now(UTC).isoformat(),
)
path = log_path or _DEFAULT_LOG
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("a") as fh:
fh.write(json.dumps(asdict(record)) + "\n")
return record