Mechanical rename (package agent_credential_broker; entry points
agent-broker{,-mcp,-plugin}; env AGENT_BROKER_*; paths agent-broker;
agent-browser credential provider 'broker'; MCP server name agent-broker).
New backend 'openbao': stdlib-only HTTP client for OpenBao/Vault KV v2
(approle login or token file/env; metadata-only ref index; lazy re-login
on 401/403; token renewal). bitwarden-cli backend kept as transition.
42 lines
1.2 KiB
Python
42 lines
1.2 KiB
Python
"""Audit logging -- metadata only, never secret material."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import threading
|
|
from datetime import datetime, timezone
|
|
|
|
from .config import audit_log_path
|
|
|
|
_lock = threading.Lock()
|
|
|
|
|
|
def _scrub(record: dict) -> dict:
|
|
return {k: v for k, v in record.items() if v is not None}
|
|
|
|
|
|
def audit(operation: str, *, ref=None, adapter=None, target=None,
|
|
result="ok", error_code=None, detail=None):
|
|
entry = _scrub({
|
|
"ts": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
|
"op": operation,
|
|
"ref": ref,
|
|
"adapter": adapter,
|
|
"target": target,
|
|
"result": result,
|
|
"error": error_code,
|
|
"detail": detail,
|
|
})
|
|
line = json.dumps(entry, sort_keys=True)
|
|
# Belt-and-suspenders: audit lines must never carry secret material.
|
|
for banned in ("password", "secret", "token", "key"):
|
|
if isinstance(detail, str) and banned in detail.lower():
|
|
entry["detail"] = "REDACTED_DETAIL"
|
|
line = json.dumps(_scrub(entry), sort_keys=True)
|
|
break
|
|
try:
|
|
with _lock, open(audit_log_path(), "a") as fh:
|
|
fh.write(line + "\n")
|
|
except OSError:
|
|
pass # audit must never break operations
|