Skip to content
Merged
17 changes: 17 additions & 0 deletions nemoclaw/src/blueprint/runner-mock-fixtures.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, it } from "vitest";

import { createRunnerFsStore, inMemoryFsMethods } from "./runner-mock-fixtures.js";

describe("blueprint runner mock fixtures", () => {
it("uses direct filesystem methods when no spy wrapper is supplied", () => {
const { store } = createRunnerFsStore();
const memory = inMemoryFsMethods(store);

expect(memory.existsSync("/sandbox")).toBe(false);
memory.mkdirSync("/sandbox");
expect(memory.existsSync("/sandbox")).toBe(true);
});
});
1 change: 1 addition & 0 deletions src/lib/onboard/managed-startup-profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ const STOCK_RUNTIME_INPUT_AGENTS = {
NEMOCLAW_HERMES_DASHBOARD_INTERNAL_PORT: ["hermes"],
NEMOCLAW_HERMES_DASHBOARD_PORT: ["hermes"],
NEMOCLAW_HERMES_DASHBOARD_TUI: ["hermes"],
NEMOCLAW_MCP_SHADOW_DIAGNOSTICS: ["openclaw"],
NEMOCLAW_MINIMAL_BOOTSTRAP: ["openclaw"],
NEMOCLAW_MCP_TOOLS_LIST_TIMEOUT_MS: ["openclaw"],
NEMOCLAW_OBSERVABILITY: ["langchain-deepagents-code"],
Expand Down
22 changes: 22 additions & 0 deletions src/lib/onboard/managed-startup/docker-root-apply.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ describe("Docker managed-startup root applicator", () => {
environment: {
NEMOCLAW_AUTO_PAIR_FAST_REENTRY_INTERVAL_SECS: " 0.25 ",
NEMOCLAW_AUTO_PAIR_FAST_REENTRY_POLLS: "03",
NEMOCLAW_MCP_SHADOW_DIAGNOSTICS: " 1 ",
NEMOCLAW_MCP_TOOLS_LIST_TIMEOUT_MS: "5000",
NEMOCLAW_NOT_AN_APPLICATION_RUNTIME_INPUT: "must-not-cross",
},
Expand All @@ -144,10 +145,31 @@ describe("Docker managed-startup root applicator", () => {
const [argv] = dockerSpawnSync.mock.calls[0] as unknown as [string[]];
expect(argv).toContain("NEMOCLAW_AUTO_PAIR_FAST_REENTRY_INTERVAL_SECS= 0.25 ");
expect(argv).toContain("NEMOCLAW_AUTO_PAIR_FAST_REENTRY_POLLS=03");
expect(argv).toContain("NEMOCLAW_MCP_SHADOW_DIAGNOSTICS=1");
expect(argv).toContain("NEMOCLAW_MCP_TOOLS_LIST_TIMEOUT_MS=5000");
expect(argv.join("\n")).not.toContain("NEMOCLAW_NOT_AN_APPLICATION_RUNTIME_INPUT");
});

it("omits an unsupported MCP shadow diagnostics value from the clean root exec", () => {
const dockerSpawnSync = vi.fn(() => successfulSpawnResult());

applyDockerManagedStartupRootRequest(
{ containerId: CONTAINER_ID, request: requestFor("openclaw") },
{
dockerCapture: vi.fn(() => stableInspect()),
dockerSpawnSync,
environment: {
NEMOCLAW_MCP_SHADOW_DIAGNOSTICS: "true",
NEMOCLAW_MCP_TOOLS_LIST_TIMEOUT_MS: "5000",
},
},
);

const [argv] = dockerSpawnSync.mock.calls[0] as unknown as [string[]];
expect(argv.join("\n")).not.toContain("NEMOCLAW_MCP_SHADOW_DIAGNOSTICS=");
expect(argv).toContain("NEMOCLAW_MCP_TOOLS_LIST_TIMEOUT_MS=5000");
});

it("retries one lost acknowledgement with the identical pinned command and payload", () => {
const request = requestFor("openclaw");
const dockerSpawnSync = vi
Expand Down
5 changes: 5 additions & 0 deletions src/lib/onboard/managed-startup/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,11 @@ export const MANAGED_STARTUP_PROFILE_DEFERRED_RUNTIME_INPUTS = Object.freeze({
"application-environment",
"operator scheduler tuning is applied by the application environment transaction",
),
deferredRuntimeInput(
"NEMOCLAW_MCP_SHADOW_DIAGNOSTICS",
"application-environment",
"operator shadow-diagnostics tuning is applied by the application environment transaction",
),
deferredRuntimeInput(
"NEMOCLAW_MCP_TOOLS_LIST_TIMEOUT_MS",
"application-environment",
Expand Down
28 changes: 28 additions & 0 deletions src/lib/onboard/managed-startup/root-apply.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, it } from "vitest";

import { selectManagedStartupApplicationRuntimeEnvironment } from "./root-apply";

describe("managed startup root application environment", () => {
it("canonicalizes the enabled MCP shadow diagnostics value", () => {
expect(
selectManagedStartupApplicationRuntimeEnvironment({
NEMOCLAW_MCP_SHADOW_DIAGNOSTICS: " 1 ",
}),
).toEqual({ NEMOCLAW_MCP_SHADOW_DIAGNOSTICS: "1" });
});

it.each(["true", "0", " "])("omits unsupported MCP shadow diagnostics value %j", (value) => {
expect(
selectManagedStartupApplicationRuntimeEnvironment({
NEMOCLAW_MCP_SHADOW_DIAGNOSTICS: value,
}),
).toEqual({});
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

it("omits an unset MCP shadow diagnostics value", () => {
expect(selectManagedStartupApplicationRuntimeEnvironment({})).toEqual({});
});
});
5 changes: 5 additions & 0 deletions src/lib/onboard/managed-startup/root-apply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const MANAGED_STARTUP_ROOT_APPLY_MAX_BYTES = 320 * 1024;
const MAX_CORPORATE_CA_ENCODED_BYTES = 4 * Math.ceil((128 * 1024) / 3);
const SHA256_RE = /^[a-f0-9]{64}$/u;
const STANDARD_BASE64_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
const MCP_SHADOW_DIAGNOSTICS_ENV = "NEMOCLAW_MCP_SHADOW_DIAGNOSTICS";

export const MANAGED_STARTUP_APPLICATION_RUNTIME_ENV_KEYS = Object.freeze(
MANAGED_STARTUP_PROFILE_DEFERRED_RUNTIME_INPUTS.openclaw
Expand All @@ -37,6 +38,10 @@ export function selectManagedStartupApplicationRuntimeEnvironment(
const selected: Record<string, string> = {};
for (const name of MANAGED_STARTUP_APPLICATION_RUNTIME_ENV_KEYS) {
const value = environment[name];
if (name === MCP_SHADOW_DIAGNOSTICS_ENV) {
if (value?.trim() === "1") selected[name] = "1";
continue;
}
if (value !== undefined) selected[name] = value;
}
return Object.freeze(selected);
Expand Down
4 changes: 4 additions & 0 deletions test/cli/connect-recovery-settle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ describe("CLI dispatch", () => {
' cmd="$8"',
' cmd="$(decode_sandbox_exec_cmd "$cmd")"',
' case "$cmd" in',
' *"inference.local/v1/models"*)',
" echo 'OK 200'",
" exit 0",
" ;;",
' *"OPENCLAW="*)',
' echo recovered > "$state_file"',
" echo '__NEMOCLAW_SANDBOX_EXEC_STARTED__'",
Expand Down
4 changes: 4 additions & 0 deletions test/cli/connect-recovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ describe("CLI connect recovery process contracts", () => {
' cmd="$8"',
' if [[ "$*" == *"inference.local/v1/models"* ]]; then echo "OK 200"; exit 0; fi',
' case "$cmd" in',
' *"inference.local/v1/models"*)',
" echo 'OK 200'",
" exit 0",
" ;;",
" *'curl -so'*)",
" echo '__NEMOCLAW_SANDBOX_EXEC_STARTED__'",
' if [ "$(cat "$state_file")" = recovered ]; then echo RUNNING; else echo STOPPED; fi',
Expand Down
2 changes: 1 addition & 1 deletion test/onboard-selection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3014,7 +3014,6 @@ const { setupNim } = require(${onboardPath});
validateCustomOpenAiLikeSelection: validation.validateCustomOpenAiLikeSelection,
}),
);

try {
const { result, lines } = await captureConsoleOutput(() =>
validateSelectedRemoteModel({
Expand Down Expand Up @@ -4308,6 +4307,7 @@ const { setupNim } = require(${onboardPath});
exitCode: 0,
timedOut: false,
}),
recordUserLocalOllamaOwnershipImpl: () => {},
runShellImpl,
waitForHttpImpl: () => true,
}),
Expand Down
4 changes: 4 additions & 0 deletions test/recover-port-forward.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ if (args[0] === "sandbox" && args[1] === "list") {
}

if (args[0] === "sandbox" && args[1] === "exec") {
if (args.join(" ").includes("inference.local/v1/models")) {
process.stdout.write("OK 200\\n");
process.exit(0);
}
// The probe parser drops everything up to and including the start marker,
// so the fake gateway response must follow it on a new line.
process.stdout.write("__NEMOCLAW_SANDBOX_EXEC_STARTED__\\n${opts.gatewayProbe}\\n");
Expand Down
Loading