Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ src/ai_company/
providers/ # LLM provider abstraction (LiteLLM adapter)
security/ # SecOps agent, approval gates, audit
templates/ # Pre-built company templates and builder
tools/ # Tool registry, built-in tools (file_system/, git), MCP integration, role-based access, sandboxing
tools/ # Tool registry, built-in tools (file_system/, git, sandbox/), MCP integration, role-based access
```

## Shell Usage
Expand Down
24 changes: 14 additions & 10 deletions DESIGN_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -1675,7 +1675,7 @@ When the LLM requests multiple tool calls in a single turn, `ToolInvoker.invoke_

The `ToolPermissionChecker` resolves permissions using a priority-based system: denied list (highest) → allowed list → access-level categories → deny (default). `AgentEngine._make_tool_invoker()` creates a permission-aware invoker from the agent's `ToolPermissions` at the start of each `run()` call. Note: M3 implements category-level gating only; the granular sub-constraints described in §11.2 (workspace scope, network mode) are planned for when sandboxing is implemented.

> **M3 implementation note — Built-in git tools:** Six workspace-scoped git tools are implemented in `tools/git_tools.py` with a shared `_BaseGitTool` base class in `tools/_git_base.py`: `GitStatusTool`, `GitLogTool`, `GitDiffTool`, `GitBranchTool`, `GitCommitTool`, and `GitCloneTool`. The base class enforces workspace boundary security (path traversal prevention via `resolve()` + `relative_to()`) and provides a common `_run_git()` helper using `asyncio.create_subprocess_exec` (never `shell=True`). Security hardening includes: `GIT_TERMINAL_PROMPT=0` to prevent credential prompts, `GIT_CONFIG_NOSYSTEM=1`, `GIT_CONFIG_GLOBAL=/dev/null`, and `GIT_PROTOCOL_FROM_USER=0` to restrict config/protocol attack surfaces, rejection of flag-like ref/branch values (starting with `-`), URL scheme validation on clone (only `https://`, `http://`, `ssh://`, `git://`, and SCP-like syntax) with `--` separator before positional URL argument, and clone URLs starting with `-` are rejected. All tools return `ToolExecutionResult` for errors rather than raising exceptions. **Future:** Consider adding host/IP allowlisting for clone URLs to prevent SSRF against internal networks (loopback, link-local, private ranges).
> **M3 implementation note — Built-in git tools:** Six workspace-scoped git tools are implemented in `tools/git_tools.py` with a shared `_BaseGitTool` base class in `tools/_git_base.py`: `GitStatusTool`, `GitLogTool`, `GitDiffTool`, `GitBranchTool`, `GitCommitTool`, and `GitCloneTool`. The base class enforces workspace boundary security (path traversal prevention via `resolve()` + `relative_to()`) and provides a common `_run_git()` helper using `asyncio.create_subprocess_exec` (never `shell=True`). Security hardening includes: `GIT_TERMINAL_PROMPT=0` to prevent credential prompts, `GIT_CONFIG_NOSYSTEM=1`, `GIT_CONFIG_GLOBAL=os.devnull`, and `GIT_PROTOCOL_FROM_USER=0` to restrict config/protocol attack surfaces, rejection of flag-like ref/branch values (starting with `-`), URL scheme validation on clone (only `https://`, `ssh://`, `git://`, and SCP-like syntax — plain `http://` rejected for security) with `--` separator before positional URL argument, and clone URLs starting with `-` are rejected. All tools return `ToolExecutionResult` for errors rather than raising exceptions. When a `SandboxBackend` is injected, `_run_git()` delegates subprocess management to the sandbox via `_run_git_sandboxed()` — the sandbox handles environment filtering and workspace-scoped cwd enforcement, while `_validate_path` independently enforces workspace boundaries for git path arguments. Git hardening env vars are passed as `env_overrides` to the sandbox, and `SandboxResult` is converted to `ToolExecutionResult` via `_sandbox_result_to_execution_result`. Without a sandbox, the direct-subprocess path is used (backward compatible). **Future:** Consider adding host/IP allowlisting for clone URLs to prevent SSRF against internal networks (loopback, link-local, private ranges).

### 11.1.2 Tool Sandboxing

Expand All @@ -1687,8 +1687,8 @@ Tool execution requires safety boundaries proportional to the risk of each tool

| Backend | Isolation | Latency | Dependencies | Status |
|---------|-----------|---------|--------------|--------|
| `SubprocessSandbox` | Process-level: timeout, restricted PATH, workspace-scoped paths | ~ms | None | M3 |
| `DockerSandbox` | Container-level: ephemeral container, mounted workspace, no network, resource limits (CPU/memory/time) | ~1-2s cold start | Docker | M3 |
| `SubprocessSandbox` | Process-level: env filtering (allowlist + denylist), restricted PATH, workspace-scoped cwd, timeout + process-group kill, library injection var blocking | ~ms | None | **Implemented** |
| `DockerSandbox` | Container-level: ephemeral container, mounted workspace, no network, resource limits (CPU/memory/time) | ~1-2s cold start | Docker | Planned |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| `K8sSandbox` | Pod-level: per-agent containers, namespace isolation, resource quotas, network policies | ~2-5s | Kubernetes | Future |

#### Default Layered Configuration
Expand Down Expand Up @@ -1775,7 +1775,7 @@ tool_access:
description: "Per-agent custom configuration."
```

> **M3 implementation note:** The current `ToolPermissionChecker` implements **category-level gating only** — each access level maps to a set of permitted `ToolCategory` values (e.g., `STANDARD` permits `file_system`, `code_execution`, `version_control`, `web`, `terminal`, `analytics`). The granular sub-constraints shown above (workspace scope, network mode, containerization) are planned for when sandboxing backends (§11.1.2) are implemented.
> **M3 implementation note:** The current `ToolPermissionChecker` implements **category-level gating only** — each access level maps to a set of permitted `ToolCategory` values (e.g., `STANDARD` permits `file_system`, `code_execution`, `version_control`, `web`, `terminal`, `analytics`). `SubprocessSandbox` provides workspace-scoped cwd enforcement and env filtering (see §11.1.2). The granular sub-constraints shown above (network mode, containerization) are planned for Docker/K8s sandbox backends.

### 11.3 Progressive Trust

Expand Down Expand Up @@ -2335,6 +2335,7 @@ ai-company/
│ │ │ ├── provider.py # PROVIDER_* constants
│ │ │ ├── role.py # ROLE_* constants
│ │ │ ├── routing.py # ROUTING_* constants
│ │ │ ├── sandbox.py # SANDBOX_* constants
│ │ │ ├── task.py # TASK_* constants
│ │ │ ├── template.py # TEMPLATE_* constants
│ │ │ └── tool.py # TOOL_* constants
Expand Down Expand Up @@ -2372,10 +2373,13 @@ ai-company/
│ │ ├── errors.py # Tool error hierarchy (incl. ToolPermissionDeniedError)
│ │ ├── examples/ # Example tool implementations
│ │ │ └── echo.py # Echo tool (for testing)
│ │ ├── sandbox/ # Sandboxing backends (M3)
│ │ ├── sandbox/ # Sandboxing backends
│ │ │ ├── __init__.py # Package exports
│ │ │ ├── config.py # SubprocessSandboxConfig model
│ │ │ ├── errors.py # SandboxError hierarchy
│ │ │ ├── protocol.py # SandboxBackend protocol
│ │ │ ├── subprocess.py # SubprocessSandbox (default for low-risk)
│ │ │ └── docker.py # DockerSandbox (for code_runner, terminal)
│ │ │ ├── result.py # SandboxResult model
│ │ │ └── subprocess_sandbox.py # SubprocessSandbox (default)
│ │ ├── file_system/ # Built-in file system tools
│ │ │ ├── __init__.py # Package exports
│ │ │ ├── _base_fs_tool.py # BaseFileSystemTool ABC
Expand All @@ -2385,8 +2389,8 @@ ai-company/
│ │ │ ├── list_directory.py # ListDirectoryTool
│ │ │ ├── read_file.py # ReadFileTool
│ │ │ └── write_file.py # WriteFileTool
│ │ ├── _git_base.py # Base class for git tools (workspace, subprocess)
│ │ ├── git_tools.py # Git operations — 6 built-in tools
│ │ ├── _git_base.py # Base class for git tools (workspace, subprocess, sandbox integration)
│ │ ├── git_tools.py # Git operations — 6 built-in tools (sandbox-aware)
│ │ ├── code_runner.py # Code execution (M3)
│ │ ├── web_tools.py # HTTP, search (M3)
│ │ └── mcp_bridge.py # MCP server integration (M7)
Expand Down Expand Up @@ -2468,7 +2472,7 @@ These conventions were established during the M0–M2+ review cycle. **Adopted**
| **Event constants** | Adopted (per-domain) | Per-domain submodules under `events/` package (e.g. `events.provider`, `events.budget`). Import directly: `from ai_company.observability.events.<domain> import CONSTANT` | Split by domain for discoverability, co-location with domain logic, and reduced merge conflicts as constants grow. `__init__.py` serves as package marker with usage documentation; no re-exports. |
| **Parallel tool execution** | Adopted (M2.5) | `asyncio.TaskGroup` in `ToolInvoker.invoke_all` with optional `max_concurrency` semaphore | Structured concurrency with proper cancellation semantics. Fatal errors collected via guarded wrapper and re-raised after all tasks complete. |
| **Tool permission checking** | Adopted (M3) | `ToolPermissionChecker` enforces category-level gating based on `ToolAccessLevel` (sandboxed → restricted → standard → elevated, plus custom). Priority-based resolution: denied list → allowed list → level categories → deny. Case-insensitive name matching. `ToolInvoker` filters definitions for prompt and checks at invocation time. | Defense-in-depth: agents only see permitted tools in the LLM prompt, and invocations are re-checked at execution time. Explicit allow/deny lists provide per-agent overrides. See §11.1.1. |
| **Tool sandboxing** | Partial (M3) | File system tools use in-process `PathValidator` for workspace-scoped path validation (symlink resolution + containment check). `BaseFileSystemTool` ABC provides shared `ToolCategory.FILE_SYSTEM` and `PathValidator` integration — all file system tools extend this base. `SandboxBackend` protocol with `SubprocessSandbox` / `DockerSandbox` remains planned for git, code_runner, terminal, web, and database tools. `K8sSandbox` planned for future container deployments. | File system tools use defence-in-depth path validation; heavier sandbox isolation reserved for higher-risk tool categories (code execution, network). See §11.1.2. |
| **Tool sandboxing** | Adopted (M3, incremental) | File system tools use in-process `PathValidator` for workspace-scoped path validation (symlink resolution + containment check). `BaseFileSystemTool` ABC provides shared `ToolCategory.FILE_SYSTEM` and `PathValidator` integration — all file system tools extend this base. `SandboxBackend` protocol with `SubprocessSandbox` implemented — git tools accept optional `SandboxBackend` injection and delegate subprocess management to it (env filtering, workspace enforcement, timeout + process-group kill). `DockerSandbox` planned for code_runner, terminal, web, and database tools. `K8sSandbox` planned for future container deployments. Config-driven per-category backend selection planned for engine wiring. | File system tools use defence-in-depth path validation; subprocess sandbox provides lightweight isolation for git tools; heavier Docker/K8s isolation reserved for higher-risk tool categories (code execution, network). See §11.1.2. |
| **Crash recovery** | Adopted (M3) | Pluggable `RecoveryStrategy` protocol. M3: `FailAndReassignStrategy` (catch at engine boundary, log snapshot, mark FAILED / eligible for reassignment). M4/M5: `CheckpointStrategy` (persist `AgentContext` per turn, resume from last checkpoint). | Immutable `model_copy` pattern makes checkpoint serialization trivial to add later. Fail-and-reassign is sufficient for short MVP tasks. See §6.6. |
| **Agent behavior testing** | Planned (M3) | Scripted `FakeProvider` for unit tests (deterministic turn sequences); behavioral outcome assertions for integration tests (task completed, tools called, cost within budget). | Leverages existing `FakeProvider` and `CompletionResponseFactory` fixtures. Precise engine testing without brittle response-matching at integration level. |
| **LLM call analytics** | Planned (incremental) | M3: proxy metrics (`turns_per_task`, `tokens_per_task`). M4: call categorization (`productive`, `coordination`, `system`) + orchestration ratio. M5+: full analytics (retry tracking, latency, cache hits, per-provider comparison). | Append-only, never blocks execution. Builds on existing `CostRecord` infrastructure. Detects orchestration overhead early. See §10.5. |
Expand Down
15 changes: 15 additions & 0 deletions src/ai_company/observability/events/sandbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Sandbox event constants."""

from typing import Final

SANDBOX_EXECUTE_START: Final[str] = "sandbox.execute.start"
SANDBOX_EXECUTE_SUCCESS: Final[str] = "sandbox.execute.success"
SANDBOX_EXECUTE_FAILED: Final[str] = "sandbox.execute.failed"
SANDBOX_EXECUTE_TIMEOUT: Final[str] = "sandbox.execute.timeout"
SANDBOX_SPAWN_FAILED: Final[str] = "sandbox.spawn.failed"
SANDBOX_ENV_FILTERED: Final[str] = "sandbox.env.filtered"
SANDBOX_WORKSPACE_VIOLATION: Final[str] = "sandbox.workspace.violation"
SANDBOX_CLEANUP: Final[str] = "sandbox.cleanup"
SANDBOX_PATH_FALLBACK: Final[str] = "sandbox.path.fallback"
SANDBOX_HEALTH_CHECK: Final[str] = "sandbox.health_check"
SANDBOX_KILL_FAILED: Final[str] = "sandbox.kill.failed"
16 changes: 16 additions & 0 deletions src/ai_company/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
from .invoker import ToolInvoker
from .permissions import ToolPermissionChecker
from .registry import ToolRegistry
from .sandbox import (
SandboxBackend,
SandboxError,
SandboxResult,
SandboxStartError,
SandboxTimeoutError,
SubprocessSandbox,
SubprocessSandboxConfig,
)

__all__ = [
"BaseFileSystemTool",
Expand All @@ -45,6 +54,13 @@
"ListDirectoryTool",
"PathValidator",
"ReadFileTool",
"SandboxBackend",
"SandboxError",
"SandboxResult",
"SandboxStartError",
"SandboxTimeoutError",
"SubprocessSandbox",
"SubprocessSandboxConfig",
"ToolError",
"ToolExecutionError",
"ToolExecutionResult",
Expand Down
Loading
Loading