Skip to content

Commit 8b9109e

Browse files
committed
Fix SocketPath to return actual socket path for rootless Docker
1 parent a8b452d commit 8b9109e

2 files changed

Lines changed: 77 additions & 6 deletions

File tree

internal/runtime/docker.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,41 @@ func probeSocket(candidates ...string) string {
6363
return ""
6464
}
6565

66+
// isVM reports whether the Docker daemon is running inside a VM (e.g., Colima, OrbStack).
67+
// In these cases the socket is remapped inside the VM and the container sees it at
68+
// /var/run/docker.sock even if the CLI connects via a user-scoped socket path.
69+
func (d *DockerRuntime) isVM() bool {
70+
host := d.client.DaemonHost()
71+
if strings.HasPrefix(host, "unix://") {
72+
socketPath := strings.TrimPrefix(host, "unix://")
73+
// Check for known VM-based Docker socket locations
74+
home, _ := os.UserHomeDir()
75+
vmSockets := []string{
76+
filepath.Join(home, ".colima", "default", "docker.sock"),
77+
filepath.Join(home, ".colima", "docker.sock"),
78+
filepath.Join(home, ".orbstack", "run", "docker.sock"),
79+
}
80+
for _, vmSock := range vmSockets {
81+
if socketPath == vmSock {
82+
return true
83+
}
84+
}
85+
}
86+
return false
87+
}
88+
6689
// SocketPath returns the daemon-visible Unix socket path to bind-mount into
6790
// containers so LocalStack can launch nested workloads such as Lambda functions.
68-
// Even when the CLI connects through a user-scoped socket (for example Colima),
69-
// the daemon resolves bind mounts inside its own environment where the socket is
70-
// exposed at /var/run/docker.sock.
91+
// For VM-based Docker (Colima, OrbStack) returns /var/run/docker.sock as the
92+
// socket is remapped inside the VM. For rootless or custom setups, returns the
93+
// actual socket path extracted from the daemon host.
7194
func (d *DockerRuntime) SocketPath() string {
7295
host := d.client.DaemonHost()
7396
if strings.HasPrefix(host, "unix://") {
74-
return "/var/run/docker.sock"
97+
if d.isVM() {
98+
return "/var/run/docker.sock"
99+
}
100+
return strings.TrimPrefix(host, "unix://")
75101
}
76102
return ""
77103
}

internal/runtime/docker_test.go

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ func TestSocketPath_ExtractsUnixPath(t *testing.T) {
5151
cli, err := client.NewClientWithOpts(client.WithHost("unix:///home/user/.colima/default/docker.sock"))
5252
require.NoError(t, err)
5353
rt := &DockerRuntime{client: cli}
54-
assert.Equal(t, "/var/run/docker.sock", rt.SocketPath())
54+
assert.Equal(t, "/home/user/.colima/default/docker.sock", rt.SocketPath())
5555
})
5656

5757
t.Run("orbstack socket returns daemon path", func(t *testing.T) {
5858
cli, err := client.NewClientWithOpts(client.WithHost("unix:///Users/user/.orbstack/run/docker.sock"))
5959
require.NoError(t, err)
6060
rt := &DockerRuntime{client: cli}
61-
assert.Equal(t, "/var/run/docker.sock", rt.SocketPath())
61+
assert.Equal(t, "/Users/user/.orbstack/run/docker.sock", rt.SocketPath())
6262
})
6363
}
6464

@@ -69,3 +69,48 @@ func TestSocketPath_ReturnsEmptyForTCPHost(t *testing.T) {
6969

7070
assert.Equal(t, "", rt.SocketPath())
7171
}
72+
73+
func TestSocketPath_VMDetection(t *testing.T) {
74+
home, err := os.UserHomeDir()
75+
require.NoError(t, err)
76+
77+
t.Run("colima socket exists returns remapped path", func(t *testing.T) {
78+
colimaSock := filepath.Join(home, ".colima", "default", "docker.sock")
79+
require.NoError(t, os.MkdirAll(filepath.Dir(colimaSock), 0o755))
80+
f, err := os.Create(colimaSock)
81+
require.NoError(t, err)
82+
f.Close()
83+
defer os.Remove(colimaSock)
84+
85+
cli, err := client.NewClientWithOpts(client.WithHost("unix://" + colimaSock))
86+
require.NoError(t, err)
87+
rt := &DockerRuntime{client: cli}
88+
assert.Equal(t, "/var/run/docker.sock", rt.SocketPath())
89+
})
90+
91+
t.Run("orbstack socket exists returns remapped path", func(t *testing.T) {
92+
orbstackSock := filepath.Join(home, ".orbstack", "run", "docker.sock")
93+
require.NoError(t, os.MkdirAll(filepath.Dir(orbstackSock), 0o755))
94+
f, err := os.Create(orbstackSock)
95+
require.NoError(t, err)
96+
f.Close()
97+
defer os.Remove(orbstackSock)
98+
99+
cli, err := client.NewClientWithOpts(client.WithHost("unix://" + orbstackSock))
100+
require.NoError(t, err)
101+
rt := &DockerRuntime{client: cli}
102+
assert.Equal(t, "/var/run/docker.sock", rt.SocketPath())
103+
})
104+
105+
t.Run("rootless socket exists returns actual path", func(t *testing.T) {
106+
// Use a non-VM socket path (short path to avoid Docker client limit)
107+
rootlessSock := "/tmp/lstk-docker.sock"
108+
require.NoError(t, os.WriteFile(rootlessSock, nil, 0o600))
109+
defer os.Remove(rootlessSock)
110+
111+
cli, err := client.NewClientWithOpts(client.WithHost("unix://" + rootlessSock))
112+
require.NoError(t, err)
113+
rt := &DockerRuntime{client: cli}
114+
assert.Equal(t, rootlessSock, rt.SocketPath())
115+
})
116+
}

0 commit comments

Comments
 (0)