Strip narrative comments and module/helper docstrings
Five rounds of sweep across the tree. Net ~544 lines removed. Removed: - Section-divider banners and one-line section labels (# Display utilities, # ----- list_requests -----, # CVSS breakdown, etc.). - Module-level prose docstrings on internal modules. Kept one-line summaries; trimmed multi-paragraph narration about SDK/Strix responsibility splits, cache strategies, three-source precedence. - Internal-helper docstrings that just restate the function name — caido_api helpers (caido_url, get_client, view_request, etc.), settings-class one-liners (LLMSettings, RuntimeSettings, ...), UI helper docstrings. - Args/Returns blocks on non-LLM-facing internal helpers (build_strix_agent, render_system_prompt, create_or_reuse, bootstrap_caido) — kept only the genuinely non-obvious params. - Internal-history phrasing — "Mirrors main-branch shape", "pre-SDK harness", "previous lookup matched no attribute". - Narrative comments inside function bodies that explained what the next line does, design rationale obvious from the surrounding code, or "we used to..." asides. - Trailing periods on every error-string literal across the tool tree. - Duplicated roundtripTime quirk comment (kept the LLM-facing copy in tools/proxy/tools.py). Kept (every one names an upstream bug, vendored-code provenance, or non-obvious data quirk): - core/runner.py: SDK replay-with-empty-initial-input + on_agent_end lifecycle gap. - runtime/docker_client.py: VERBATIM COPY block of the upstream _create_container body, pinned to SDK v0.14.6. - runtime/session_manager.py: NO_PROXY for agent-browser CDP loopback. - tools/proxy/caido_api.py: generated-pydantic Request.raw quirk, replay double-history pitfall. - tools/proxy/tools.py: Caido roundtripTime=0 quirk for proxy captures. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1 @@
|
||||
"""Strix runtime — pluggable sandbox lifecycle on top of the Agents SDK.
|
||||
|
||||
- :mod:`.backends` — registry mapping ``STRIX_RUNTIME_BACKEND`` values
|
||||
to async factories that bring up a ``(client, session)`` pair. Ships
|
||||
with ``"docker"`` out of the box; ``register_backend`` lets downstream
|
||||
users add Daytona / K8s / Modal / etc. without forking.
|
||||
- :mod:`.session_manager` — ``create_or_reuse`` / ``cleanup`` keyed
|
||||
by scan id; bundles the SDK session with a ready Caido client.
|
||||
- :mod:`.caido_bootstrap` — runtime-agnostic Caido auth dance via
|
||||
``session.exec``.
|
||||
- :class:`strix.runtime.docker_client.StrixDockerSandboxClient` —
|
||||
``DockerSandboxClient`` subclass that injects ``NET_ADMIN`` /
|
||||
``NET_RAW`` capabilities and ``host.docker.internal`` extra-hosts
|
||||
(used only by the Docker backend).
|
||||
"""
|
||||
"""Pluggable sandbox lifecycle on top of the Agents SDK."""
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
"""Sandbox backend registry — runtime-agnostic session bring-up.
|
||||
|
||||
A *backend* is an async callable that takes an image tag + an SDK
|
||||
:class:`Manifest` + the ports to expose, and returns the matching
|
||||
``(client, session)`` pair. The caller owns lifecycle from there
|
||||
(``await client.delete(session)``).
|
||||
|
||||
This keeps :mod:`strix.runtime.session_manager` free of any
|
||||
backend-specific imports — switching to Daytona / K8s / Modal /
|
||||
whatever is one new factory function plus one registry entry.
|
||||
|
||||
Selection is driven by ``STRIX_RUNTIME_BACKEND`` (default: ``"docker"``).
|
||||
Unknown values raise :class:`ValueError` rather than silently falling
|
||||
back, so typos fail loudly.
|
||||
"""
|
||||
"""Sandbox backend registry — selected via STRIX_RUNTIME_BACKEND (default: docker)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -28,11 +14,6 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# A backend brings up a fresh session and returns the (client, session)
|
||||
# pair. The client is whatever object exposes ``await client.delete(session)``
|
||||
# for cleanup — typically an ``agents.sandbox.client.BaseSandboxClient``
|
||||
# subclass, but the protocol is duck-typed so non-SDK backends could
|
||||
# also plug in if they implement the same interface.
|
||||
SandboxBackend = Callable[..., Awaitable[tuple[Any, Any]]]
|
||||
|
||||
|
||||
@@ -103,5 +84,4 @@ def register_backend(name: str, backend: SandboxBackend) -> None:
|
||||
|
||||
|
||||
def supported_backends() -> list[str]:
|
||||
"""Snapshot of registered backend names. Useful for ``--help`` text."""
|
||||
return sorted(_BACKENDS)
|
||||
|
||||
@@ -5,10 +5,6 @@ The Caido CLI runs as an in-container sidecar listening on
|
||||
``session.exec()``-ing curl from inside the container, then construct
|
||||
a host-side :class:`caido_sdk_client.Client` against the runtime's
|
||||
exposed-port URL for all subsequent SDK calls.
|
||||
|
||||
Running the auth dance through ``session.exec`` keeps this module
|
||||
runtime-agnostic — Docker / Daytona / K8s sessions all implement
|
||||
``exec`` even when their port-exposure semantics differ.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -89,22 +85,7 @@ async def bootstrap_caido(
|
||||
host_url: str,
|
||||
container_url: str,
|
||||
) -> Client:
|
||||
"""Connect to the in-container Caido sidecar and select a fresh project.
|
||||
|
||||
Args:
|
||||
session: Bound sandbox session — used for ``exec`` to call into
|
||||
the in-container Caido API for the guest-login dance.
|
||||
host_url: Host-reachable URL for Caido's GraphQL endpoint
|
||||
(e.g. ``http://127.0.0.1:{exposed_port}``). Used by the
|
||||
host-side :class:`Client` for all post-bootstrap calls.
|
||||
container_url: In-container URL for Caido's GraphQL endpoint
|
||||
(e.g. ``http://127.0.0.1:48080``). Used by the in-sandbox
|
||||
curl for the guest-login dance.
|
||||
|
||||
Returns:
|
||||
A connected :class:`caido_sdk_client.Client` with a temporary
|
||||
``"sandbox"`` project selected.
|
||||
"""
|
||||
"""Connect to the in-container Caido sidecar and select a fresh project."""
|
||||
logger.info("Bootstrapping Caido client (host=%s, container=%s)", host_url, container_url)
|
||||
|
||||
access_token = await _login_as_guest(session, container_url=container_url)
|
||||
|
||||
@@ -42,12 +42,6 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StrixDockerSandboxClient(DockerSandboxClient):
|
||||
"""``DockerSandboxClient`` subclass that injects Strix-required capabilities.
|
||||
|
||||
Only ``_create_container`` is overridden. All other behavior — image
|
||||
management, session lifecycle, port resolution, cleanup — is inherited.
|
||||
"""
|
||||
|
||||
async def _create_container(
|
||||
self,
|
||||
image: str,
|
||||
@@ -104,7 +98,7 @@ class StrixDockerSandboxClient(DockerSandboxClient):
|
||||
|
||||
# Strix injections — append, don't overwrite, so FUSE/SYS_ADMIN survives.
|
||||
cap_add = create_kwargs.setdefault("cap_add", [])
|
||||
if not isinstance(cap_add, list): # defensive — parent always sets list
|
||||
if not isinstance(cap_add, list):
|
||||
cap_add = list(cap_add)
|
||||
create_kwargs["cap_add"] = cap_add
|
||||
for cap in ("NET_ADMIN", "NET_RAW"):
|
||||
|
||||
@@ -1,17 +1,4 @@
|
||||
"""Per-scan sandbox session lifecycle.
|
||||
|
||||
One session per scan, reused across every agent in that scan's tree.
|
||||
|
||||
The bundle returned by :func:`create_or_reuse` carries the SDK
|
||||
``client`` + ``session`` plus a ready-to-use Caido client (already
|
||||
authenticated and pointing at a temporary sandbox project).
|
||||
|
||||
Cache strategy: a module-level dict keyed by ``scan_id``. The same scan
|
||||
issuing multiple ``create_or_reuse`` calls (e.g., resume after a crash
|
||||
on the host side) gets the same bundle back. ``cleanup`` is best-effort
|
||||
— a leaked container is preferable to a stuck cleanup that prevents the
|
||||
next scan from starting.
|
||||
"""
|
||||
"""Per-scan sandbox session lifecycle."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -34,10 +21,6 @@ logger = logging.getLogger(__name__)
|
||||
_CONTAINER_CAIDO_PORT = 48080
|
||||
|
||||
|
||||
# Per-scan session cache. Module-level so a scan that bounces through
|
||||
# multiple host-side processes (e.g., re-imports the module) doesn't
|
||||
# spin up a second container — though in practice we expect one
|
||||
# Strix process per scan.
|
||||
_SESSION_CACHE: dict[str, dict[str, Any]] = {}
|
||||
|
||||
|
||||
@@ -47,29 +30,16 @@ async def create_or_reuse(
|
||||
image: str,
|
||||
local_sources: list[dict[str, str]],
|
||||
) -> dict[str, Any]:
|
||||
"""Return the existing bundle for ``scan_id`` or create a new one.
|
||||
"""Return the existing session bundle for ``scan_id`` or create a new one.
|
||||
|
||||
Args:
|
||||
scan_id: Caller-provided scan identifier (used as cache key).
|
||||
image: Docker image tag (e.g. ``"strix-sandbox:0.2.0"``).
|
||||
local_sources: Each entry's ``source_path`` (host) is mounted at
|
||||
``/workspace/<workspace_subdir>`` inside the container — the
|
||||
same path the root-task prompt advertises. Empty list means
|
||||
no host code is mounted (web/IP-only scans).
|
||||
|
||||
Returns the bundle dict containing ``client``, ``session``, and
|
||||
``caido_client``.
|
||||
Each ``local_sources`` entry mounts its host ``source_path`` at
|
||||
``/workspace/<workspace_subdir>`` inside the container.
|
||||
"""
|
||||
cached = _SESSION_CACHE.get(scan_id)
|
||||
if cached is not None:
|
||||
logger.info("Reusing existing sandbox session for scan %s", scan_id)
|
||||
return cached
|
||||
|
||||
# Build Manifest entries keyed by ``workspace_subdir`` — the SDK
|
||||
# mounts each at ``/workspace/<key>``, which is exactly the path
|
||||
# ``build_root_task`` puts in the agent's task prompt. Mounting
|
||||
# only the listed source dirs (not their parent) avoids leaking
|
||||
# unrelated host content into the sandbox.
|
||||
entries: dict[str | Path, BaseEntry] = {}
|
||||
for src in local_sources:
|
||||
ws_subdir = src.get("workspace_subdir") or ""
|
||||
|
||||
Reference in New Issue
Block a user