From bef2c9b1c52dc5088e8c40b2b08ed3358fa49bb5 Mon Sep 17 00:00:00 2001 From: Deepak Jain Date: Wed, 27 May 2026 09:16:29 -0700 Subject: [PATCH] fix(onboard): explain Docker Desktop WSL integration gaps Fixes #4301 Signed-off-by: Deepak Jain --- src/lib/onboard/preflight.test.ts | 68 +++++++++++++++++++++++++++++++ src/lib/onboard/preflight.ts | 37 +++++++++++++++-- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/lib/onboard/preflight.test.ts b/src/lib/onboard/preflight.test.ts index 8381a67ecc1..b71bbea7f1a 100644 --- a/src/lib/onboard/preflight.test.ts +++ b/src/lib/onboard/preflight.test.ts @@ -843,6 +843,38 @@ describe("getNvidiaCdiSpecPath", () => { }); describe("planHostRemediation", () => { + function baseAssessment( + overrides: Partial[0]> = {}, + ): Parameters[0] { + return { + platform: "linux", + isWsl: false, + runtime: "unknown", + packageManager: "apt", + systemctlAvailable: true, + dockerServiceActive: null, + dockerServiceEnabled: null, + dockerInstalled: true, + dockerRunning: false, + dockerReachable: false, + nodeInstalled: true, + openshellInstalled: true, + dockerCgroupVersion: "unknown", + dockerDefaultCgroupnsMode: "unknown", + isContainerRuntimeUnderProvisioned: false, + hasNestedOverlayConflict: false, + requiresHostCgroupnsFix: false, + isUnsupportedRuntime: false, + isHeadlessLikely: false, + hasNvidiaGpu: false, + dockerCdiSpecDirs: [], + cdiNvidiaGpuSpecMissing: false, + nvidiaContainerToolkitInstalled: true, + notes: [], + ...overrides, + }; + } + it("recommends starting docker when installed but unreachable and service inactive", () => { const actions = planHostRemediation({ platform: "linux", @@ -876,6 +908,42 @@ describe("planHostRemediation", () => { expect(actions[0].commands).toContain("sudo systemctl start docker"); }); + it("recommends Docker Desktop WSL integration when docker is missing inside WSL", () => { + const actions = planHostRemediation( + baseAssessment({ + isWsl: true, + dockerInstalled: false, + systemctlAvailable: false, + }), + ); + + expect(actions[0].id).toBe("enable_docker_desktop_wsl_integration"); + expect(actions[0].title).toBe("Enable Docker Desktop WSL integration"); + expect(actions[0].blocking).toBe(true); + expect(actions[0].commands.join("\n")).toContain( + "Docker Desktop → Settings → Resources → WSL integration", + ); + expect(actions[0].commands.join("\n")).toContain("wsl --shutdown"); + expect(actions[0].commands.join("\n")).toContain("docker info"); + }); + + it("recommends Docker Desktop WSL integration when docker is unreachable inside WSL", () => { + const actions = planHostRemediation( + baseAssessment({ + isWsl: true, + dockerInstalled: true, + dockerServiceActive: true, + systemctlAvailable: false, + }), + ); + + expect(actions[0].id).toBe("enable_docker_desktop_wsl_integration"); + expect(actions[0].reason).toContain("WSL distro cannot reach the Docker daemon"); + expect(actions[0].commands.join("\n")).toContain("Start Docker Desktop"); + expect(actions[0].commands.join("\n")).toContain("wsl --shutdown"); + expect(actions[0].commands.join("\n")).not.toContain("sudo systemctl start docker"); + }); + it("suggests usermod when docker service is active but daemon is unreachable", () => { const actions = planHostRemediation({ platform: "linux", diff --git a/src/lib/onboard/preflight.ts b/src/lib/onboard/preflight.ts index 186769be8c9..0739ee60554 100644 --- a/src/lib/onboard/preflight.ts +++ b/src/lib/onboard/preflight.ts @@ -658,6 +658,23 @@ export function planHostRemediation(assessment: HostAssessment): RemediationActi const actions: RemediationAction[] = []; if (!assessment.dockerInstalled) { + if (assessment.isWsl) { + actions.push({ + id: "enable_docker_desktop_wsl_integration", + title: "Enable Docker Desktop WSL integration", + kind: "manual", + reason: + "Docker is not available inside this WSL distro. When using Docker Desktop on Windows, WSL integration must be enabled for the Ubuntu distro before NemoClaw can create a gateway or sandbox.", + commands: [ + "Open Docker Desktop → Settings → Resources → WSL integration.", + "Enable integration for this Ubuntu distro, apply the change, then run `wsl --shutdown` from Windows PowerShell.", + "Reopen Ubuntu, verify `docker info`, then rerun `nemoclaw onboard`.", + ], + blocking: true, + }); + return actions; + } + const installCommands: Record = { apt: "Install Docker Engine, then rerun `nemoclaw onboard`.", dnf: "Install Docker Engine with your package manager, then rerun `nemoclaw onboard`.", @@ -684,15 +701,27 @@ export function planHostRemediation(assessment: HostAssessment): RemediationActi const likelyGroupIssue = assessment.platform === "linux" && assessment.dockerServiceActive === true; - if (likelyGroupIssue) { + if (assessment.isWsl) { + actions.push({ + id: "enable_docker_desktop_wsl_integration", + title: "Enable Docker Desktop WSL integration", + kind: "manual", + reason: + "Docker is installed but this WSL distro cannot reach the Docker daemon. Docker Desktop may not be running, or WSL integration may be disabled for this distro.", + commands: [ + "Start Docker Desktop on Windows.", + "Open Docker Desktop → Settings → Resources → WSL integration and enable integration for this Ubuntu distro.", + "Apply the change, run `wsl --shutdown` from Windows PowerShell, reopen Ubuntu, verify `docker info`, then rerun `nemoclaw onboard`.", + ], + blocking: true, + }); + return actions; + } else if (likelyGroupIssue) { const commands = [ "sudo usermod -aG docker $USER", "newgrp docker # or log out and back in", "nemoclaw onboard", ]; - if (assessment.isWsl) { - commands.unshift(DOCKER_DESKTOP_WSL_INTEGRATION_HINT); - } actions.push({ id: "docker_group_permission", title: "Add user to docker group",