Skip to content

fix(docker): support ssh:// DOCKER_HOST on WSL (#977) - #986

Merged
skevetter merged 3 commits into
mainfrom
fix/wsl-docker-doc-accuracy
Aug 18, 2026
Merged

fix(docker): support ssh:// DOCKER_HOST on WSL (#977)#986
skevetter merged 3 commits into
mainfrom
fix/wsl-docker-doc-accuracy

Conversation

@devsy-app

@devsy-app devsy-app Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the WSL2 setup instructions in the Docker provider via WSL tutorial and two underlying bugs that broke workspaces using an ssh:// Docker daemon on Windows. All three were surfaced via #977.

Technical fixes

1. Mount-path translation (EnsurePath)

Problem: pkg/driver/docker/runargs.go EnsurePath only converted Windows drive paths to their WSL /mnt/<drive> form when DOCKER_HOST was tcp://. The documented WSL setup (#977, the docker-provider-via-wsl tutorial) uses an ssh:// DOCKER_HOST pointing at a Docker daemon inside the WSL2 VM, so workspace mounts were passed through as raw Windows paths that the WSL daemon could not resolve. This caused the workspace build/tar failures the user hit before reaching the editor SSH stage.

Change:

  • Generalized remote-daemon detection in EnsurePath to any non-local DOCKER_HOST (i.e. not unix:// or npipe://), covering both tcp:// and ssh:// endpoints, via the new docker.RemoteDockerHost helper (pkg/docker/helper.go) — matching the semantics already used by pkg/agent/delivery/factory.go.
  • Extracted the path conversion into a testable windowsToWSLPath helper.
  • Added unit tests: TestWSLPathConversion, TestIsRemoteDockerHost, TestIsRemoteDockerHostEnv, plus a non-Windows no-op guard in the driver suite.

2. Agent delivery routing never checked the real DOCKER_HOST

Problem: pkg/agent/delivery/factory.go's NewAgentDelivery already had an IsRemoteDocker field that takes priority for choosing between LocalDockerDelivery (named-volume, assumes a filesystem-shared local daemon) and RemoteDockerDelivery (docker cp, for a daemon on a different host). pkg/devcontainer/setup.go's newAgentDelivery() never set it, so routing always fell through to dockerDelivery's own isDockerLocal() check — which read the ambient os.Getenv("DOCKER_HOST") instead of the workspace's resolved Agent.Docker.Env["DOCKER_HOST"] (the value actually passed to the docker subprocess calls). This is why the reporter's logs show using local docker delivery (named volume) despite DOCKER_HOST=ssh://avencod@localhost being configured and used.

In practice this rarely surfaced as a hard failure — LocalDockerDelivery.populateVolume tries a helper-container copy first, which still works over an ssh:// transport — but it silently defeated the RemoteDockerDelivery path this repo already built for non-local daemons, and would misbehave if that helper-copy fallback ever fails (it falls back to writing directly to the volume's host-filesystem mountpoint, which is unreachable from Windows for a WSL-side daemon).

Change:

  • setup.go: set IsRemoteDocker: docker.RemoteDockerHost(dockerEnv), reusing the helper added for fix Rebrand devpod/loft to devsy #1.
  • factory.go: removed the now-redundant/buggy isDockerLocal os.Getenv check — dockerDelivery is only reached once the caller has already classified the daemon as local, so there is a single source of truth for the local/remote decision.
  • setup_test.go: added TestNewAgentDelivery_RemoteDockerHostWiring (unix/unset → local, ssh/tcp → remote). Verified it fails against the pre-fix code and passes after.

Documentation

  • Step 1: lead with wsl --install (recent Windows builds), then the full manual dism path enabling both Microsoft-Windows-Subsystem-Linux and VirtualMachinePlatform, followed by wsl --set-default-version 2 (the original step only enabled WSL, not WSL2).
  • Step 2: note that Steps 3 and 5 use systemctl, which requires systemd enabled in WSL.
  • Step 8: added a callout documenting the mount-path translation behavior fix Rebrand devpod/loft to devsy #1 provides (Windows drive -> /mnt/<drive>), and that \wsl.localhost\... UNC paths are not supported for mounts.
  • New Step 9: connecting the editor over Devsy's built-in SSH tunnel, with a troubleshooting note on surfacing the structured tunnel logs behind an editor write EPIPE error via DEVSY_DEBUG=true.

Verification

  • go build ./... OK
  • go test ./pkg/driver/docker/... ./pkg/agent/delivery/... ./pkg/devcontainer/... — all existing + new tests pass
  • go vet clean, gofmt clean

Notes / follow-ups

Still out of scope here (needs Windows/WSL reproduction, not something to guess at blind): the reporter's write EPIPE from VSCodium's ProxyCommand during the IDE SSH stage. Traced the call path (workspace ssh --stdioContainerTunnel.RunrunHostTunnel/runInContainer → nested docker exec/ssh subprocess spawns, none with a console, all under a process VSCodium itself spawned with piped stdio). agent.local: true in the docker provider template is not the bug — traced agent.InjectAgent's IsLocal branch and confirmed the local path runs the outer SSH-server in-process via an emulated shell (no extra subprocess), so flipping it to "remote" for an ssh:// daemon would regress the working case, not fix it. The nesting itself (docker CLI → ssh.exe, spawned from an SSH-session-spawned subprocess, spawned from a ProxyCommand-spawned subprocess, all pipe-only stdio) is the more likely culprit, but pinning down which hop actually fails needs either:

  • DEVSY_DEBUG=true structured tunnel logs from a reporter still hitting this (requested in Step 9's troubleshooting note), or
  • a new e2e case exercising DOCKER_HOST=ssh:// (not just Podman's own machine/named-pipe transport) on the windows-latest runner already used by the up-docker-wsl label — this needs provisioning a real WSL distro with sshd + a docker daemon, which isn't in CI today and is worth tracking as its own PR rather than bundling into this one.
  • An e2e test for the ssh:// docker host path (see above) would help confirm/deny the hop.

Related issue: #977

@netlify

netlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev canceled.

Name Link
🔨 Latest commit 718396e
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a845f4ea182d20008a94423

@github-actions

Copy link
Copy Markdown

⚠️ This PR contains unsigned commits. To get your PR merged, please sign those commits (git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}) and force push them to this branch (git push --force-with-lease).

If you're new to commit signing, there are different ways to set it up:

Sign commits with gpg

Follow the steps below to set up commit signing with gpg:

  1. Generate a GPG key
  2. Add the GPG key to your GitHub account
  3. Configure git to use your GPG key for commit signing
Sign commits with ssh-agent

Follow the steps below to set up commit signing with ssh-agent:

  1. Generate an SSH key and add it to ssh-agent
  2. Add the SSH key to your GitHub account
  3. Configure git to use your SSH key for commit signing
Sign commits with 1Password

You can also sign commits using 1Password, which lets you sign commits with biometrics without the signing key leaving the local 1Password process.

Learn how to use 1Password to sign your commits.

Watch the demo

@netlify

netlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploy Preview for images-devsy-sh canceled.

Name Link
🔨 Latest commit 718396e
🔍 Latest deploy log https://app.netlify.com/projects/images-devsy-sh/deploys/6a845f4e8d1033000870a40d

@codacy-production

codacy-production Bot commented Aug 10, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 11 complexity · 1 duplication

Metric Results
Complexity 11
Duplication 1

View in Codacy

AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@github-actions github-actions Bot added size/m and removed size/xs labels Aug 11, 2026
@devsy-app devsy-app Bot changed the title docs: fix WSL2 setup steps in docker-provider-via-wsl tutorial fix(docker): support ssh:// DOCKER_HOST on WSL + WSL setup docs (#977) Aug 11, 2026
@devsy-app
devsy-app Bot force-pushed the fix/wsl-docker-doc-accuracy branch from e139954 to b40471f Compare August 11, 2026 19:11
@github-actions github-actions Bot added size/l and removed size/m labels Aug 11, 2026
@devsy-app
devsy-app Bot force-pushed the fix/wsl-docker-doc-accuracy branch from b40471f to f5974b5 Compare August 11, 2026 19:34
@skevetter
skevetter marked this pull request as draft August 14, 2026 05:00
Fixes the WSL2 setup instructions in the docker-provider-via-wsl
tutorial and two underlying bugs that broke workspaces using an
ssh:// Docker daemon on Windows.

Mount-path translation (EnsurePath):
EnsurePath only converted Windows drive paths to their WSL /mnt/<drive>
form when DOCKER_HOST was tcp://. The documented WSL setup uses an
ssh:// DOCKER_HOST pointing at a daemon inside the WSL2 VM, so
workspace mounts were passed through as raw Windows paths the WSL
daemon could not resolve, causing build/tar failures before reaching
the editor SSH stage.

- Generalized remote-daemon detection to any non-local DOCKER_HOST
  (not unix:// or npipe://) via the new docker.RemoteDockerHost
  helper, covering both tcp:// and ssh:// endpoints.
- Extracted path conversion into a testable windowsToWSLPath helper.
- Added TestWSLPathConversion, TestIsRemoteDockerHost,
  TestIsRemoteDockerHostEnv, and a non-Windows no-op guard.

Agent delivery routing never checked the real DOCKER_HOST:
NewAgentDelivery already had an IsRemoteDocker field that takes
priority when choosing between LocalDockerDelivery (named-volume,
assumes a filesystem-shared local daemon) and RemoteDockerDelivery
(docker cp, for a daemon on a different host), but setup.go's
newAgentDelivery() never set it. Routing fell through to
dockerDelivery's own isDockerLocal(), which read the ambient
os.Getenv("DOCKER_HOST") instead of the workspace's resolved
Agent.Docker.Env["DOCKER_HOST"] actually used for docker subprocess
calls -- explaining logs showing "using local docker delivery (named
volume)" despite DOCKER_HOST=ssh://... being configured.

- setup.go: set IsRemoteDocker via docker.RemoteDockerHost(dockerEnv).
- factory.go: removed the redundant/buggy isDockerLocal check; routing
  is decided once, at the call site, from the real env.
- setup_test.go: added TestNewAgentDelivery_RemoteDockerHostWiring
  covering unix/unset (local) and ssh/tcp (remote) DOCKER_HOST cases.

Documentation (docker-provider-via-wsl.mdx):
- Step 1: lead with wsl --install, then the full manual dism path
  enabling both Microsoft-Windows-Subsystem-Linux and
  VirtualMachinePlatform, followed by wsl --set-default-version 2.
- Step 2: note Steps 3 and 5 require systemd enabled in WSL.
- Step 8: document the mount-path translation behavior and that
  \\wsl.localhost\... UNC paths are not supported for mounts.
- New Step 9: connecting the editor over Devsy's built-in SSH tunnel,
  with a troubleshooting note on DEVSY_DEBUG=true for the editor
  write EPIPE error.

Verification: go build ./... OK; go test ./pkg/driver/docker/...
./pkg/agent/delivery/... ./pkg/devcontainer/... all pass; go vet and
gofmt clean.

Related issue: #977
@skevetter
skevetter force-pushed the fix/wsl-docker-doc-accuracy branch from 9d0387b to 4474db1 Compare August 18, 2026 05:02
@skevetter
skevetter marked this pull request as ready for review August 18, 2026 05:57
@skevetter skevetter changed the title fix(docker): support ssh:// DOCKER_HOST on WSL + WSL setup docs (#977) fix(docker): support ssh:// DOCKER_HOST on WSL (#977) Aug 18, 2026
@mergify

mergify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Signed-off-by: Samuel K <skevetter@pm.me>
@skevetter
skevetter merged commit c829cc6 into main Aug 18, 2026
78 checks passed
@skevetter
skevetter deleted the fix/wsl-docker-doc-accuracy branch August 18, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant