Option C Tools
Loading...
Searching...
No Matches
oct.git.audit Namespace Reference

Classes

class  AuditRecord
class  AuditLogger

Functions

str _utc_now_iso ()
list[str] _redact_args (list[str]|tuple[str,...]|None argv)
Callable[[Callable[..., Any]], Callable[..., Any]] audited (str cmd_name)
Path _resolve_project_root_from_ctx (Any ctx)

Variables

int AUDIT_MAX_FILES = 20
int AUDIT_MAX_SIZE_BYTES = 5 * 1024 * 1024
str _AUDIT_TS_FORMAT = "%Y%m%d-%H%M%S"
str _AUDIT_FILENAME_PREFIX = "git-audit-"
str _AUDIT_FILENAME_SUFFIX = ".jsonl"
str _AUDIT_GLOB = f"{_AUDIT_FILENAME_PREFIX}*{_AUDIT_FILENAME_SUFFIX}"
str _AUDIT_SUBDIR = "logs"

Detailed Description

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.

Function Documentation

◆ _redact_args()

list[str] oct.git.audit._redact_args ( list[str] | tuple[str, ...] | None argv)
protected
Run each argv element through :func:`_redact_git_url`.

This is defensive: an ``oct git`` command rarely receives a remote
URL as a positional arg, but a user *could* pass one via future
subcommands (e.g. ``oct git init --remote``). Applying the redactor
unconditionally costs a regex match per arg and closes the hole.

Definition at line 141 of file audit.py.

Here is the caller graph for this function:

◆ _resolve_project_root_from_ctx()

Path oct.git.audit._resolve_project_root_from_ctx ( Any ctx)
protected
Best-effort extraction of the project root from a Click context.

Tries, in order:

1. ``ctx.obj["project_root"]`` — the canonical slot set by the
   top-level ``cli`` group (see [oct/oct/cli.py](../cli.py)).
2. ``ctx.obj["root"]`` — older convention used by a couple of
   legacy commands.
3. :func:`oct.core.project_root.get_project_root` — the formal
   resolver, which consults ``--root-dir`` and walks upward.
4. ``Path.cwd()`` as the absolute last resort.

Any exception is swallowed and falls through to the next step so
the decorator never blocks command execution on a resolution error.

Definition at line 406 of file audit.py.

Here is the caller graph for this function:

◆ _utc_now_iso()

str oct.git.audit._utc_now_iso ( )
protected
Return the current UTC time as an ISO 8601 string.

Uses ``datetime.now(timezone.utc)`` rather than ``datetime.utcnow``
(deprecated in 3.12+) and appends a literal ``Z`` so readers can
round-trip the value without timezone ambiguity.

Definition at line 131 of file audit.py.

Here is the caller graph for this function:

◆ audited()

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.

Here is the call graph for this function:

Variable Documentation

◆ _AUDIT_FILENAME_PREFIX

str oct.git.audit._AUDIT_FILENAME_PREFIX = "git-audit-"
protected

Definition at line 81 of file audit.py.

◆ _AUDIT_FILENAME_SUFFIX

str oct.git.audit._AUDIT_FILENAME_SUFFIX = ".jsonl"
protected

Definition at line 82 of file audit.py.

◆ _AUDIT_GLOB

str oct.git.audit._AUDIT_GLOB = f"{_AUDIT_FILENAME_PREFIX}*{_AUDIT_FILENAME_SUFFIX}"
protected

Definition at line 83 of file audit.py.

◆ _AUDIT_SUBDIR

str oct.git.audit._AUDIT_SUBDIR = "logs"
protected

Definition at line 91 of file audit.py.

◆ _AUDIT_TS_FORMAT

str oct.git.audit._AUDIT_TS_FORMAT = "%Y%m%d-%H%M%S"
protected

Definition at line 78 of file audit.py.

◆ AUDIT_MAX_FILES

int oct.git.audit.AUDIT_MAX_FILES = 20

Definition at line 69 of file audit.py.

◆ AUDIT_MAX_SIZE_BYTES

int oct.git.audit.AUDIT_MAX_SIZE_BYTES = 5 * 1024 * 1024

Definition at line 74 of file audit.py.