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

.. py:module:: jeevesagent.security

.. autoapi-nested-parse::

   Security harness: permissions, hooks, sandbox, audit.



Submodules
----------

.. toctree::
   :maxdepth: 1

   /api/jeevesagent/security/audit/index
   /api/jeevesagent/security/hooks/index
   /api/jeevesagent/security/permissions/index
   /api/jeevesagent/security/sandbox/index


Attributes
----------

.. autoapisummary::

   jeevesagent.security.PostToolHook
   jeevesagent.security.PreToolHook


Classes
-------

.. autoapisummary::

   jeevesagent.security.AllowAll
   jeevesagent.security.AuditLog
   jeevesagent.security.FileAuditLog
   jeevesagent.security.FilesystemSandbox
   jeevesagent.security.HookRegistry
   jeevesagent.security.InMemoryAuditLog
   jeevesagent.security.Mode
   jeevesagent.security.NoSandbox
   jeevesagent.security.StandardPermissions
   jeevesagent.security.SubprocessSandbox


Functions
---------

.. autoapisummary::

   jeevesagent.security.verify_signature


Package Contents
----------------

.. py:class:: AllowAll

   Trivial permission policy: every call is allowed.

   The default for :class:`Agent` when no permissions are configured.


   .. py:method:: check(call: jeevesagent.core.types.ToolCall, *, context: collections.abc.Mapping[str, Any]) -> jeevesagent.core.types.PermissionDecision
      :async:



.. 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:: FilesystemSandbox(inner: jeevesagent.core.protocols.ToolHost, *, roots: collections.abc.Iterable[str | pathlib.Path], path_args: collections.abc.Iterable[str] | None = None, auto_detect: bool = True)

   Restrict a tool host's path-typed arguments to declared roots.


   .. py:method:: call(tool: str, args: collections.abc.Mapping[str, Any], *, call_id: str = '') -> jeevesagent.core.types.ToolResult
      :async:



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



   .. py:method:: watch() -> collections.abc.AsyncIterator[jeevesagent.core.types.ToolEvent]
      :async:



   .. py:property:: inner
      :type: jeevesagent.core.protocols.ToolHost



   .. py:property:: roots
      :type: tuple[pathlib.Path, Ellipsis]



.. py:class:: HookRegistry

   Implements :class:`~jeevesagent.core.protocols.HookHost`.


   .. py:method:: on_event(event: jeevesagent.core.types.Event) -> None
      :async:



   .. py:method:: post_tool(call: jeevesagent.core.types.ToolCall, result: jeevesagent.core.types.ToolResult) -> None
      :async:


      Best-effort post-tool callbacks. Failures and timeouts are
      absorbed so they cannot affect the result the loop returns.



   .. py:method:: pre_tool(call: jeevesagent.core.types.ToolCall) -> jeevesagent.core.types.PermissionDecision
      :async:


      Run all pre-tool hooks. First deny wins; otherwise allow.



   .. py:method:: register_event(hook: EventHook) -> EventHook


   .. py:method:: register_post_tool(hook: PostToolHook) -> PostToolHook


   .. py:method:: register_pre_tool(hook: PreToolHook) -> PreToolHook


   .. py:attribute:: event_hooks
      :type:  list[EventHook]
      :value: []



   .. py:attribute:: hook_timeout_s
      :type:  float
      :value: 5.0



   .. py:attribute:: post_tool_hooks
      :type:  list[PostToolHook]
      :value: []



   .. py:attribute:: pre_tool_hooks
      :type:  list[PreToolHook]
      :value: []



.. 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:class:: Mode

   Bases: :py:obj:`enum.StrEnum`


   Enum where members are also (and must be) strings

   Initialize self.  See help(type(self)) for accurate signature.


   .. py:attribute:: ACCEPT_EDITS
      :value: 'acceptEdits'



   .. py:attribute:: BYPASS
      :value: 'bypassPermissions'



   .. py:attribute:: DEFAULT
      :value: 'default'



.. py:class:: NoSandbox(inner: jeevesagent.core.protocols.ToolHost)

   Pass-through wrapper around a :class:`ToolHost`.


   .. py:method:: call(tool: str, args: collections.abc.Mapping[str, Any], *, call_id: str = '') -> jeevesagent.core.types.ToolResult
      :async:



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



   .. py:method:: watch() -> collections.abc.AsyncIterator[jeevesagent.core.types.ToolEvent]
      :async:



   .. py:property:: inner
      :type: jeevesagent.core.protocols.ToolHost



.. py:class:: StandardPermissions(*, mode: Mode = Mode.DEFAULT, allowed_tools: list[str] | None = None, denied_tools: list[str] | None = None)

   Mode + allow/deny-list permission policy.


   .. py:method:: check(call: jeevesagent.core.types.ToolCall, *, context: collections.abc.Mapping[str, Any]) -> jeevesagent.core.types.PermissionDecision
      :async:



   .. py:method:: strict() -> StandardPermissions
      :classmethod:


      Convenience: default-mode permissions with no overrides.



.. py:class:: SubprocessSandbox(inner: jeevesagent.core.protocols.ToolHost, *, timeout_seconds: float = 30.0)

   Run each tool call in a fresh child Python process.


   .. py:method:: call(tool: str, args: collections.abc.Mapping[str, Any], *, call_id: str = '') -> jeevesagent.core.types.ToolResult
      :async:



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



   .. py:method:: watch() -> collections.abc.AsyncIterator[jeevesagent.core.types.ToolEvent]
      :async:



   .. py:property:: inner
      :type: jeevesagent.core.protocols.ToolHost



   .. py:property:: timeout_seconds
      :type: float



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

   Recompute the HMAC and compare against the stored signature.


.. py:data:: PostToolHook

.. py:data:: PreToolHook

