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

.. py:module:: jeevesagent.security.sandbox

.. autoapi-nested-parse::

   Sandbox layer.

   Sandboxes wrap a :class:`~jeevesagent.core.protocols.ToolHost` and
   mediate every call. The wrapper *is* itself a ``ToolHost`` (it
   re-exports ``list_tools`` / ``call`` / ``watch``) so it slots straight
   into ``Agent(tools=sandbox)`` with zero changes to the agent core.

   What's here today:

   * :class:`NoSandbox` — pass-through. Useful as a layer placeholder and
     to demonstrate the wrapping pattern.
   * :class:`FilesystemSandbox` — validates path-typed arguments don't
     escape one or more declared roots; symlinks are resolved before the
     containment check. Auto-detects path arguments by name (``path``,
     ``file``, ``directory``, ...) or by the value containing ``/``;
     callers can also pass an explicit ``path_args=`` allowlist.

   OS-level isolation backends (Bubblewrap on Linux, Seatbelt on macOS,
   gVisor/Docker for cross-platform) live in subsequent slices.



Submodules
----------

.. toctree::
   :maxdepth: 1

   /api/jeevesagent/security/sandbox/base/index
   /api/jeevesagent/security/sandbox/filesystem/index
   /api/jeevesagent/security/sandbox/subprocess_/index


Classes
-------

.. autoapisummary::

   jeevesagent.security.sandbox.FilesystemSandbox
   jeevesagent.security.sandbox.NoSandbox
   jeevesagent.security.sandbox.SubprocessSandbox


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

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



