Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions crates/openshell-driver-docker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ fn docker_gateway_route(
};
}

if is_docker_desktop(info) {
if is_vm_dockerd_runtime(info) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why include "vm" here? This is just a docker (and compatible alternatives) check, right?

DockerGatewayRoute::HostGateway
} else {
DockerGatewayRoute::Bridge {
Expand All @@ -1109,7 +1109,17 @@ fn docker_gateway_route(
}
}

fn is_docker_desktop(info: &SystemInfo) -> bool {
/// Detect Docker daemons that ship a bridge network inside a host VM rather
/// than on the host itself. Their bridge gateway IP is reachable from inside
/// containers but not from the `OpenShell` server process running on the host,
/// so callbacks must traverse `host-gateway`.
///
/// Covers Docker Desktop on macOS/Windows and the common community VM-Docker
/// runtimes on macOS (and Lima-backed runtimes on Linux): Colima, Lima,
/// Rancher Desktop, and `OrbStack`. Each is detected via the daemon's
/// reported OS string or hostname, supplemented by labels where the runtime
/// publishes them.
fn is_vm_dockerd_runtime(info: &SystemInfo) -> bool {
let operating_system = info
.operating_system
.as_deref()
Expand All @@ -1119,10 +1129,25 @@ fn is_docker_desktop(info: &SystemInfo) -> bool {
return true;
}

let name = info
.name
.as_deref()
.unwrap_or_default()
.to_ascii_lowercase();
if name.starts_with("colima")
|| name.starts_with("lima-")
|| name.starts_with("rancher-desktop")
|| name.starts_with("orbstack")
{
return true;
}

info.labels.as_ref().is_some_and(|labels| {
labels
.iter()
.any(|label| label.starts_with("com.docker.desktop."))
labels.iter().any(|label| {
label.starts_with("com.docker.desktop.")
|| label.starts_with("dev.rancherdesktop.")
|| label.starts_with("dev.orbstack.")
})
})
}

Expand Down
82 changes: 82 additions & 0 deletions crates/openshell-driver-docker/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,88 @@ fn docker_gateway_route_uses_host_gateway_for_docker_desktop() {
);
}

#[test]
fn docker_gateway_route_uses_host_gateway_for_colima() {
let info = SystemInfo {
operating_system: Some("Ubuntu 24.04 LTS".to_string()),
name: Some("colima".to_string()),
..Default::default()
};

assert_eq!(
docker_gateway_route(
&info,
IpAddr::V4(Ipv4Addr::new(172, 18, 0, 1)),
DEFAULT_SERVER_PORT,
None,
),
DockerGatewayRoute::HostGateway
);
}

#[test]
fn docker_gateway_route_uses_host_gateway_for_colima_named_profile() {
let info = SystemInfo {
operating_system: Some("Ubuntu 24.04 LTS".to_string()),
// `colima start --profile <name>` sets the daemon hostname to
// `colima-<name>`; the prefix match still catches it.
name: Some("colima-default".to_string()),
..Default::default()
};

assert_eq!(
docker_gateway_route(
&info,
IpAddr::V4(Ipv4Addr::new(172, 18, 0, 1)),
DEFAULT_SERVER_PORT,
None,
),
DockerGatewayRoute::HostGateway
);
}

#[test]
fn docker_gateway_route_uses_host_gateway_for_rancher_desktop() {
let info = SystemInfo {
operating_system: Some("Alpine Linux v3.20".to_string()),
name: Some("lima-rancher-desktop".to_string()),
labels: Some(vec![
"dev.rancherdesktop.profile=Rancher Desktop".to_string(),
]),
..Default::default()
};

assert_eq!(
docker_gateway_route(
&info,
IpAddr::V4(Ipv4Addr::new(172, 18, 0, 1)),
DEFAULT_SERVER_PORT,
None,
),
DockerGatewayRoute::HostGateway
);
}

#[test]
fn docker_gateway_route_uses_host_gateway_for_orbstack() {
let info = SystemInfo {
operating_system: Some("OrbStack".to_string()),
name: Some("orbstack".to_string()),
labels: Some(vec!["dev.orbstack.machine_type=docker".to_string()]),
..Default::default()
};

assert_eq!(
docker_gateway_route(
&info,
IpAddr::V4(Ipv4Addr::new(172, 18, 0, 1)),
DEFAULT_SERVER_PORT,
None,
),
DockerGatewayRoute::HostGateway
);
}

#[test]
fn docker_gateway_route_uses_bridge_gateway_for_linux_docker() {
let info = SystemInfo {
Expand Down
Loading