From 1a78378ed7f2fa778f95e283d7e899ba58fd3598 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Fri, 27 Feb 2026 09:56:39 -0800 Subject: [PATCH] Fix docker socket not mounting when toggling container spawning When "Allow container spawning" was toggled on an existing container, the docker socket mount was never applied because the container was simply restarted rather than recreated. Now inspects the existing container's mounts and recreates it when there's a mismatch, preserving the named config volume (keyed by project ID) across recreation. Co-Authored-By: Claude Opus 4.6 --- .../src/commands/project_commands.rs | 34 +++++++++++++++++-- app/src-tauri/src/docker/container.rs | 21 ++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/app/src-tauri/src/commands/project_commands.rs b/app/src-tauri/src/commands/project_commands.rs index a7c881a..6dec327 100644 --- a/app/src-tauri/src/commands/project_commands.rs +++ b/app/src-tauri/src/commands/project_commands.rs @@ -102,9 +102,37 @@ pub async fn start_project_container( // Check for existing container let container_id = if let Some(existing_id) = docker::find_existing_container(&project).await? { - // Start existing container - docker::start_container(&existing_id).await?; - existing_id + // Check if docker socket mount matches the current project setting. + // If the user toggled "Allow container spawning" after the container was + // created, we need to recreate the container for the mount change to take + // effect. + let has_socket = docker::container_has_docker_socket(&existing_id).await.unwrap_or(false); + if has_socket != project.allow_docker_access { + log::info!( + "Docker socket mismatch (container has_socket={}, project wants={}), recreating container", + has_socket, project.allow_docker_access + ); + // Safe to remove and recreate: the claude config named volume is + // keyed by project ID (not container ID) so it persists across + // container recreation. Bind mounts (workspace, SSH, AWS) are + // host paths and are unaffected. + let _ = docker::stop_container(&existing_id).await; + docker::remove_container(&existing_id).await?; + let new_id = docker::create_container( + &project, + api_key.as_deref(), + &docker_socket, + &image_name, + aws_config_path.as_deref(), + &settings.global_aws, + ).await?; + docker::start_container(&new_id).await?; + new_id + } else { + // Start existing container as-is + docker::start_container(&existing_id).await?; + existing_id + } } else { // Create new container let new_id = docker::create_container( diff --git a/app/src-tauri/src/docker/container.rs b/app/src-tauri/src/docker/container.rs index f8d6c5c..e63cfbc 100644 --- a/app/src-tauri/src/docker/container.rs +++ b/app/src-tauri/src/docker/container.rs @@ -288,6 +288,27 @@ pub async fn remove_container(container_id: &str) -> Result<(), String> { .map_err(|e| format!("Failed to remove container: {}", e)) } +/// Check whether an existing container has docker socket mounted. +pub async fn container_has_docker_socket(container_id: &str) -> Result { + let docker = get_docker()?; + let info = docker + .inspect_container(container_id, None) + .await + .map_err(|e| format!("Failed to inspect container: {}", e))?; + + let has_socket = info + .host_config + .and_then(|hc| hc.mounts) + .map(|mounts| { + mounts.iter().any(|m| { + m.target.as_deref() == Some("/var/run/docker.sock") + }) + }) + .unwrap_or(false); + + Ok(has_socket) +} + pub async fn get_container_info(project: &Project) -> Result, String> { if let Some(ref container_id) = project.container_id { let docker = get_docker()?;