From 5925108bcd0db8d4e5cd3cf44c3ea71bdd3c081f Mon Sep 17 00:00:00 2001 From: Akram Date: Mon, 1 Jun 2026 15:31:45 +0200 Subject: [PATCH] fix(docker): route macOS callbacks via host-gateway On macOS, Docker-compatible runtimes keep bridge networking inside a VM. Binding the gateway listener to the bridge gateway IP (e.g. Podman machine at 10.89.0.1) fails with EADDRNOTAVAIL. Always use host-gateway aliases for docker-driver callback routing on macOS hosts. Add docker_gateway_route unit tests for the OpenShell issue 1358 regression, including Podman-machine-style daemon info. Signed-off-by: Akram --- crates/openshell-driver-docker/src/lib.rs | 9 +++ crates/openshell-driver-docker/src/tests.rs | 62 ++++++++++++++++----- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/crates/openshell-driver-docker/src/lib.rs b/crates/openshell-driver-docker/src/lib.rs index 2ce652bee..214de6ca7 100644 --- a/crates/openshell-driver-docker/src/lib.rs +++ b/crates/openshell-driver-docker/src/lib.rs @@ -1914,6 +1914,15 @@ fn host_runtime_requires_host_gateway_alias() -> bool { /// Each runtime is detected via the daemon's reported OS string or hostname, /// supplemented by labels where the runtime publishes them. fn uses_host_gateway_alias(info: &SystemInfo) -> bool { + // On macOS, Docker-compatible runtimes (Docker Desktop, Colima, Podman + // machine, etc.) run Linux networking inside a VM. The bridge gateway IP is + // therefore not assigned on the host interface where the gateway process + // runs, so binding the gateway listener to that IP fails with + // EADDRNOTAVAIL. Always route callbacks via host-gateway aliases. + if cfg!(target_os = "macos") { + return true; + } + let operating_system = info .operating_system .as_deref() diff --git a/crates/openshell-driver-docker/src/tests.rs b/crates/openshell-driver-docker/src/tests.rs index cbc5130a4..d8945db84 100644 --- a/crates/openshell-driver-docker/src/tests.rs +++ b/crates/openshell-driver-docker/src/tests.rs @@ -282,20 +282,56 @@ fn docker_gateway_route_uses_bridge_gateway_for_linux_docker() { false, ); - assert_eq!( - route, - DockerGatewayRoute::Bridge { - bind_address: "172.18.0.1:17670".parse().unwrap(), - host_alias_ip: IpAddr::V4(Ipv4Addr::new(172, 18, 0, 1)), - } - ); - assert_eq!( - docker_extra_hosts(&route), - vec![ - "host.docker.internal:172.18.0.1".to_string(), - "host.openshell.internal:172.18.0.1".to_string() - ] + if cfg!(target_os = "macos") { + assert_eq!(route, DockerGatewayRoute::HostGateway); + assert_eq!( + docker_extra_hosts(&route), + vec![ + "host.docker.internal:host-gateway".to_string(), + "host.openshell.internal:host-gateway".to_string() + ] + ); + } else { + assert_eq!( + route, + DockerGatewayRoute::Bridge { + bind_address: "172.18.0.1:17670".parse().unwrap(), + host_alias_ip: IpAddr::V4(Ipv4Addr::new(172, 18, 0, 1)), + } + ); + assert_eq!( + docker_extra_hosts(&route), + vec![ + "host.docker.internal:172.18.0.1".to_string(), + "host.openshell.internal:172.18.0.1".to_string() + ] + ); + } +} + +// Regression for macOS + OPENSHELL_DRIVERS=docker against a Podman-machine socket +// (OpenShell issue #1358): the daemon looks like generic Linux, but the bridge +// gateway IP only exists inside the VM. Binding it on the host fails with +// EADDRNOTAVAIL during gateway startup. +#[test] +#[cfg(target_os = "macos")] +fn docker_gateway_route_uses_host_gateway_for_podman_machine_on_macos() { + let info = SystemInfo { + // Observed values when docker CLI talks to podman machine API. + operating_system: Some("fedora".to_string()), + name: Some("localhost.localdomain".to_string()), + labels: None, + ..Default::default() + }; + + let route = docker_gateway_route( + &info, + // Typical Podman machine bridge gateway; not routable on the macOS host. + IpAddr::V4(Ipv4Addr::new(10, 89, 0, 1)), + DEFAULT_SERVER_PORT, + None, ); + assert_eq!(route, DockerGatewayRoute::HostGateway); } #[test]