From c946b492fb87faa808443501b6d27d7f8b61880d Mon Sep 17 00:00:00 2001 From: Gabor Koerber Date: Sat, 30 May 2026 02:20:06 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=B0=EF=B8=8F=20export=20from=20upstrea?= =?UTF-8?q?m=20(1f28d45)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/sandcage/src/backend/bollard.rs | 30 +++++++++++++++++++++++++- crates/sandcage/src/service/builtin.rs | 9 ++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/crates/sandcage/src/backend/bollard.rs b/crates/sandcage/src/backend/bollard.rs index c45a3fb..0c421b9 100644 --- a/crates/sandcage/src/backend/bollard.rs +++ b/crates/sandcage/src/backend/bollard.rs @@ -38,7 +38,7 @@ pub struct BollardBackend { impl BollardBackend { pub fn try_new() -> super::Result { - let docker = Docker::connect_with_local_defaults().map_err(|e| { + let docker = Self::connect_docker().map_err(|e| { DockerError::SpawnFailed(std::io::Error::new( std::io::ErrorKind::ConnectionRefused, format!( @@ -52,6 +52,34 @@ impl BollardBackend { runtime_info: tokio::sync::OnceCell::new(), }) } + + fn connect_docker() -> std::result::Result { + if std::env::var("DOCKER_HOST").is_ok() { + return Docker::connect_with_local_defaults(); + } + if let Some(socket) = Self::socket_from_docker_context() { + eprintln!("sandcage: using docker socket from context → {socket}"); + return Docker::connect_with_socket(&socket, 120, bollard::API_DEFAULT_VERSION); + } + Docker::connect_with_local_defaults() + } + + fn socket_from_docker_context() -> Option { + let output = std::process::Command::new("docker") + .args(["context", "inspect", "--format", "{{.Endpoints.docker.Host}}"]) + .output() + .ok()?; + if !output.status.success() { + return None; + } + let host = String::from_utf8(output.stdout).ok()?.trim().to_string(); + let path = host.strip_prefix("unix://")?; + if std::path::Path::new(path).exists() { + Some(path.to_string()) + } else { + None + } + } } #[async_trait] diff --git a/crates/sandcage/src/service/builtin.rs b/crates/sandcage/src/service/builtin.rs index 1736dc0..0c30020 100644 --- a/crates/sandcage/src/service/builtin.rs +++ b/crates/sandcage/src/service/builtin.rs @@ -5,7 +5,10 @@ set -e CLAUDE_BIN="$HOME/.local/bin/claude" if [ ! -x "$CLAUDE_BIN" ]; then echo "sandcage: installing Claude Code..." >&2 + WORKDIR="$(pwd)" + cd "$HOME" curl -fsSL https://claude.ai/install.sh | bash >&2 + cd "$WORKDIR" fi exec "$CLAUDE_BIN" "$@" "#; @@ -15,6 +18,8 @@ set -e CODEX_BIN="$HOME/.local/bin/codex" if [ ! -x "$CODEX_BIN" ]; then echo "sandcage: installing Codex..." >&2 + WORKDIR="$(pwd)" + cd "$HOME" arch=$(uname -m) case "$arch" in x86_64) target="x86_64-unknown-linux-musl" ;; @@ -25,6 +30,7 @@ if [ ! -x "$CODEX_BIN" ]; then curl -fsSL "https://github.com/openai/codex/releases/latest/download/codex-${target}.tar.gz" \ | tar xz -C "$HOME/.local/bin" mv "$HOME/.local/bin/codex-${target}" "$CODEX_BIN" + cd "$WORKDIR" fi exec "$CODEX_BIN" "$@" "#; @@ -34,7 +40,10 @@ set -e GEMINI_BIN="$HOME/.local/bin/gemini" if [ ! -x "$GEMINI_BIN" ]; then echo "sandcage: installing Gemini CLI..." >&2 + WORKDIR="$(pwd)" + cd "$HOME" npm install -g @anthropic-ai/gemini-cli >&2 + cd "$WORKDIR" fi exec "$GEMINI_BIN" "$@" "#;