net-kingdom/local-identity/src/local_identity/audit.py
tegwick d1e5661369
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Report bootstrap audit failures and track cadence adoption work
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
2026-10-03 22:42:57 +02:00

46 lines
1.4 KiB
Python

"""
Append-only audit log for local-identity.
All CLI commands and OIDC server events write one entry per operation to
~/.local-identity/audit.log (mode 600).
Format (TSV): ISO-timestamp command username outcome
Example:
2026-03-02T00:00:00Z init alice ok
2026-03-02T00:01:00Z serve/auth alice auth_request
2026-03-02T00:01:01Z serve/token alice token_issued
I/O failures emit a fixed diagnostic without event contents or exception
details. The audit log never interrupts the primary operation; emission may
still be incomplete.
"""
import datetime
import logging
import os
from pathlib import Path
from .store import _store_dir
logger = logging.getLogger(__name__)
def _audit_log_path() -> Path:
return _store_dir() / "audit.log"
def log_event(command: str, username: str | None, outcome: str) -> None:
"""Append one audit entry; report I/O failure without exposing event data."""
timestamp = datetime.datetime.now(datetime.timezone.utc).strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
entry = f"{timestamp}\t{command}\t{username or '-'}\t{outcome}\n"
try:
path = _audit_log_path()
is_new = not path.exists()
with open(path, "a", encoding="utf-8") as fh:
fh.write(entry)
if is_new:
os.chmod(path, 0o600)
except OSError:
logger.warning("local-identity audit write failed; evidence may be incomplete")