jeevesagent.security.audit
==========================

.. py:module:: jeevesagent.security.audit

.. autoapi-nested-parse::

   Append-only audit log.

   Every meaningful event in the loop — run start/finish, tool dispatch,
   tool result, permission decision — gets a signed entry on the audit
   log. Two backends ship:

   * :class:`InMemoryAuditLog` — list-backed, fast, used in tests and dev.
   * :class:`FileAuditLog` — JSONL append on disk, durable across
     process restarts.

   Both compute an HMAC-SHA256 ``signature`` over a canonicalised
   representation of the entry's content fields, keyed by a per-log
   ``secret``. The signature lets compliance tooling detect tampering;
   :func:`verify_signature` recomputes it and compares.

   The log is conceptually monotonic: ``seq`` is per-log and never
   re-used. :class:`FileAuditLog` recovers the highest seq from the file
   on startup so multiple processes can append in turn.



Classes
-------

.. autoapisummary::

   jeevesagent.security.audit.AuditLog
   jeevesagent.security.audit.FileAuditLog
   jeevesagent.security.audit.InMemoryAuditLog


Functions
---------

.. autoapisummary::

   jeevesagent.security.audit.stream_entries
   jeevesagent.security.audit.verify_signature


Module Contents
---------------

.. py:class:: AuditLog

   Bases: :py:obj:`Protocol`


   The append-only signed log surface.


   .. py:method:: append(*, session_id: str, actor: str, action: str, payload: dict[str, Any]) -> jeevesagent.core.types.AuditEntry
      :async:



   .. py:method:: query(*, session_id: str | None = None, action: str | None = None) -> list[jeevesagent.core.types.AuditEntry]
      :async:



.. py:class:: FileAuditLog(path: str | pathlib.Path, *, secret: str = '')

   JSONL append-only audit log with HMAC signatures.

   On construction we read any pre-existing entries to recover the
   highest seq, so a process restart picks up where the last one left
   off.


   .. py:method:: append(*, session_id: str, actor: str, action: str, payload: dict[str, Any]) -> jeevesagent.core.types.AuditEntry
      :async:



   .. py:method:: query(*, session_id: str | None = None, action: str | None = None) -> list[jeevesagent.core.types.AuditEntry]
      :async:



   .. py:property:: path
      :type: pathlib.Path



.. py:class:: InMemoryAuditLog(*, secret: str = '')

   List-backed signed audit log.


   .. py:method:: all_entries() -> list[jeevesagent.core.types.AuditEntry]
      :async:



   .. py:method:: append(*, session_id: str, actor: str, action: str, payload: dict[str, Any]) -> jeevesagent.core.types.AuditEntry
      :async:



   .. py:method:: query(*, session_id: str | None = None, action: str | None = None) -> list[jeevesagent.core.types.AuditEntry]
      :async:



.. py:function:: stream_entries(log: AuditLog) -> collections.abc.AsyncIterator[jeevesagent.core.types.AuditEntry]
   :async:


   Yield every entry currently in ``log`` in seq order.

   A polling helper for compliance tooling. Doesn't tail — that comes
   later when we add an on-write notification stream.


.. py:function:: verify_signature(entry: jeevesagent.core.types.AuditEntry, secret: str) -> bool

   Recompute the HMAC and compare against the stored signature.


