Purpose
-------
Audit JSONL logger and AI-Trace decorator for Phase 4B ``oct git``
commands. Writes one JSON object per line to
``<project>/logs/git-audit-YYYYMMDD-HHMMSS.jsonl`` with size + count
rotation, and provides the :func:`audited` decorator that every
``oct git`` Click command is wrapped in so that entry/exit trace events
and a persistent audit row are recorded even if the command crashes.
Responsibilities
----------------
- Define :class:`AuditRecord` — the exact on-disk schema (blueprint
§12.2, verbatim).
- Implement :class:`AuditLogger` with size-based rotation (5 MB) and
count-based pruning (keep the 20 newest files).
- Redact credentials from any string value written to the log by
deferring to :func:`oct.core.git._redact_git_url`.
- Emit AI-Trace shadow events via ``_dbg("GIT", msg, 4)`` — file-only,
off by default; see blueprint §12.3 and Phase 4B design decision D7.
Diagnostics
-----------
Domain: GIT
Levels:
L1 — errors: rotation IO failures, directory-create failures
L2 — lifecycle: file rotated, files pruned
L4 — deep trace: every ``write()`` call and every command start/end
Contracts
---------
- This module does not import ``click``, does not shell out, and does
not touch any git state. It only reads config-less arguments passed
in from the caller.
- :meth:`AuditLogger.write` must never raise. On any IO failure it
logs an error via ``_dbg`` and returns silently — the audit log is
*observability*, not a correctness path.
- Filenames follow ``git-audit-YYYYMMDD-HHMMSS.jsonl`` strictly so that
lexical ordering matches chronological ordering for pruning.
- Every ``AuditRecord`` field is JSON-serialisable. ``args`` is always
passed through credential redaction before serialisation.
| Callable[[Callable[..., Any]], Callable[..., Any]] oct.git.audit.audited |
( |
str | cmd_name | ) |
|
Decorator that wraps an ``oct git`` Click command.
Responsibilities:
1. Emit ``_dbg("GIT", "command_start ...", 4)`` before the command.
2. Run the wrapped function.
3. In a ``finally`` block, emit ``_dbg("GIT", "command_end ...", 4)``
and write an :class:`AuditRecord` into the project's audit log.
The wrapped command is responsible for populating
``ctx.obj["_audit_record"]`` during its run — the decorator reads
that slot at the end and writes whatever is there, falling back to
a minimal record (with ``exit_code=None`` and ``checks_passed=False``)
if the command crashed before populating it. This guarantees every
command invocation leaves exactly one audit row.
Parameters
----------
cmd_name
Human-readable command identifier for the trace and audit row,
e.g. ``"oct git check"``.
Definition at line 328 of file audit.py.