fix: bind project container host ports to 0.0.0.0
Story 1130 added HUSKIES_HOST=0.0.0.0 so the server INSIDE a project
container binds to all interfaces, but the host-side `docker -p`
mapping was still `127.0.0.1:{port}:3001` and `127.0.0.1:{ssh_port}:22`
— reachable from the docker host only, blocking remote MCP clients
and out-of-host SSH onto the project container.
Switch host-side mapping to 0.0.0.0 for both the MCP and SSH ports so
project containers spawned via `new project` are reachable from
anywhere that can route to the docker host. Existing containers
created before this commit retain their localhost-only mapping and
need to be recreated to pick up the change.
Add a regression test asserting both -p arguments use 0.0.0.0 and
reject any 127.0.0.1 restriction in the mapping.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -913,6 +913,11 @@ pub async fn handle_new_project(
|
||||
/// to all interfaces, making Docker port forwarding reachable from the host.
|
||||
/// Without this the server defaults to `127.0.0.1` inside the container —
|
||||
/// reachable only from within the container itself, not via `docker -p`.
|
||||
///
|
||||
/// Host-side port mappings use `0.0.0.0` so the MCP and SSH endpoints are
|
||||
/// reachable from outside the docker host (not just from the host itself).
|
||||
/// `127.0.0.1` had been the conservative default but blocked remote MCP
|
||||
/// clients and out-of-host SSH onto the project container.
|
||||
fn project_docker_run_args(
|
||||
container_name: &str,
|
||||
port: u16,
|
||||
@@ -927,9 +932,9 @@ fn project_docker_run_args(
|
||||
"--name".into(),
|
||||
container_name.to_string(),
|
||||
"-p".into(),
|
||||
format!("127.0.0.1:{port}:3001"),
|
||||
format!("0.0.0.0:{port}:3001"),
|
||||
"-p".into(),
|
||||
format!("127.0.0.1:{ssh_port}:22"),
|
||||
format!("0.0.0.0:{ssh_port}:22"),
|
||||
"-e".into(),
|
||||
"HUSKIES_HOST=0.0.0.0".into(),
|
||||
"-e".into(),
|
||||
@@ -1348,6 +1353,39 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_docker_args_bind_host_ports_to_all_interfaces() {
|
||||
// Project containers must be reachable from outside the docker host
|
||||
// (remote MCP clients, ssh into the project container) — host-side
|
||||
// mapping must use 0.0.0.0, not 127.0.0.1.
|
||||
let args = project_docker_run_args(
|
||||
"huskies-myapp",
|
||||
3100,
|
||||
2200,
|
||||
"ssh-ed25519 AAAA...",
|
||||
"Test User",
|
||||
"test@example.com",
|
||||
);
|
||||
let pairs: Vec<_> = args.windows(2).collect();
|
||||
assert!(
|
||||
pairs
|
||||
.iter()
|
||||
.any(|w| w[0] == "-p" && w[1] == "0.0.0.0:3100:3001"),
|
||||
"expected -p 0.0.0.0:3100:3001 in docker args, got: {args:?}"
|
||||
);
|
||||
assert!(
|
||||
pairs
|
||||
.iter()
|
||||
.any(|w| w[0] == "-p" && w[1] == "0.0.0.0:2200:22"),
|
||||
"expected -p 0.0.0.0:2200:22 in docker args, got: {args:?}"
|
||||
);
|
||||
assert!(
|
||||
!pairs.iter().any(|w| w[0] == "-p"
|
||||
&& (w[1].starts_with("127.0.0.1:") || w[1] == "127.0.0.1")),
|
||||
"host-side mapping must not be 127.0.0.1-restricted: {args:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpret_docker_run_error_missing_image_points_at_script() {
|
||||
let stderr = "Unable to find image 'huskies-project-rust:latest' locally\n\
|
||||
|
||||
Reference in New Issue
Block a user