From 9127023c91f2d400ea4020223d7eb23fc34d653d Mon Sep 17 00:00:00 2001 From: Tinson Lai Date: Thu, 6 Aug 2026 12:58:00 +0000 Subject: [PATCH 1/3] fix(onboard): name the advisory identifier in preflight remediation output Signed-off-by: Tinson Lai --- docs/reference/troubleshooting.mdx | 1 + src/lib/onboard/preflight-docker-host.test.ts | 26 ++++++++++++++++++- src/lib/onboard/remediation.ts | 8 ++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/reference/troubleshooting.mdx b/docs/reference/troubleshooting.mdx index 09ab640bd8d..28131d2d270 100644 --- a/docs/reference/troubleshooting.mdx +++ b/docs/reference/troubleshooting.mdx @@ -137,6 +137,7 @@ It rejects remote endpoints and relative socket paths before service startup. ### Onboarding Reports an Invalid Docker Host The `invalid_docker_host` advisory means that `DOCKER_HOST` is not an absolute local `unix://` socket path that NemoClaw can write to the managed OpenShell gateway service environment. +Onboarding prints each advisory identifier in parentheses after the suggested-fix title, so the terminal output names the advisory you look up here. NemoClaw does not use the standalone gateway fallback when this validation fails. Remove the override to use Docker's default local socket: diff --git a/src/lib/onboard/preflight-docker-host.test.ts b/src/lib/onboard/preflight-docker-host.test.ts index 9fb0ec8d443..2a2111ecfd0 100644 --- a/src/lib/onboard/preflight-docker-host.test.ts +++ b/src/lib/onboard/preflight-docker-host.test.ts @@ -1,15 +1,39 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { assessHost, planHostRemediation } from "./preflight"; +import { printRemediationActions } from "./remediation"; // Regression: NemoClaw #7731. This invalid TCP endpoint makes `docker info` // fail, but the local docker.service is still active. Preflight used to emit // the docker-group remediation. The host assessment now flags the invalid // DOCKER_HOST so onboarding names it instead. describe("assessHost invalid DOCKER_HOST (#7731)", () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("names the advisory identifier in the printed remediation so output matches the docs", () => { + const assessment = assessHost({ + platform: "linux", + env: { DOCKER_HOST: "tcp://203.0.113.10:2375" }, + dockerInfoOutput: "", + commandExistsImpl: (name: string) => name === "docker" || name === "systemctl", + runCaptureImpl: (command: readonly string[]) => + command.includes("is-active") ? "active" : "", + }); + + const err = vi.spyOn(console, "error").mockImplementation(() => undefined); + printRemediationActions(planHostRemediation(assessment)); + const output = err.mock.calls.map((call: unknown[]) => String(call[0])).join("\n"); + + expect(output).toContain("Fix the DOCKER_HOST endpoint (invalid_docker_host):"); + expect(output).toContain("unset DOCKER_HOST"); + expect(output).not.toContain("docker_group_permission"); + }); + it("flags an invalid DOCKER_HOST so onboarding names the endpoint, not a docker-group fix", () => { const assessment = assessHost({ platform: "linux", diff --git a/src/lib/onboard/remediation.ts b/src/lib/onboard/remediation.ts index 65ba6fdb5f5..4da860139c5 100644 --- a/src/lib/onboard/remediation.ts +++ b/src/lib/onboard/remediation.ts @@ -6,7 +6,10 @@ import path from "node:path"; const OPENCLAW_LAUNCH_AGENT_PLIST = "~/Library/LaunchAgents/ai.openclaw.gateway.plist"; export function printRemediationActions( - actions: Array<{ title: string; reason: string; commands?: string[] }> | null | undefined, + actions: + | Array<{ id?: string; title: string; reason: string; commands?: string[] }> + | null + | undefined, ): void { if (!Array.isArray(actions) || actions.length === 0) { return; @@ -16,7 +19,8 @@ export function printRemediationActions( console.error(" Suggested fix:"); console.error(""); for (const action of actions) { - console.error(` - ${action.title}: ${action.reason}`); + const label = action.id ? `${action.title} (${action.id})` : action.title; + console.error(` - ${label}: ${action.reason}`); for (const command of action.commands || []) { console.error(` ${command}`); } From a8561a8f3bb83209a19523e7d8c6ae93161c1637 Mon Sep 17 00:00:00 2001 From: Tinson Lai Date: Thu, 6 Aug 2026 13:07:45 +0000 Subject: [PATCH 2/3] refactor(onboard): require the advisory identifier in remediation output Signed-off-by: Tinson Lai --- docs/reference/troubleshooting.mdx | 3 +- src/lib/onboard/preflight-docker-host.test.ts | 38 ++++++++++--------- src/lib/onboard/remediation.ts | 5 +-- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/reference/troubleshooting.mdx b/docs/reference/troubleshooting.mdx index 28131d2d270..3243fee43e9 100644 --- a/docs/reference/troubleshooting.mdx +++ b/docs/reference/troubleshooting.mdx @@ -137,8 +137,9 @@ It rejects remote endpoints and relative socket paths before service startup. ### Onboarding Reports an Invalid Docker Host The `invalid_docker_host` advisory means that `DOCKER_HOST` is not an absolute local `unix://` socket path that NemoClaw can write to the managed OpenShell gateway service environment. -Onboarding prints each advisory identifier in parentheses after the suggested-fix title, so the terminal output names the advisory you look up here. NemoClaw does not use the standalone gateway fallback when this validation fails. +Onboarding prints the advisory identifier in parentheses after each action title in the `Suggested fix` list. +The terminal output names `invalid_docker_host` when this validation fails, so you can match the message to this section. Remove the override to use Docker's default local socket: ```bash diff --git a/src/lib/onboard/preflight-docker-host.test.ts b/src/lib/onboard/preflight-docker-host.test.ts index 2a2111ecfd0..70181e96741 100644 --- a/src/lib/onboard/preflight-docker-host.test.ts +++ b/src/lib/onboard/preflight-docker-host.test.ts @@ -11,27 +11,29 @@ import { printRemediationActions } from "./remediation"; // the docker-group remediation. The host assessment now flags the invalid // DOCKER_HOST so onboarding names it instead. describe("assessHost invalid DOCKER_HOST (#7731)", () => { - afterEach(() => { - vi.restoreAllMocks(); - }); - - it("names the advisory identifier in the printed remediation so output matches the docs", () => { - const assessment = assessHost({ - platform: "linux", - env: { DOCKER_HOST: "tcp://203.0.113.10:2375" }, - dockerInfoOutput: "", - commandExistsImpl: (name: string) => name === "docker" || name === "systemctl", - runCaptureImpl: (command: readonly string[]) => - command.includes("is-active") ? "active" : "", + describe("printRemediationActions", () => { + afterEach(() => { + vi.restoreAllMocks(); }); - const err = vi.spyOn(console, "error").mockImplementation(() => undefined); - printRemediationActions(planHostRemediation(assessment)); - const output = err.mock.calls.map((call: unknown[]) => String(call[0])).join("\n"); + it("prints the advisory identifier after the remediation title", () => { + const assessment = assessHost({ + platform: "linux", + env: { DOCKER_HOST: "tcp://203.0.113.10:2375" }, + dockerInfoOutput: "", + commandExistsImpl: (name: string) => name === "docker" || name === "systemctl", + runCaptureImpl: (command: readonly string[]) => + command.includes("is-active") ? "active" : "", + }); - expect(output).toContain("Fix the DOCKER_HOST endpoint (invalid_docker_host):"); - expect(output).toContain("unset DOCKER_HOST"); - expect(output).not.toContain("docker_group_permission"); + const err = vi.spyOn(console, "error").mockImplementation(() => undefined); + printRemediationActions(planHostRemediation(assessment)); + const output = err.mock.calls.map((call: unknown[]) => String(call[0])).join("\n"); + + expect(output).toContain("Fix the DOCKER_HOST endpoint (invalid_docker_host):"); + expect(output).toContain("unset DOCKER_HOST"); + expect(output).not.toContain("docker_group_permission"); + }); }); it("flags an invalid DOCKER_HOST so onboarding names the endpoint, not a docker-group fix", () => { diff --git a/src/lib/onboard/remediation.ts b/src/lib/onboard/remediation.ts index 4da860139c5..6ecc2514529 100644 --- a/src/lib/onboard/remediation.ts +++ b/src/lib/onboard/remediation.ts @@ -7,7 +7,7 @@ const OPENCLAW_LAUNCH_AGENT_PLIST = "~/Library/LaunchAgents/ai.openclaw.gateway. export function printRemediationActions( actions: - | Array<{ id?: string; title: string; reason: string; commands?: string[] }> + | Array<{ id: string; title: string; reason: string; commands?: string[] }> | null | undefined, ): void { @@ -19,8 +19,7 @@ export function printRemediationActions( console.error(" Suggested fix:"); console.error(""); for (const action of actions) { - const label = action.id ? `${action.title} (${action.id})` : action.title; - console.error(` - ${label}: ${action.reason}`); + console.error(` - ${action.title} (${action.id}): ${action.reason}`); for (const command of action.commands || []) { console.error(` ${command}`); } From b3dfbd1893b3cd6c89203fd9362011aaec1f51dc Mon Sep 17 00:00:00 2001 From: Apurv Kumaria Date: Thu, 6 Aug 2026 06:57:52 -0700 Subject: [PATCH 3/3] test(onboard): cover invalid Docker host remediation Signed-off-by: Apurv Kumaria --- src/lib/onboard/preflight-docker-host.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/onboard/preflight-docker-host.test.ts b/src/lib/onboard/preflight-docker-host.test.ts index 70181e96741..05a828e892a 100644 --- a/src/lib/onboard/preflight-docker-host.test.ts +++ b/src/lib/onboard/preflight-docker-host.test.ts @@ -32,7 +32,9 @@ describe("assessHost invalid DOCKER_HOST (#7731)", () => { expect(output).toContain("Fix the DOCKER_HOST endpoint (invalid_docker_host):"); expect(output).toContain("unset DOCKER_HOST"); + expect(output).toContain("unix:///var/run/docker.sock"); expect(output).not.toContain("docker_group_permission"); + expect(output).not.toContain("start_docker"); }); });