mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 15:40:18 +00:00
* feat: add Docker detection module with platform guidance Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: add Docker sandbox step to setup wizard Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: show Docker status in boot screen Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: check Docker availability at startup When SANDBOX_ENABLED=true, proactively detect whether Docker is installed and running before creating the ContainerJobManager. If Docker is unavailable, log a warning with platform-specific guidance and disable the sandbox for the session. Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: enable sandbox by default, improve wizard explanation, document detection limits - SandboxConfig defaults to enabled=true (startup check disables gracefully if Docker is unavailable) - Wizard step explains why Docker matters: isolation for LLM-generated code vs running directly on the host - Document detection confidence per platform in detect.rs module docs: high on macOS/Linux, medium on Windows (named pipe edge cases) Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: cargo fmt + update test_builder_defaults for enabled-by-default Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: deduplicate wizard Docker status handling per review Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: fix skills system - enable by default, fix registry connectivity and install - Enable skills system by default (SKILLS_ENABLED no longer required) - Bypass Vercel TLS fingerprint blocking by pointing DEFAULT_REGISTRY_URL directly at the Convex backend (wry-manatee-359.convex.site) - Handle ZIP archives from ClawHub download API - the registry returns ZIP files containing SKILL.md, not raw text. Uses flate2 (existing dep) to extract SKILL.md from the archive. - Surface catalog search errors in the UI with a yellow warning banner instead of silently returning empty results - Handle both {"results":[...]} envelope and bare [...] array JSON formats from the search API - Add ClawHub links and metadata to search result cards (clickable skill names linking to clawhub.ai, relevance score, "updated X ago" recency) - Fix 3 pre-existing clippy warnings in tests/html_to_markdown.rs Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address security review feedback on ZIP extraction and SSRF - Cap download size to 10 MB before reading response body - Guard against ZIP bombs: cap uncompressed_size at 1 MB, wrap DeflateDecoder with .take() read limit - Use checked_add for ZIP header offset arithmetic to prevent overflow - Remove .unwrap() on try_into() -- use direct array construction - Handle IPv4-mapped IPv6 addresses (::ffff:192.168.x.x) in SSRF checks - Don't leak internal registry URLs in user-facing catalog_error messages - Fix non-ASCII panic in catalog response debug logging (use .get() instead of byte slicing) Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: add /skills command and enrich search results with ClawHub metadata - Parse /skills and /skills search <query> as SystemCommands in submission.rs - Add skill_catalog to AgentDeps and wire it through main.rs - Handle "skills" command in commands.rs: list installed skills and search ClawHub - Add /skills and /skills search <q> entries to /help output - Add SkillDetail, SkillStats, SkillOwner structs to catalog.rs - Add fetch_skill_detail() calling GET /api/v1/skills/{slug} on Convex backend - Add enrich_search_results() to fetch stars/downloads/owner for top 5 results in parallel - Fix SkillDetailResponse wrapper struct to match actual API shape: {"skill":{...},"owner":{...}} - Surface stars, downloads, owner in web UI skill search cards (app.js) - Surface enriched data in skills web handler and skill_search tool output Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix: cargo fmt after merge conflict resolution Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix: separate installed_skills dir for correct trust on restart, remove duplicate handlers Trust level bug: skills installed from ClawHub were written to user_dir (~/.ironclaw/skills/) which is discovered as Trusted on restart. Now installs go to ~/.ironclaw/installed_skills/ which is discovered as Installed, matching the documented skill directory layout. Changes: - SkillsConfig: add installed_dir field (SKILLS_INSTALLED_DIR env var, default ~/.ironclaw/installed_skills/) - SkillRegistry: add with_installed_dir() builder, installed_dir()/ install_target_dir() accessors, and discover installed_dir with SkillTrust::Installed in discover_all() - All install paths (web handler, skill tool) use install_target_dir() instead of user_dir() so new installs land in the correct directory - 3 new registry tests: test_installed_dir_uses_installed_trust, test_install_target_dir_prefers_installed_dir, test_user_dir_stays_trusted_with_installed_dir Duplicate handler cleanup: handlers/skills.rs was the canonical implementation but the handlers module was never compiled (not declared in web/mod.rs), so server.rs had its own duplicate inline definitions that the router used. Wire up the handlers module, delete the 260-line duplicate in server.rs, and have server.rs import skills handlers from handlers::skills. Fix pre-existing compile error in handlers/extensions.rs (missing needs_setup field). Add #[allow(dead_code)] on not-yet-migrated handler modules to suppress warnings. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: probe more Docker socket paths on macOS Docker Desktop 4.13+ (stabilised in 4.18) no longer creates the /var/run/docker.sock symlink by default. The API socket lives at ~/.docker/run/docker.sock, which bollard's connect_with_local_defaults() does not try. Add a fallback probe list covering the common macOS container runtimes: - ~/.docker/run/docker.sock — Docker Desktop 4.13+ - ~/.colima/default/docker.sock — Colima - ~/.rd/docker.sock — Rancher Desktop Remove the bogus ~/.docker/desktop/docker.sock path that was added previously; it is not an API socket on any known Docker installation. Fixes the false-negative "Docker is installed but not running" warning reported by Illia on macOS with Docker Desktop 4.18+. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * Harden Docker detection for rootless Linux and Windows fallback --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
114 lines
6.5 KiB
Rust
114 lines
6.5 KiB
Rust
//! Docker execution sandbox for secure command execution.
|
|
//!
|
|
//! This module provides a complete sandboxing solution for running untrusted commands:
|
|
//! - **Container isolation**: Commands run in ephemeral Docker containers
|
|
//! - **Network proxy**: All network traffic goes through a validating proxy
|
|
//! - **Credential injection**: Secrets are injected by the proxy, never exposed in containers
|
|
//! - **Resource limits**: Memory, CPU, and timeout enforcement
|
|
//!
|
|
//! # Architecture
|
|
//!
|
|
//! ```text
|
|
//! ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
//! │ Sandbox System │
|
|
//! │ │
|
|
//! │ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
//! │ │ SandboxManager │ │
|
|
//! │ │ │ │
|
|
//! │ │ • Coordinates container creation and execution │ │
|
|
//! │ │ • Manages proxy lifecycle │ │
|
|
//! │ │ • Enforces resource limits │ │
|
|
//! │ └─────────────────────────────────────────────────────────────────────┘ │
|
|
//! │ │ │ │
|
|
//! │ ▼ ▼ │
|
|
//! │ ┌──────────────────┐ ┌───────────────────┐ │
|
|
//! │ │ Container │ │ Network Proxy │ │
|
|
//! │ │ Runner │ │ │ │
|
|
//! │ │ │ │ • Allowlist │ │
|
|
//! │ │ • Create │◀────────▶│ • Credentials │ │
|
|
//! │ │ • Execute │ │ • Logging │ │
|
|
//! │ │ • Cleanup │ │ │ │
|
|
//! │ └──────────────────┘ └───────────────────┘ │
|
|
//! │ │ │ │
|
|
//! │ ▼ ▼ │
|
|
//! │ ┌──────────────────┐ ┌───────────────────┐ │
|
|
//! │ │ Docker │ │ Internet │ │
|
|
//! │ │ │ │ (allowed hosts) │ │
|
|
//! │ └──────────────────┘ └───────────────────┘ │
|
|
//! └─────────────────────────────────────────────────────────────────────────────┘
|
|
//! ```
|
|
//!
|
|
//! # Sandbox Policies
|
|
//!
|
|
//! | Policy | Filesystem | Network | Use Case |
|
|
//! |--------|------------|---------|----------|
|
|
//! | `ReadOnly` | Read workspace | Proxied | Explore code, fetch docs |
|
|
//! | `WorkspaceWrite` | Read/write workspace | Proxied | Build software, run tests |
|
|
//! | `FullAccess` | Full host | Full | Direct execution (no sandbox) |
|
|
//!
|
|
//! # Example
|
|
//!
|
|
//! ```rust,no_run
|
|
//! use ironclaw::sandbox::{SandboxManager, SandboxManagerBuilder, SandboxPolicy};
|
|
//! use std::collections::HashMap;
|
|
//! use std::path::Path;
|
|
//!
|
|
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
|
|
//! let manager = SandboxManagerBuilder::new()
|
|
//! .enabled(true)
|
|
//! .policy(SandboxPolicy::WorkspaceWrite)
|
|
//! .build();
|
|
//!
|
|
//! manager.initialize().await?;
|
|
//!
|
|
//! let result = manager.execute(
|
|
//! "cargo build --release",
|
|
//! Path::new("/workspace/my-project"),
|
|
//! HashMap::new(),
|
|
//! ).await?;
|
|
//!
|
|
//! println!("Exit code: {}", result.exit_code);
|
|
//! println!("Output: {}", result.output);
|
|
//!
|
|
//! manager.shutdown().await;
|
|
//! # Ok(())
|
|
//! # }
|
|
//! ```
|
|
//!
|
|
//! # Security Properties
|
|
//!
|
|
//! - **No credentials in containers**: Environment variables with secrets never enter containers
|
|
//! - **Network isolation**: All traffic routes through the proxy (validated domains only)
|
|
//! - **Non-root execution**: Containers run as UID 1000
|
|
//! - **Read-only root**: Container filesystem is read-only (except workspace mount)
|
|
//! - **Capability dropping**: All Linux capabilities dropped, only essential ones added back
|
|
//! - **Auto-cleanup**: Containers are removed after execution (--rm + explicit cleanup)
|
|
//! - **Timeout enforcement**: Commands are killed after the timeout
|
|
|
|
pub mod config;
|
|
pub mod container;
|
|
pub mod detect;
|
|
pub mod error;
|
|
pub mod manager;
|
|
pub mod proxy;
|
|
|
|
pub use config::{ResourceLimits, SandboxConfig, SandboxPolicy};
|
|
pub use container::{ContainerOutput, ContainerRunner, connect_docker};
|
|
pub use detect::{DockerDetection, DockerStatus, Platform, check_docker};
|
|
pub use error::{Result, SandboxError};
|
|
pub use manager::{ExecOutput, SandboxManager, SandboxManagerBuilder};
|
|
pub use proxy::{
|
|
CredentialResolver, DefaultPolicyDecider, DomainAllowlist, EnvCredentialResolver, HttpProxy,
|
|
NetworkDecision, NetworkPolicyDecider, NetworkProxyBuilder, NetworkRequest,
|
|
};
|
|
|
|
/// Default allowlist getter (re-export for convenience).
|
|
pub fn default_allowlist() -> Vec<String> {
|
|
config::default_allowlist()
|
|
}
|
|
|
|
/// Default credential mappings getter (re-export for convenience).
|
|
pub fn default_credential_mappings() -> Vec<crate::secrets::CredentialMapping> {
|
|
config::default_credential_mappings()
|
|
}
|