From 1d44f825e4370ae0f30dcc5b2568df3c33e88da7 Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Mon, 10 Aug 2026 09:29:58 -0400 Subject: [PATCH 1/2] fix(images): report MCP discovery assertion failures --- Dockerfile | 16 ++- agents/hermes/Dockerfile | 16 ++- agents/langchain-deepagents-code/Dockerfile | 16 ++- .../managed-bootstrap-image-contract.ts | 125 +++++++++++++++++- 4 files changed, 163 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8526c8bdda6..c32b593367c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1501,10 +1501,20 @@ RUN managed_runtime_assertion_failed() { \ "$nemoclaw_assertion" "$nemoclaw_artifact_path" "$nemoclaw_metadata" "$nemoclaw_symlink_state" >&2; \ exit 1; \ }; \ + managed_image_command_failed() { \ + nemoclaw_command_assertion="$1"; \ + nemoclaw_command_status="$2"; \ + printf 'ERROR: managed image assertion failed: %s exit-status=%s\n' \ + "$nemoclaw_command_assertion" "$nemoclaw_command_status" >&2; \ + exit 1; \ + }; \ discovery_contract="$(node /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs)" \ - && node -e "const result = JSON.parse(process.argv[1]); if (result.protocol !== 1 || result.ok !== false || result.detail !== \"tool discovery received invalid runtime arguments\") process.exit(1);" "$discovery_contract" \ - && discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ - && test -z "$discovery_unsafe" \ + || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"; \ + node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; const printable = value.replace(/[^\x20-\x7e]/gu, "?").replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/(\b(?:api[_-]?key|token|secret|password|credential|authorization)\b"?\s*[:=]\s*"?)[^",}\s]+/giu, (_match, prefix) => prefix + "").replace(/\b(?:gh[pousr]_|sk-|nvapi-|xox[baprs]-)[A-Za-z0-9._=-]+/giu, "").replace(/\b[A-Za-z0-9_=-]{32,}\b/gu, ""); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ + || exit 1; \ + discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ + || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"; \ + { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"; } \ && { test -f /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed regular-file /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { test ! -L /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed non-symlink /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ diff --git a/agents/hermes/Dockerfile b/agents/hermes/Dockerfile index 307fb207287..47f190e7fc9 100644 --- a/agents/hermes/Dockerfile +++ b/agents/hermes/Dockerfile @@ -363,10 +363,20 @@ RUN managed_runtime_assertion_failed() { \ "$nemoclaw_assertion" "$nemoclaw_artifact_path" "$nemoclaw_metadata" "$nemoclaw_symlink_state" >&2; \ exit 1; \ }; \ + managed_image_command_failed() { \ + nemoclaw_command_assertion="$1"; \ + nemoclaw_command_status="$2"; \ + printf 'ERROR: managed image assertion failed: %s exit-status=%s\n' \ + "$nemoclaw_command_assertion" "$nemoclaw_command_status" >&2; \ + exit 1; \ + }; \ discovery_contract="$(node /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs)" \ - && node -e 'const result = JSON.parse(process.argv[1]); if (result.protocol !== 1 || result.ok !== false || result.detail !== "tool discovery received invalid runtime arguments") process.exit(1);' "$discovery_contract" \ - && discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ - && test -z "$discovery_unsafe" \ + || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"; \ + node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; const printable = value.replace(/[^\x20-\x7e]/gu, "?").replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/(\b(?:api[_-]?key|token|secret|password|credential|authorization)\b"?\s*[:=]\s*"?)[^",}\s]+/giu, (_match, prefix) => prefix + "").replace(/\b(?:gh[pousr]_|sk-|nvapi-|xox[baprs]-)[A-Za-z0-9._=-]+/giu, "").replace(/\b[A-Za-z0-9_=-]{32,}\b/gu, ""); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ + || exit 1; \ + discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ + || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"; \ + { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"; } \ && { test -f /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed regular-file /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { test ! -L /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed non-symlink /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ diff --git a/agents/langchain-deepagents-code/Dockerfile b/agents/langchain-deepagents-code/Dockerfile index 914748ac335..0f6cefd3396 100644 --- a/agents/langchain-deepagents-code/Dockerfile +++ b/agents/langchain-deepagents-code/Dockerfile @@ -113,10 +113,20 @@ RUN managed_runtime_assertion_failed() { \ "$nemoclaw_assertion" "$nemoclaw_artifact_path" "$nemoclaw_metadata" "$nemoclaw_symlink_state" >&2; \ exit 1; \ }; \ + managed_image_command_failed() { \ + nemoclaw_command_assertion="$1"; \ + nemoclaw_command_status="$2"; \ + printf 'ERROR: managed image assertion failed: %s exit-status=%s\n' \ + "$nemoclaw_command_assertion" "$nemoclaw_command_status" >&2; \ + exit 1; \ + }; \ discovery_contract="$(node /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs)" \ - && node -e 'const result = JSON.parse(process.argv[1]); if (result.protocol !== 1 || result.ok !== false || result.detail !== "tool discovery received invalid runtime arguments") process.exit(1);' "$discovery_contract" \ - && discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ - && test -z "$discovery_unsafe" \ + || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"; \ + node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; const printable = value.replace(/[^\x20-\x7e]/gu, "?").replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/(\b(?:api[_-]?key|token|secret|password|credential|authorization)\b"?\s*[:=]\s*"?)[^",}\s]+/giu, (_match, prefix) => prefix + "").replace(/\b(?:gh[pousr]_|sk-|nvapi-|xox[baprs]-)[A-Za-z0-9._=-]+/giu, "").replace(/\b[A-Za-z0-9_=-]{32,}\b/gu, ""); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ + || exit 1; \ + discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ + || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"; \ + { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"; } \ && { test -f /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed regular-file /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { test ! -L /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed non-symlink /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ diff --git a/test/support/managed-bootstrap-image-contract.ts b/test/support/managed-bootstrap-image-contract.ts index 4b12be7c2ef..3e397a8b986 100644 --- a/test/support/managed-bootstrap-image-contract.ts +++ b/test/support/managed-bootstrap-image-contract.ts @@ -31,6 +31,10 @@ const COMPILER_FLAGS = [ const MANAGED_BOOTSTRAP_BUILDER_IMAGE = "node:22-trixie@sha256:a566dd560283ae5615c8bb86b58fa8a1b6f3c82b492473a061672416266625da"; +const DISCOVERY_RUNTIME_ROOT = "/usr/local/lib/nemoclaw/mcp-tool-discovery-runtime"; +const DISCOVERY_RUNTIME_PATH = `${DISCOVERY_RUNTIME_ROOT}/mcp-tool-discovery.mjs`; +const DISCOVERY_EXPECTED_CONTRACT = + '{"protocol":1,"ok":false,"detail":"tool discovery received invalid runtime arguments"}'; const MANAGED_STARTUP_RUNTIME_PATH = "/usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs"; function expectManagedRuntimeDiagnostic(dockerfile: string): void { @@ -40,20 +44,33 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { instruction.body.includes("managed_runtime_assertion_failed()"), ); expect(instructions).toHaveLength(1); - const logicalInstruction = (instructions[0]?.body ?? "").replace(/\\\r?\n[ \t]*/gu, " "); + const logicalInstruction = (instructions[0]?.body ?? "") + .replace(/\\\r?\n[ \t]*/gu, " ") + .replace(/[ \t]+/gu, " "); const discoveryStart = logicalInstruction.indexOf("discovery_contract="); expect(discoveryStart).toBeGreaterThan(0); + const managedRuntimeStart = logicalInstruction.indexOf( + `&& { test -f ${MANAGED_STARTUP_RUNTIME_PATH}`, + discoveryStart, + ); + expect(managedRuntimeStart).toBeGreaterThan(discoveryStart); const functionSource = logicalInstruction.slice(0, discoveryStart).trim(); + const discoverySource = logicalInstruction.slice(discoveryStart, managedRuntimeStart).trim(); for (const fragment of [ "stat -c 'uid=%u gid=%g type=%F mode=%a' -- \"$nemoclaw_artifact_path\" 2>/dev/null", "uid=unavailable gid=unavailable type=missing mode=unavailable", "printf 'ERROR: managed image assertion failed: %s path=%s %s symlink=%s\\n'", + "printf 'ERROR: managed image assertion failed: %s exit-status=%s\\n'", ]) { expect(functionSource).toContain(fragment); } for (const assertion of [ + `discovery_contract="$(node ${DISCOVERY_RUNTIME_PATH})" || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"`, + "ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", + `discovery_unsafe="$(find -L ${DISCOVERY_RUNTIME_ROOT} \\( ! -user root -o -perm /022 \\) -print -quit)" || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"`, + 'test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"', `test -f ${MANAGED_STARTUP_RUNTIME_PATH} || managed_runtime_assertion_failed regular-file ${MANAGED_STARTUP_RUNTIME_PATH}`, `test ! -L ${MANAGED_STARTUP_RUNTIME_PATH} || managed_runtime_assertion_failed non-symlink ${MANAGED_STARTUP_RUNTIME_PATH}`, `chown root:root ${MANAGED_STARTUP_RUNTIME_PATH} 2>/dev/null || managed_runtime_assertion_failed owner-root-root ${MANAGED_STARTUP_RUNTIME_PATH}`, @@ -69,6 +86,55 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { const linkPath = path.join(tmp, "runtime-link.cjs"); fs.writeFileSync(targetPath, "fixture\n", { mode: 0o444 }); fs.symlinkSync(targetPath, linkPath); + const runDiscoveryChecks = ({ + discoveryOutput = DISCOVERY_EXPECTED_CONTRACT, + discoveryStatus = 0, + findOutput = "", + findStatus = 0, + statOutput = "uid=0 gid=0 type=regular file mode=444", + }: { + discoveryOutput?: string; + discoveryStatus?: number; + findOutput?: string; + findStatus?: number; + statOutput?: string; + } = {}) => + spawnSync( + "sh", + [ + "-c", + [ + "node() {", + ' if [ "$1" = "$NEMOCLAW_TEST_DISCOVERY_RUNTIME" ]; then', + " printf '%s' \"$NEMOCLAW_TEST_DISCOVERY_OUTPUT\"", + ' return "$NEMOCLAW_TEST_DISCOVERY_STATUS"', + " fi", + ' "$NEMOCLAW_TEST_NODE" "$@"', + "}", + "find() {", + " printf '%s' \"$NEMOCLAW_TEST_FIND_OUTPUT\"", + ' return "$NEMOCLAW_TEST_FIND_STATUS"', + "}", + "stat() { printf '%s' \"$NEMOCLAW_TEST_STAT_OUTPUT\"; }", + functionSource, + discoverySource, + "printf 'discovery-ok\\n'", + ].join("\n"), + ], + { + encoding: "utf-8", + env: { + PATH: process.env.PATH ?? "", + NEMOCLAW_TEST_DISCOVERY_OUTPUT: discoveryOutput, + NEMOCLAW_TEST_DISCOVERY_RUNTIME: DISCOVERY_RUNTIME_PATH, + NEMOCLAW_TEST_DISCOVERY_STATUS: String(discoveryStatus), + NEMOCLAW_TEST_FIND_OUTPUT: findOutput, + NEMOCLAW_TEST_FIND_STATUS: String(findStatus), + NEMOCLAW_TEST_NODE: process.execPath, + NEMOCLAW_TEST_STAT_OUTPUT: statOutput, + }, + }, + ); const runDiagnostic = (artifactPath: string, invariant: string, statOutput: string) => spawnSync( "sh", @@ -92,6 +158,63 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { ); try { + const bundleFailure = runDiscoveryChecks({ + discoveryOutput: "output must remain private", + discoveryStatus: 23, + }); + expect(bundleFailure.status).toBe(1); + expect(bundleFailure.stdout).toBe(""); + expect(bundleFailure.stderr).toBe( + "ERROR: managed image assertion failed: mcp-tool-discovery-bundle-execution exit-status=23\n", + ); + + const credential = "gho_diagnosticSecretValue0123456789"; + const contractFailure = runDiscoveryChecks({ + discoveryOutput: JSON.stringify({ + protocol: 2, + ok: true, + detail: `wrong\n${credential}\tcontinued\u001b[31m`, + }), + }); + expect(contractFailure.status).toBe(1); + expect(contractFailure.stdout).toBe(""); + expect(contractFailure.stderr).toBe( + `ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual={"protocol":2,"ok":true,"detail":"wrong??continued?[31m"} expected=${DISCOVERY_EXPECTED_CONTRACT}\n`, + ); + expect(contractFailure.stderr).not.toContain(credential); + expect(contractFailure.stderr).not.toContain("\u001b"); + + const findFailure = runDiscoveryChecks({ findOutput: linkPath, findStatus: 42 }); + expect(findFailure.status).toBe(1); + expect(findFailure.stdout).toBe(""); + expect(findFailure.stderr).toBe( + "ERROR: managed image assertion failed: mcp-tool-discovery-tree-find-execution exit-status=42\n", + ); + + const unsafePath = runDiscoveryChecks({ + findOutput: linkPath, + statOutput: "uid=123 gid=456 type=symbolic link mode=777", + }); + expect(unsafePath.status).toBe(1); + expect(unsafePath.stdout).toBe(""); + expect(unsafePath.stderr).toBe( + `ERROR: managed image assertion failed: mcp-tool-discovery-tree-safety path=${linkPath} uid=123 gid=456 type=symbolic link mode=777 symlink=yes\n`, + ); + + const success = runDiscoveryChecks({ + discoveryOutput: JSON.stringify({ + protocol: 1, + ok: false, + detail: "tool discovery received invalid runtime arguments", + count: 0, + tools: [], + truncated: false, + }), + }); + expect(success.status, success.stderr).toBe(0); + expect(success.stdout).toBe("discovery-ok\n"); + expect(success.stderr).toBe(""); + const missing = runDiagnostic(missingPath, "regular-file", "unused"); expect(missing.status).toBe(1); expect(missing.stdout).toBe(""); From f67df5af4900e42a80e78acb148156f780858bf8 Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Mon, 10 Aug 2026 09:52:33 -0400 Subject: [PATCH 2/2] fix(images): harden discovery diagnostics --- Dockerfile | 13 ++- agents/hermes/Dockerfile | 13 ++- agents/langchain-deepagents-code/Dockerfile | 13 ++- .../managed-bootstrap-image-contract.ts | 105 +++++++++++++++--- 4 files changed, 119 insertions(+), 25 deletions(-) diff --git a/Dockerfile b/Dockerfile index c32b593367c..fcd6c3bfcab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1490,8 +1490,13 @@ RUN managed_runtime_assertion_failed() { \ nemoclaw_assertion="$1"; \ nemoclaw_artifact_path="$2"; \ if [ -e "$nemoclaw_artifact_path" ] || [ -L "$nemoclaw_artifact_path" ]; then \ - nemoclaw_metadata="$(stat -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ - || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + if [ "${3:-}" = dereference ] && [ -e "$nemoclaw_artifact_path" ]; then \ + nemoclaw_metadata="$(stat -L -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ + || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + else \ + nemoclaw_metadata="$(stat -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ + || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + fi; \ if [ -L "$nemoclaw_artifact_path" ]; then nemoclaw_symlink_state='yes'; else nemoclaw_symlink_state='no'; fi; \ else \ nemoclaw_metadata='uid=unavailable gid=unavailable type=missing mode=unavailable'; \ @@ -1510,11 +1515,11 @@ RUN managed_runtime_assertion_failed() { \ }; \ discovery_contract="$(node /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs)" \ || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"; \ - node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; const printable = value.replace(/[^\x20-\x7e]/gu, "?").replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/(\b(?:api[_-]?key|token|secret|password|credential|authorization)\b"?\s*[:=]\s*"?)[^",}\s]+/giu, (_match, prefix) => prefix + "").replace(/\b(?:gh[pousr]_|sk-|nvapi-|xox[baprs]-)[A-Za-z0-9._=-]+/giu, "").replace(/\b[A-Za-z0-9_=-]{32,}\b/gu, ""); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ + node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const standaloneSecretPatterns = [/(?:nvapi-|nvcf-|gh[pousr]_|sk-proj-|sk-ant-|hf_|glpat-|gsk_|pypi-|tvly-)[A-Za-z0-9_-]{10,}/gu, /github_pat_[A-Za-z0-9_]{30,}/gu, /sk-[A-Za-z0-9_-]{20,}/gu, /(?:xox[bpas]|xapp)-[A-Za-z0-9-]{10,}/gu, /A(?:K|S)IA[A-Z0-9]{16}/gu, /\bbot\d{8,10}:[A-Za-z0-9_-]{35}\b/gu, /\b\d{8,10}:[A-Za-z0-9_-]{35}\b/gu, /\b[A-Za-z0-9]{24}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27,}\b/gu, /lsv2_(?:pt|sk)_[A-Za-z0-9]{10,}(?:_[A-Za-z0-9]+)*/gu, /\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]{10,}\b/gu, /\b[A-Za-z0-9_=-]{32,}\b/gu]; const redactContextSecrets = (value) => value.replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/((?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]{1,128}_(?:KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|PASSWD|PASS)|(?:X[-_])?API[-_]KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|PASSWD|PASS)["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/giu, (_match, prefix) => prefix + "").replace(/((?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]{1,128}(?:Token|Secret|Credential)|[A-Za-z0-9]{0,128}(?:[Aa]ccess|[Rr]efresh|[Cc]lient|[Bb]earer|[Aa]uth|[Aa][Pp][Ii]|[Pp]rivate|[Ss]igning|[Ss]ession|[Bb]ot|[Aa]pp|[Rr]esolved)Key|[A-Za-z0-9]{1,128}(?:Password|Passwd|Pass))["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/gu, (_match, prefix) => prefix + "").replace(/((?:^|[^A-Za-z0-9])KEY["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/gu, (_match, prefix) => prefix + ""); const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; let printable = value.replace(/-----BEGIN (?:[A-Z0-9]+ )?PRIVATE KEY-----[\s\S]*/gu, "").replace(/[^\x20-\x7e]/gu, "?"); for (const pattern of standaloneSecretPatterns) printable = printable.replace(pattern, ""); printable = redactContextSecrets(printable); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ || exit 1; \ discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"; \ - { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"; } \ + { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe" dereference; } \ && { test -f /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed regular-file /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { test ! -L /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed non-symlink /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ diff --git a/agents/hermes/Dockerfile b/agents/hermes/Dockerfile index 47f190e7fc9..3e4cefe3e3b 100644 --- a/agents/hermes/Dockerfile +++ b/agents/hermes/Dockerfile @@ -352,8 +352,13 @@ RUN managed_runtime_assertion_failed() { \ nemoclaw_assertion="$1"; \ nemoclaw_artifact_path="$2"; \ if [ -e "$nemoclaw_artifact_path" ] || [ -L "$nemoclaw_artifact_path" ]; then \ - nemoclaw_metadata="$(stat -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ - || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + if [ "${3:-}" = dereference ] && [ -e "$nemoclaw_artifact_path" ]; then \ + nemoclaw_metadata="$(stat -L -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ + || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + else \ + nemoclaw_metadata="$(stat -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ + || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + fi; \ if [ -L "$nemoclaw_artifact_path" ]; then nemoclaw_symlink_state='yes'; else nemoclaw_symlink_state='no'; fi; \ else \ nemoclaw_metadata='uid=unavailable gid=unavailable type=missing mode=unavailable'; \ @@ -372,11 +377,11 @@ RUN managed_runtime_assertion_failed() { \ }; \ discovery_contract="$(node /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs)" \ || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"; \ - node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; const printable = value.replace(/[^\x20-\x7e]/gu, "?").replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/(\b(?:api[_-]?key|token|secret|password|credential|authorization)\b"?\s*[:=]\s*"?)[^",}\s]+/giu, (_match, prefix) => prefix + "").replace(/\b(?:gh[pousr]_|sk-|nvapi-|xox[baprs]-)[A-Za-z0-9._=-]+/giu, "").replace(/\b[A-Za-z0-9_=-]{32,}\b/gu, ""); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ + node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const standaloneSecretPatterns = [/(?:nvapi-|nvcf-|gh[pousr]_|sk-proj-|sk-ant-|hf_|glpat-|gsk_|pypi-|tvly-)[A-Za-z0-9_-]{10,}/gu, /github_pat_[A-Za-z0-9_]{30,}/gu, /sk-[A-Za-z0-9_-]{20,}/gu, /(?:xox[bpas]|xapp)-[A-Za-z0-9-]{10,}/gu, /A(?:K|S)IA[A-Z0-9]{16}/gu, /\bbot\d{8,10}:[A-Za-z0-9_-]{35}\b/gu, /\b\d{8,10}:[A-Za-z0-9_-]{35}\b/gu, /\b[A-Za-z0-9]{24}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27,}\b/gu, /lsv2_(?:pt|sk)_[A-Za-z0-9]{10,}(?:_[A-Za-z0-9]+)*/gu, /\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]{10,}\b/gu, /\b[A-Za-z0-9_=-]{32,}\b/gu]; const redactContextSecrets = (value) => value.replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/((?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]{1,128}_(?:KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|PASSWD|PASS)|(?:X[-_])?API[-_]KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|PASSWD|PASS)["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/giu, (_match, prefix) => prefix + "").replace(/((?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]{1,128}(?:Token|Secret|Credential)|[A-Za-z0-9]{0,128}(?:[Aa]ccess|[Rr]efresh|[Cc]lient|[Bb]earer|[Aa]uth|[Aa][Pp][Ii]|[Pp]rivate|[Ss]igning|[Ss]ession|[Bb]ot|[Aa]pp|[Rr]esolved)Key|[A-Za-z0-9]{1,128}(?:Password|Passwd|Pass))["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/gu, (_match, prefix) => prefix + "").replace(/((?:^|[^A-Za-z0-9])KEY["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/gu, (_match, prefix) => prefix + ""); const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; let printable = value.replace(/-----BEGIN (?:[A-Z0-9]+ )?PRIVATE KEY-----[\s\S]*/gu, "").replace(/[^\x20-\x7e]/gu, "?"); for (const pattern of standaloneSecretPatterns) printable = printable.replace(pattern, ""); printable = redactContextSecrets(printable); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ || exit 1; \ discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"; \ - { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"; } \ + { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe" dereference; } \ && { test -f /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed regular-file /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { test ! -L /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed non-symlink /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ diff --git a/agents/langchain-deepagents-code/Dockerfile b/agents/langchain-deepagents-code/Dockerfile index 0f6cefd3396..b6c97012657 100644 --- a/agents/langchain-deepagents-code/Dockerfile +++ b/agents/langchain-deepagents-code/Dockerfile @@ -102,8 +102,13 @@ RUN managed_runtime_assertion_failed() { \ nemoclaw_assertion="$1"; \ nemoclaw_artifact_path="$2"; \ if [ -e "$nemoclaw_artifact_path" ] || [ -L "$nemoclaw_artifact_path" ]; then \ - nemoclaw_metadata="$(stat -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ - || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + if [ "${3:-}" = dereference ] && [ -e "$nemoclaw_artifact_path" ]; then \ + nemoclaw_metadata="$(stat -L -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ + || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + else \ + nemoclaw_metadata="$(stat -c 'uid=%u gid=%g type=%F mode=%a' -- "$nemoclaw_artifact_path" 2>/dev/null)" \ + || nemoclaw_metadata='uid=unavailable gid=unavailable type=unavailable mode=unavailable'; \ + fi; \ if [ -L "$nemoclaw_artifact_path" ]; then nemoclaw_symlink_state='yes'; else nemoclaw_symlink_state='no'; fi; \ else \ nemoclaw_metadata='uid=unavailable gid=unavailable type=missing mode=unavailable'; \ @@ -122,11 +127,11 @@ RUN managed_runtime_assertion_failed() { \ }; \ discovery_contract="$(node /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs)" \ || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"; \ - node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; const printable = value.replace(/[^\x20-\x7e]/gu, "?").replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/(\b(?:api[_-]?key|token|secret|password|credential|authorization)\b"?\s*[:=]\s*"?)[^",}\s]+/giu, (_match, prefix) => prefix + "").replace(/\b(?:gh[pousr]_|sk-|nvapi-|xox[baprs]-)[A-Za-z0-9._=-]+/giu, "").replace(/\b[A-Za-z0-9_=-]{32,}\b/gu, ""); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ + node -e 'const expected = { protocol: 1, ok: false, detail: "tool discovery received invalid runtime arguments" }; const standaloneSecretPatterns = [/(?:nvapi-|nvcf-|gh[pousr]_|sk-proj-|sk-ant-|hf_|glpat-|gsk_|pypi-|tvly-)[A-Za-z0-9_-]{10,}/gu, /github_pat_[A-Za-z0-9_]{30,}/gu, /sk-[A-Za-z0-9_-]{20,}/gu, /(?:xox[bpas]|xapp)-[A-Za-z0-9-]{10,}/gu, /A(?:K|S)IA[A-Z0-9]{16}/gu, /\bbot\d{8,10}:[A-Za-z0-9_-]{35}\b/gu, /\b\d{8,10}:[A-Za-z0-9_-]{35}\b/gu, /\b[A-Za-z0-9]{24}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27,}\b/gu, /lsv2_(?:pt|sk)_[A-Za-z0-9]{10,}(?:_[A-Za-z0-9]+)*/gu, /\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]{10,}\b/gu, /\b[A-Za-z0-9_=-]{32,}\b/gu]; const redactContextSecrets = (value) => value.replace(/\b(?:Bearer|Basic)\s+\S+/giu, "").replace(/((?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]{1,128}_(?:KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|PASSWD|PASS)|(?:X[-_])?API[-_]KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|PASSWD|PASS)["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/giu, (_match, prefix) => prefix + "").replace(/((?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]{1,128}(?:Token|Secret|Credential)|[A-Za-z0-9]{0,128}(?:[Aa]ccess|[Rr]efresh|[Cc]lient|[Bb]earer|[Aa]uth|[Aa][Pp][Ii]|[Pp]rivate|[Ss]igning|[Ss]ession|[Bb]ot|[Aa]pp|[Rr]esolved)Key|[A-Za-z0-9]{1,128}(?:Password|Passwd|Pass))["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/gu, (_match, prefix) => prefix + "").replace(/((?:^|[^A-Za-z0-9])KEY["\x27]?(?:[ \t]{0,32}[=:][ \t]{0,32}|[ \t]{1,32})["\x27]?)[^\s"\x27]{10,}/gu, (_match, prefix) => prefix + ""); const sanitize = (value) => { if (value === undefined) return ""; if (value === null || typeof value === "boolean" || typeof value === "number") return value; if (typeof value !== "string") return "<" + (Array.isArray(value) ? "array" : typeof value) + ">"; let printable = value.replace(/-----BEGIN (?:[A-Z0-9]+ )?PRIVATE KEY-----[\s\S]*/gu, "").replace(/[^\x20-\x7e]/gu, "?"); for (const pattern of standaloneSecretPatterns) printable = printable.replace(pattern, ""); printable = redactContextSecrets(printable); return printable.length <= 240 ? printable : printable.slice(0, 237) + "..."; }; let result; let parsed = true; try { result = JSON.parse(process.argv[1]); } catch { parsed = false; } const record = parsed && result !== null && typeof result === "object" && !Array.isArray(result) ? result : undefined; if (record && record.protocol === expected.protocol && record.ok === expected.ok && record.detail === expected.detail) process.exit(0); const actual = record ? { protocol: sanitize(record.protocol), ok: sanitize(record.ok), detail: sanitize(record.detail) } : parsed ? { type: result === null ? "null" : Array.isArray(result) ? "array" : typeof result, value: sanitize(result) } : { type: "invalid-json", preview: sanitize(process.argv[1]) }; console.error("ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", JSON.stringify(actual), JSON.stringify(expected)); process.exit(1);' "$discovery_contract" \ || exit 1; \ discovery_unsafe="$(find -L /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime \( ! -user root -o -perm /022 \) -print -quit)" \ || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"; \ - { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"; } \ + { test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe" dereference; } \ && { test -f /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed regular-file /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { test ! -L /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs || managed_runtime_assertion_failed non-symlink /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ && { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \ diff --git a/test/support/managed-bootstrap-image-contract.ts b/test/support/managed-bootstrap-image-contract.ts index 3e397a8b986..cb9507658aa 100644 --- a/test/support/managed-bootstrap-image-contract.ts +++ b/test/support/managed-bootstrap-image-contract.ts @@ -58,6 +58,7 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { const discoverySource = logicalInstruction.slice(discoveryStart, managedRuntimeStart).trim(); for (const fragment of [ + "stat -L -c 'uid=%u gid=%g type=%F mode=%a' -- \"$nemoclaw_artifact_path\" 2>/dev/null", "stat -c 'uid=%u gid=%g type=%F mode=%a' -- \"$nemoclaw_artifact_path\" 2>/dev/null", "uid=unavailable gid=unavailable type=missing mode=unavailable", "printf 'ERROR: managed image assertion failed: %s path=%s %s symlink=%s\\n'", @@ -70,7 +71,7 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { `discovery_contract="$(node ${DISCOVERY_RUNTIME_PATH})" || managed_image_command_failed mcp-tool-discovery-bundle-execution "$?"`, "ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual=%s expected=%s", `discovery_unsafe="$(find -L ${DISCOVERY_RUNTIME_ROOT} \\( ! -user root -o -perm /022 \\) -print -quit)" || managed_image_command_failed mcp-tool-discovery-tree-find-execution "$?"`, - 'test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe"', + 'test -z "$discovery_unsafe" || managed_runtime_assertion_failed mcp-tool-discovery-tree-safety "$discovery_unsafe" dereference', `test -f ${MANAGED_STARTUP_RUNTIME_PATH} || managed_runtime_assertion_failed regular-file ${MANAGED_STARTUP_RUNTIME_PATH}`, `test ! -L ${MANAGED_STARTUP_RUNTIME_PATH} || managed_runtime_assertion_failed non-symlink ${MANAGED_STARTUP_RUNTIME_PATH}`, `chown root:root ${MANAGED_STARTUP_RUNTIME_PATH} 2>/dev/null || managed_runtime_assertion_failed owner-root-root ${MANAGED_STARTUP_RUNTIME_PATH}`, @@ -91,12 +92,14 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { discoveryStatus = 0, findOutput = "", findStatus = 0, + dereferencedStatOutput = "uid=0 gid=0 type=regular file mode=444", statOutput = "uid=0 gid=0 type=regular file mode=444", }: { discoveryOutput?: string; discoveryStatus?: number; findOutput?: string; findStatus?: number; + dereferencedStatOutput?: string; statOutput?: string; } = {}) => spawnSync( @@ -115,7 +118,13 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { " printf '%s' \"$NEMOCLAW_TEST_FIND_OUTPUT\"", ' return "$NEMOCLAW_TEST_FIND_STATUS"', "}", - "stat() { printf '%s' \"$NEMOCLAW_TEST_STAT_OUTPUT\"; }", + "stat() {", + ' if [ "$1" = "-L" ]; then', + " printf '%s' \"$NEMOCLAW_TEST_DEREFERENCED_STAT_OUTPUT\"", + " else", + " printf '%s' \"$NEMOCLAW_TEST_STAT_OUTPUT\"", + " fi", + "}", functionSource, discoverySource, "printf 'discovery-ok\\n'", @@ -128,6 +137,7 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { NEMOCLAW_TEST_DISCOVERY_OUTPUT: discoveryOutput, NEMOCLAW_TEST_DISCOVERY_RUNTIME: DISCOVERY_RUNTIME_PATH, NEMOCLAW_TEST_DISCOVERY_STATUS: String(discoveryStatus), + NEMOCLAW_TEST_DEREFERENCED_STAT_OUTPUT: dereferencedStatOutput, NEMOCLAW_TEST_FIND_OUTPUT: findOutput, NEMOCLAW_TEST_FIND_STATUS: String(findStatus), NEMOCLAW_TEST_NODE: process.execPath, @@ -168,21 +178,89 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { "ERROR: managed image assertion failed: mcp-tool-discovery-bundle-execution exit-status=23\n", ); - const credential = "gho_diagnosticSecretValue0123456789"; - const contractFailure = runDiscoveryChecks({ + const standaloneCredentials = [ + "nvapi-abcdefghij", + "nvcf-abcdefghij", + "ghp_abcdefghij", + "gho_abcdefghij", + `github_pat_${"a".repeat(30)}`, + "sk-proj-abcdefghij", + "sk-ant-abcdefghij", + `sk-${"a".repeat(20)}`, + "xoxb-abcdefghij", + "xapp-abcdefghij", + "AKIA1234567890ABCDEF", + "ASIA1234567890ABCDEF", + "hf_abcdefghij", + "glpat-abcdefghij", + "gsk_abcdefghij", + "pypi-abcdefghij", + `bot12345678:${"a".repeat(35)}`, + `12345678:${"a".repeat(35)}`, + `${"a".repeat(24)}.${"b".repeat(6)}.${"c".repeat(27)}`, + "tvly-abcdefghij", + "lsv2_pt_abcdefghij_tail", + "lsv2_sk_abcdefghij", + `eyJabcde.${"b".repeat(2)}.${"c".repeat(10)}`, + ]; + for (const credential of standaloneCredentials) { + const contractFailure = runDiscoveryChecks({ + discoveryOutput: JSON.stringify({ + protocol: 2, + ok: true, + detail: `wrong\n${credential}\tcontinued\u001b[31m`, + }), + }); + expect(contractFailure.status).toBe(1); + expect(contractFailure.stdout).toBe(""); + expect(contractFailure.stderr).toBe( + `ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual={"protocol":2,"ok":true,"detail":"wrong??continued?[31m"} expected=${DISCOVERY_EXPECTED_CONTRACT}\n`, + ); + expect(contractFailure.stderr).not.toContain(credential); + expect(contractFailure.stderr).not.toContain("\u001b"); + } + + for (const [credential, sanitized] of [ + ["Bearer abcdefghij", ""], + ["Basic abcdefghij", ""], + ["OPENAI_API_KEY=abcdefghij", "OPENAI_API_KEY="], + ["accessToken=abcdefghij", "accessToken="], + ["KEY=abcdefghij", "KEY="], + ]) { + const contractFailure = runDiscoveryChecks({ + discoveryOutput: JSON.stringify({ protocol: 2, ok: true, detail: credential }), + }); + expect(contractFailure.status).toBe(1); + expect(contractFailure.stdout).toBe(""); + expect(contractFailure.stderr).toBe( + `ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual={"protocol":2,"ok":true,"detail":"${sanitized}"} expected=${DISCOVERY_EXPECTED_CONTRACT}\n`, + ); + expect(contractFailure.stderr).not.toContain(credential); + } + + const invalidJsonFailure = runDiscoveryChecks({ + discoveryOutput: '{"detail":"nvcf-abcdefghij"', + }); + expect(invalidJsonFailure.status).toBe(1); + expect(invalidJsonFailure.stdout).toBe(""); + expect(invalidJsonFailure.stderr).toBe( + `ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual={"type":"invalid-json","preview":"{\\"detail\\":\\"\\""} expected=${DISCOVERY_EXPECTED_CONTRACT}\n`, + ); + + const privateKeyLabel = `${"PRIVATE"} KEY`; + const privateKeyFailure = runDiscoveryChecks({ discoveryOutput: JSON.stringify({ protocol: 2, ok: true, - detail: `wrong\n${credential}\tcontinued\u001b[31m`, + detail: `wrong\n-----BEGIN ${privateKeyLabel}-----\nprivate-material\n-----END ${privateKeyLabel}-----`, }), }); - expect(contractFailure.status).toBe(1); - expect(contractFailure.stdout).toBe(""); - expect(contractFailure.stderr).toBe( - `ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual={"protocol":2,"ok":true,"detail":"wrong??continued?[31m"} expected=${DISCOVERY_EXPECTED_CONTRACT}\n`, + expect(privateKeyFailure.status).toBe(1); + expect(privateKeyFailure.stdout).toBe(""); + expect(privateKeyFailure.stderr).toBe( + `ERROR: managed image assertion failed: mcp-tool-discovery-json-contract actual={"protocol":2,"ok":true,"detail":"wrong?"} expected=${DISCOVERY_EXPECTED_CONTRACT}\n`, ); - expect(contractFailure.stderr).not.toContain(credential); - expect(contractFailure.stderr).not.toContain("\u001b"); + expect(privateKeyFailure.stderr).not.toContain("private-material"); const findFailure = runDiscoveryChecks({ findOutput: linkPath, findStatus: 42 }); expect(findFailure.status).toBe(1); @@ -192,13 +270,14 @@ function expectManagedRuntimeDiagnostic(dockerfile: string): void { ); const unsafePath = runDiscoveryChecks({ + dereferencedStatOutput: "uid=123 gid=456 type=regular file mode=664", findOutput: linkPath, - statOutput: "uid=123 gid=456 type=symbolic link mode=777", + statOutput: "uid=0 gid=0 type=symbolic link mode=777", }); expect(unsafePath.status).toBe(1); expect(unsafePath.stdout).toBe(""); expect(unsafePath.stderr).toBe( - `ERROR: managed image assertion failed: mcp-tool-discovery-tree-safety path=${linkPath} uid=123 gid=456 type=symbolic link mode=777 symlink=yes\n`, + `ERROR: managed image assertion failed: mcp-tool-discovery-tree-safety path=${linkPath} uid=123 gid=456 type=regular file mode=664 symlink=yes\n`, ); const success = runDiscoveryChecks({