From 7f7f8c071614cb74617716b91da4108ffd69ec86 Mon Sep 17 00:00:00 2001 From: Miyoung Choi Date: Fri, 24 Jul 2026 11:13:05 -0700 Subject: [PATCH 1/3] docs: complete post-tag audit fixes Signed-off-by: Miyoung Choi --- ci/platform-matrix.json | 2 +- docs/changelog/2026-06-08.mdx | 2 +- docs/changelog/2026-06-11.mdx | 2 +- docs/changelog/2026-06-28.mdx | 2 +- docs/changelog/2026-07-01.mdx | 2 +- docs/changelog/2026-07-04.mdx | 4 +- docs/changelog/2026-07-08.mdx | 2 +- docs/changelog/2026-07-09.mdx | 2 +- docs/changelog/2026-07-12.mdx | 2 +- docs/changelog/2026-07-14.mdx | 2 +- docs/changelog/2026-07-24.mdx | 2 +- .../quickstart-langchain-deepagents-code.mdx | 383 +----------- docs/index.yml | 64 ++ docs/inference/set-up-vllm.mdx | 18 +- .../manage-deepagents-trace-export.mdx | 71 +++ .../set-up-deepagents-trace-export.mdx | 286 +++++++++ .../understand-deepagents-trace-export.mdx | 87 +++ .../verify-deepagents-trace-export.mdx | 69 +++ docs/network-policy/apply-policy-presets.mdx | 107 ++++ .../change-baseline-network-policy.mdx | 91 +++ .../configure-raw-tls-passthrough.mdx | 86 +++ .../create-custom-policy-presets.mdx | 191 ++++++ .../customize-network-policy.mdx | 547 ++---------------- .../explain-network-policy-to-agents.mdx | 96 +++ .../integration-policy-examples.mdx | 236 +------- .../replace-live-network-policy.mdx | 75 +++ .../set-up-gmail-with-an-app-password.mdx | 187 ++++++ docs/reference/commands.mdx | 6 +- docs/reference/network-policies.mdx | 2 +- docs/reference/platform-support.mdx | 2 +- docs/security/advisory-early-warning.md | 142 ++--- docs/security/credential-storage.mdx | 2 +- ...agents-monitoring-published-routes.test.ts | 60 ++ .../network-policies-published-routes.test.ts | 87 +++ test/policy-roundtrip-docs.test.ts | 15 +- 35 files changed, 1736 insertions(+), 1198 deletions(-) create mode 100644 docs/monitoring/manage-deepagents-trace-export.mdx create mode 100644 docs/monitoring/set-up-deepagents-trace-export.mdx create mode 100644 docs/monitoring/understand-deepagents-trace-export.mdx create mode 100644 docs/monitoring/verify-deepagents-trace-export.mdx create mode 100644 docs/network-policy/apply-policy-presets.mdx create mode 100644 docs/network-policy/change-baseline-network-policy.mdx create mode 100644 docs/network-policy/configure-raw-tls-passthrough.mdx create mode 100644 docs/network-policy/create-custom-policy-presets.mdx create mode 100644 docs/network-policy/explain-network-policy-to-agents.mdx create mode 100644 docs/network-policy/replace-live-network-policy.mdx create mode 100644 docs/network-policy/set-up-gmail-with-an-app-password.mdx create mode 100644 test/deepagents-monitoring-published-routes.test.ts diff --git a/ci/platform-matrix.json b/ci/platform-matrix.json index 246dfc3f1f..2b41cf7b82 100644 --- a/ci/platform-matrix.json +++ b/ci/platform-matrix.json @@ -231,7 +231,7 @@ { "name": "Intel Mac (macOS x86_64)", "status": "unsupported", - "notes": "OpenShell does not publish macOS x86_64 standalone gateway assets. Install hard-fails on x86_64 macOS (`scripts/install-openshell.sh:689`). See issue #954 (closed)." + "notes": "OpenShell does not publish macOS x86_64 standalone gateway assets. The top-level installer rejects Intel Mac hosts before release-ref resolution or downloads (`install.sh:108`), and the OpenShell installer retains a downstream asset guard (`scripts/install-openshell.sh:689`). See issue #954 (closed)." }, { "name": "Non-Ubuntu/Debian Linux distros", diff --git a/docs/changelog/2026-06-08.mdx b/docs/changelog/2026-06-08.mdx index 5f8207b088..cba0089cb3 100644 --- a/docs/changelog/2026-06-08.mdx +++ b/docs/changelog/2026-06-08.mdx @@ -9,7 +9,7 @@ NemoClaw v0.0.61 improves sandbox network visibility, onboarding recovery, Herme - Agents and operators can inspect a redacted policy context that lists active presets, allowed host categories, approval paths, and policy drift states. Strict SSRF fetches now route through the sandbox proxy, stale `sandboxes.json` locks held by recycled PIDs are reclaimed, and dashboard tool-scope approvals can recover through doctor after sandbox startup. - For more information, refer to [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy). + For more information, refer to [Explain Network Policy to Agents](/user-guide/openclaw/network-policy/explain-network-policy-to-agents). - Sandbox hardening now caps open file descriptors at entrypoint, preserves the tunnel service PID directory across restarts, and keeps build-time plugin install state from forcing runtime npm calls offline. NemoClaw also closed coordinated code-scanning findings and consolidated HTTP probe policy handling without changing the operator contract. For more information, refer to [Security Best Practices](/user-guide/openclaw/security/best-practices). diff --git a/docs/changelog/2026-06-11.mdx b/docs/changelog/2026-06-11.mdx index 738fa9af50..7df6c0ebf2 100644 --- a/docs/changelog/2026-06-11.mdx +++ b/docs/changelog/2026-06-11.mdx @@ -8,7 +8,7 @@ NemoClaw v0.0.64 improves sandbox restore, onboarding stability, inference routing, messaging setup, and release validation: - Snapshot restore preserves custom policy presets applied with `policy-add --from-file` or `policy-add --from-dir`, so restored sandboxes keep the custom egress rules that were recorded with the source sandbox. - For more information, refer to [Create and Restore Snapshots](/user-guide/openclaw/manage-sandboxes/state-and-backups/create-and-restore-snapshots) and [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy). + For more information, refer to [Create and Restore Snapshots](/user-guide/openclaw/manage-sandboxes/state-and-backups/create-and-restore-snapshots) and [Create Custom Policy Presets](/user-guide/openclaw/network-policy/configure-policies/create-custom-policy-presets). - OpenClaw onboarding keeps Brave Search pinned to the NemoClaw-managed runtime and preserves the `BRAVE_API_KEY` placeholder through build doctor. Docker-driver gateway health checks now follow the entrypoint path that actually launches the in-container gateway, which avoids misleading health reports on host-gateway setups. For more information, refer to [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). diff --git a/docs/changelog/2026-06-28.mdx b/docs/changelog/2026-06-28.mdx index a2fb94a8a3..e249fb5b80 100644 --- a/docs/changelog/2026-06-28.mdx +++ b/docs/changelog/2026-06-28.mdx @@ -27,4 +27,4 @@ NemoClaw v0.0.69 improves sandbox recovery, Deep Agents Code workflows, Hermes m For more information, refer to [Security Best Practices](/user-guide/openclaw/security/best-practices), [Credential Storage](/user-guide/openclaw/security/credential-storage), [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands), and [Monitor Sandbox Activity](/user-guide/openclaw/monitoring/monitor-sandbox-activity). - Documentation and release gates now cover more policy, approval, and live validation paths. The docs include clearer policy round-trip and network-request approval examples, while the live release gates distinguish public NVIDIA API keys from hosted inference keys and exercise Deep Agents Code terminal behavior more directly. - For more information, refer to [Network Policies](/user-guide/openclaw/reference/network-policies), [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy), and [Approve or Deny Agent Network Requests](/user-guide/openclaw/network-policy/approve-network-requests). + For more information, refer to [Network Policies](/user-guide/openclaw/reference/network-policies), [Replace the Live Network Policy](/user-guide/openclaw/network-policy/configure-policies/replace-live-network-policy), and [Approve or Deny Agent Network Requests](/user-guide/openclaw/network-policy/approve-network-requests). diff --git a/docs/changelog/2026-07-01.mdx b/docs/changelog/2026-07-01.mdx index b50c4af998..cda8a8500b 100644 --- a/docs/changelog/2026-07-01.mdx +++ b/docs/changelog/2026-07-01.mdx @@ -18,7 +18,7 @@ NemoClaw v0.0.72 improves installer recovery, sandbox diagnostics, inference set For more information, refer to [Choose an Inference Provider](/user-guide/openclaw/inference/learn-and-choose/choose-inference-provider), [Switch Inference Providers](/user-guide/openclaw/inference/manage-inference/switch-providers), and [Security Best Practices](/user-guide/openclaw/security/best-practices). - Custom policy and sandbox credential boundaries are tighter. User-supplied custom presets reject `allowed_ips` except the explicit host bridge, OpenClaw processes receive `AWS_EC2_METADATA_DISABLED=true`, Hermes runtime configuration output masks API key fields, and `exec` restores mutable OpenClaw config permissions after one-shot commands. - For more information, refer to [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy), [Security Best Practices](/user-guide/openclaw/security/best-practices), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). + For more information, refer to [Create Custom Policy Presets](/user-guide/openclaw/network-policy/configure-policies/create-custom-policy-presets), [Security Best Practices](/user-guide/openclaw/security/best-practices), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). - Runtime repair covers more sandbox-specific drift. OpenClaw gateway watchdog exits respawn the gateway instead of ending PID 1, Hermes upgrade checks compare agent versions in the Hermes runtime scheme, Tavily access is restored for managed Python workflows, and prompt-stdin EOF during onboarding is treated as cancellation. For more information, refer to [Recover and Rebuild Sandboxes](/user-guide/openclaw/manage-sandboxes/operate-sandboxes/recover-and-rebuild-sandboxes), [Common NemoClaw Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). diff --git a/docs/changelog/2026-07-04.mdx b/docs/changelog/2026-07-04.mdx index d2a3cb0d35..338f1bf633 100644 --- a/docs/changelog/2026-07-04.mdx +++ b/docs/changelog/2026-07-04.mdx @@ -9,7 +9,7 @@ NemoClaw v0.0.74 upgrades the OpenShell policy boundary, adds managed MCP and pr - Stable installs pin OpenShell `0.0.72` release artifacts and the supervisor image, adding MCP Streamable HTTP and JSON-RPC request-policy enforcement. Policy mutations read the round-trippable base policy instead of the effective policy, which preserves existing MCP rules without sending provider-composed `_provider_*` entries back through `policy set`. - For more information, refer to [OpenShell 0.0.72 Compatibility Review](/user-guide/openclaw/security/openshell-0.0.72-compatibility-review) and [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy). + For more information, refer to [OpenShell 0.0.72 Compatibility Review](/user-guide/openclaw/security/openshell-0.0.72-compatibility-review) and [Replace the Live Network Policy](/user-guide/openclaw/network-policy/configure-policies/replace-live-network-policy). - Managed MCP commands use `add`, `list`, `status`, `restart`, and `remove` to manage authenticated HTTPS Streamable HTTP servers for OpenClaw, Hermes, and experimental LangChain Deep Agents Code through native OpenShell policy enforcement and provider-backed credential replacement. The LangChain Deep Agents Code rebuild path validates the recorded gateway, route, image, staged build context, and prepared replacement inputs before deleting the previous sandbox, then restores managed MCP state after the recreated runtime is ready. For more information, refer to [About Managed MCP Servers](/user-guide/openclaw/manage-sandboxes/mcp-servers/about-managed-mcp-servers), [Quickstart with LangChain Deep Agents Code](/user-guide/deepagents/get-started/quickstart), and the [accepted architecture decision](https://github.com/NVIDIA/NemoClaw/issues/566#issuecomment-4847534784). @@ -25,7 +25,7 @@ NemoClaw v0.0.74 upgrades the OpenShell policy boundary, adds managed MCP and pr On Windows on Arm N1X systems, automatic Local Ollama setup treats the integrated GPU as compute-constrained and selects `qwen3.5:9b` instead of the 30B and 35B starter models. For more information, refer to [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands), [Install OpenClaw Plugins](/user-guide/openclaw/manage-sandboxes/install-openclaw-plugins), [Choose a Local Inference Server](/user-guide/openclaw/inference/local-inference/choose-local-inference-server), [Prepare Windows for NemoClaw](/user-guide/openclaw/get-started/additional-setup/windows-preparation), and [Troubleshooting](/user-guide/openclaw/reference/troubleshooting). - Messaging configuration now keeps channel policy ownership with the enabled channel, persists selected policy presets through onboarding and rebuilds, reports Telegram mention mode in channel status, and detects credential conflicts before a destructive rebuild starts. - For more information, refer to [Choose Messaging Channels](/user-guide/openclaw/manage-sandboxes/messaging-channels/choose-messaging-channels), [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). + For more information, refer to [Choose Messaging Channels](/user-guide/openclaw/manage-sandboxes/messaging-channels/choose-messaging-channels), [Apply Policy Presets](/user-guide/openclaw/network-policy/configure-policies/apply-policy-presets), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). - Day-two commands provide safer recovery and clearer automation behavior. `update --fresh` can reinstall the current version, and `destroy --force` can remove a local record when the OpenShell gateway is unavailable while warning that the sandbox and retained volume may still exist. Failed `exec` commands can surface recent policy-denial context, tunnel stop releases its gateway port, WSL keeps a usable loopback dashboard URL, and affected CLI user-error surfaces preserve a nonzero exit status. diff --git a/docs/changelog/2026-07-08.mdx b/docs/changelog/2026-07-08.mdx index 84d679ad17..7728f11681 100644 --- a/docs/changelog/2026-07-08.mdx +++ b/docs/changelog/2026-07-08.mdx @@ -24,7 +24,7 @@ NemoClaw v0.0.78 adds opt-in thread-scoped auto-approval and policy-routed repos For more information, refer to [Choose a Local Inference Server](/user-guide/openclaw/inference/local-inference/choose-local-inference-server) and [Troubleshooting](/user-guide/openclaw/reference/troubleshooting). - New `nemoclaw policy-get` output provides validated base-policy YAML suitable for review, editing, and reapplication, while `--raw` preserves the metadata-bearing response for diagnostics. The plugin registration banner now uses stderr, and `agents apply` tolerates warning-prefixed and wrapped JSON so command stdout remains usable by automation. - For more information, refer to [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy), [Common Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). + For more information, refer to [Replace the Live Network Policy](/user-guide/openclaw/network-policy/configure-policies/replace-live-network-policy), [Common Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), and [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). - Rebuild now prints redacted managed MCP destroy diagnostics before backup or deletion, recovers prepared-only transactions through `mcp remove --force`, and lets an explicit `rebuild --force` continue without a backup when a crashed sandbox cannot be reached. The no-backup path warns that prior sandbox state is not preserved, and gateway recovery reports its bounded retry budget. For more information, refer to [About Managed MCP Servers](/user-guide/openclaw/manage-sandboxes/mcp-servers/about-managed-mcp-servers), [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands), and [Recover and Rebuild Sandboxes](/user-guide/openclaw/manage-sandboxes/operate-sandboxes/recover-and-rebuild-sandboxes). diff --git a/docs/changelog/2026-07-09.mdx b/docs/changelog/2026-07-09.mdx index 43089dd4d4..d9878fe806 100644 --- a/docs/changelog/2026-07-09.mdx +++ b/docs/changelog/2026-07-09.mdx @@ -24,7 +24,7 @@ The release also refreshes quickstarts and variant rendering so OpenClaw, Hermes For more information, refer to [Security Best Practices](/user-guide/openclaw/security/best-practices), [Credential Storage](/user-guide/openclaw/security/credential-storage), [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands), and [Quickstart with LangChain Deep Agents Code](/user-guide/deepagents/get-started/quickstart). - Network policy and messaging behavior now preserve narrower boundaries. Homebrew Git operations require the GitHub policy preset for Git egress, Gmail has a documented policy preset and integration example, custom URL-based MCP server allowlists are documented, WhatsApp post-pair gateway restarts no longer require `operator.admin`, and the overview hides messaging-channel guidance from Deep Agents pages where the channel flow is not supported. - For more information, refer to [Network Policies](/user-guide/openclaw/reference/network-policies), [Common Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy), and [Choose Messaging Channels](/user-guide/openclaw/manage-sandboxes/messaging-channels/choose-messaging-channels). + For more information, refer to [Network Policies](/user-guide/openclaw/reference/network-policies), [Common Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), [Set Up Gmail With an App Password](/user-guide/openclaw/network-policy/set-up-gmail-with-an-app-password), [Create Custom Policy Presets](/user-guide/openclaw/network-policy/configure-policies/create-custom-policy-presets), and [Choose Messaging Channels](/user-guide/openclaw/manage-sandboxes/messaging-channels/choose-messaging-channels). - Onboarding and recovery paths preserve intent across more interrupted flows. Resume recovery now follows one explicit finite-state path, pending route reservations survive resume, sandbox create-failure reporting is separated from create-step handling, BuildKit progress no longer forces plain output, and null-name resume sessions are covered so canceled or malformed session state does not send users down the wrong recovery path. For more information, refer to [NemoClaw Quickstart with OpenClaw](/user-guide/openclaw/get-started/quickstart), [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands), [Recover and Rebuild Sandboxes](/user-guide/openclaw/manage-sandboxes/operate-sandboxes/recover-and-rebuild-sandboxes), and [Troubleshooting](/user-guide/openclaw/reference/troubleshooting). diff --git a/docs/changelog/2026-07-12.mdx b/docs/changelog/2026-07-12.mdx index 63b4eadc3e..0ebaaf86fe 100644 --- a/docs/changelog/2026-07-12.mdx +++ b/docs/changelog/2026-07-12.mdx @@ -32,4 +32,4 @@ NemoClaw v0.0.81 strengthens rebuild and snapshot state preservation, repairs lo - Security and policy diagnostics preserve more context without hiding risk. OpenClaw security audits keep NemoClaw-managed dashboard compatibility findings visible with their severity, remediation, and recorded reason, while token-shaped URL query values are redacted even when their parameter names look benign. The custom Streamable HTTP MCP policy recipe also scopes `DELETE` to the exact MCP endpoint used for session termination. - For more information, refer to [Security Best Practices](/user-guide/openclaw/security/best-practices) and [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy). + For more information, refer to [Security Best Practices](/user-guide/openclaw/security/best-practices) and [Create Custom Policy Presets](/user-guide/openclaw/network-policy/configure-policies/create-custom-policy-presets). diff --git a/docs/changelog/2026-07-14.mdx b/docs/changelog/2026-07-14.mdx index a8a5d55cc5..6d2f57ffae 100644 --- a/docs/changelog/2026-07-14.mdx +++ b/docs/changelog/2026-07-14.mdx @@ -59,7 +59,7 @@ NemoClaw v0.0.82 adds non-destructive sandbox stop and start commands, protects - Custom policy application rejects catch-all destinations before widening sandbox egress. Runtime custom presets now reject `*`, `0.0.0.0`, `0.0.0.0/0`, `::`, and `::/0` while continuing to allow scoped subdomain wildcards such as `*.example.com`. The same semantic check protects repository validation, `policy-add --from-file`, and in-memory custom preset application. - For more information, refer to [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy). + For more information, refer to [Create Custom Policy Presets](/user-guide/openclaw/network-policy/configure-policies/create-custom-policy-presets). - NemoClaw now requires Node.js 22.19 or later for host installs and contributor tooling, matching current OpenClaw runtime and advisor SDK requirements. Ubuntu 26.04 has a digest-pinned userspace contract lane for CLI, preflight, installer, and platform checks, while Docker-host, AppArmor, Landlock, and live onboarding validation remain pending. For more information, refer to [Prerequisites](/user-guide/openclaw/get-started/prerequisites) and [Platform Support and Launch Claims](/user-guide/openclaw/reference/platform-support). diff --git a/docs/changelog/2026-07-24.mdx b/docs/changelog/2026-07-24.mdx index 26994a80c1..5d2322ac04 100644 --- a/docs/changelog/2026-07-24.mdx +++ b/docs/changelog/2026-07-24.mdx @@ -18,7 +18,7 @@ NemoClaw v0.0.94 strengthens sandbox restore and update behavior, adds machine-r - `policy-add` now compares an already-applied catalog preset with the live policy. It exits without mutation when the content matches and previews the update when the preset changed. Network policy guidance now explains when an endpoint requires `tls: skip` raw TLS passthrough and identifies the lost L7 inspection and credential-resolution controls. - For more information, refer to [Customize the Network Policy](/user-guide/openclaw/network-policy/customize-network-policy), [Common NemoClaw Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), and the [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). + For more information, refer to [Apply Policy Presets](/user-guide/openclaw/network-policy/configure-policies/apply-policy-presets), [Configure Raw TLS Passthrough](/user-guide/openclaw/network-policy/configure-policies/configure-raw-tls-passthrough), [Common NemoClaw Integration Policy Examples](/user-guide/openclaw/network-policy/integration-policy-examples), and the [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). - Onboarding now supports `--events=jsonl` for a versioned, redacted stream of canonical state-machine events. The human-readable progress stream remains on standard error, and closing or slowing the event stream does not cancel onboarding. DGX Spark resume preserves the selected managed vLLM Express path, managed vLLM rejects a model that does not support the detected platform before downloads, and compatibility recovery selects and probes one usable IPv4 resolver. diff --git a/docs/get-started/quickstart-langchain-deepagents-code.mdx b/docs/get-started/quickstart-langchain-deepagents-code.mdx index 241f81113e..1f8e8b58c6 100644 --- a/docs/get-started/quickstart-langchain-deepagents-code.mdx +++ b/docs/get-started/quickstart-langchain-deepagents-code.mdx @@ -318,383 +318,11 @@ OpenShell rejects provider deletion while any sandbox still has it attached. - NemoClaw can export Deep Agents Code traces to an OTLP/HTTP collector that you operate on the host. -The sandbox always targets one local collector address, while the collector owns the remote backend, credentials, TLS, batching, retry, and optional filtering. -Changing from LangSmith to another OTLP-compatible backend does not require a sandbox rebuild or policy change. - -The complete example below uses the primary tested NemoClaw platform, Linux with Docker, and the official OpenTelemetry Collector Contrib `0.155.0` image. -It binds the unauthenticated receiver only to the private Docker bridge address that the target sandbox resolves as `host.openshell.internal`. -Do not publish this receiver as `0.0.0.0:4318` on the host. -For general image and configuration-file mechanics, refer to [Install the Collector with Docker](https://opentelemetry.io/docs/collector/install/docker/). - -### Understand the Export Boundary - -Trace export is off by default and requires an explicit onboarding choice. -When enabled, the managed exporter can include bounded prompts, model responses, tool arguments, tool results, operation names, model and tool names, and success or error information. -Treat the resulting traces as sensitive application data even when your normal prompts do not contain secrets. - -Managed capture selects at most 8,000 source characters from each captured string before adding truncation metadata, limits each mapping or sequence to 50 items, and limits nesting to 8 levels. -Each captured value also has an aggregate budget of 2,048 traversed nodes and 50,000 source string characters. -Repeated or cyclic containers are replaced with a reference-omission marker instead of being expanded again. -After bounding a value, a JSON encoding longer than 50,000 characters is replaced by a constant opaque marker and a 16,000-character serialized preview. -Other opaque objects are replaced by the same constant marker without reading their class name or string representation. -It replaces binary values with their byte count and bounds dictionary key names, replacing credential-shaped matches in those names with ``. -When a dictionary key matches a recognized credential, header, cookie, password, token, checkpoint, resume, or interrupt class, it replaces the associated value with ``. -It also replaces original exception text with a stable redacted error. -Model request traces include only the bounded messages and sanitized model identifier. -They exclude request headers, `model_settings`, `response_format`, and tool definitions or schemas. -Model and tool spans carry the bounded content used for debugging. -LangGraph node scopes export only bounded node names, a static LangGraph integration label, and success or error status. -They omit raw graph inputs and outputs, callback metadata, checkpoint payloads, and interrupt or resume values so a node span does not duplicate the full conversation and graph state. -These controls bound payload shape and remove recognized key classes. -As a best-effort second layer, the managed exporter also scrubs recognized credential-shaped tokens, such as provider API keys, bearer tokens, and private key blocks, from bounded prompt, response, tool, and other captured string content and replaces each match with ``. -Identifier fields are scrubbed before sanitization and carry the identifier-safe text `redacted-secret` instead. -This value scrubbing is pattern-based and not exhaustive: a secret in an obfuscated or unrecognized form, or any sensitive text that does not match a known credential shape, can still be exported. -Complete redaction depends on upstream content controls and on the redaction processors you run in the host collector. - -The sandbox sends OTLP/HTTP protobuf requests only to `http://host.openshell.internal:4318/v1/traces` and reports `service.name=nemoclaw-langchain-deepagents-code`. -The OTLP library adds standard transport headers such as content type and content length, but the managed exporter cannot add operator-supplied custom or authentication headers. -It cannot select a remote endpoint or receive a backend credential. -Native LangSmith tracing and ambient OpenTelemetry exporter configuration remain disabled inside the sandbox. -Do not put `LANGSMITH_API_KEY` or another backend credential in the sandbox. - -Exporter initialization, delivery, and flush failures do not stop Deep Agents Code work. -This fail-open behavior keeps tracing outages from blocking the agent, but it also means successful agent work does not prove that traces were delivered. - - -The `observability-otlp-local` preset authorizes `/opt/venv/bin/python3*`, which is the executable OpenShell observes for Deep Agents Code. -That permission is process-wide for the managed Python environment rather than limited to the `dcode` launcher. -Sandbox Python can forge spans, resource attributes, and `service.name`, so the collector must not use trace fields as authenticated tenant identity. -Any process that can reach this receiver can submit trace content without a receiver credential. -Bind the receiver only to the private sandbox bridge, use it only with trusted local sandboxes, and apply your organization's filtering or redaction requirements in the host collector before remote export. -This path is not a multi-tenant identity or data-loss-prevention boundary. - - -### Enable Trace Export - -Set the sandbox name in the host shell, then opt in during initial onboarding. - -```bash -export SANDBOX_NAME=my-dcode -nemo-deepagents onboard --name "$SANDBOX_NAME" --observability -``` - -NemoClaw records the choice with the onboarding session and sandbox. -Resume and rebuild operations preserve it without requiring the flag again. - -To enable tracing on an existing Deep Agents Code sandbox, use the transactional rebuild opt-in. -NemoClaw backs up the declared agent state, preserves managed MCP providers and adapter state, recreates the sandbox, and restores the backup. -Finish active `dcode` tasks first because Deep Agents Code backup refuses to capture state while a task is running. - -```bash -export SANDBOX_NAME=my-dcode -nemo-deepagents "$SANDBOX_NAME" rebuild --observability --yes -``` - -The setting is part of the sandbox startup environment, so changing it cannot reuse the existing sandbox process. - -### Recover a Skipped Policy - -Balanced and Open policy tiers add the `observability-otlp-local` preset during onboarding. -The Restricted tier suppresses it. -`NEMOCLAW_POLICY_MODE=skip` skips policy application and reconciliation during non-interactive onboarding. -On a new sandbox, either choice leaves the preset inactive, so the fail-open exporter cannot reach the collector until you add it. -On an existing sandbox, skip mode leaves the current live policy unchanged. - -Inspect the effective policy first. - -```bash -nemo-deepagents "$SANDBOX_NAME" policy-list -``` - -If `observability-otlp-local` is not active, preview and apply it. - -```bash -nemo-deepagents "$SANDBOX_NAME" policy-add observability-otlp-local --dry-run -nemo-deepagents "$SANDBOX_NAME" policy-add observability-otlp-local --yes -``` - -The preset permits only `POST /v1/traces` to `host.openshell.internal:4318` from `/opt/venv/bin/python3*`. -On the Restricted tier, the next onboarding or rebuild reconciliation removes this manually added preset unless you change tiers. - -### Create LangSmith Credentials - -LangSmith is one possible downstream backend for the same backend-neutral receiver. -Create a workspace-scoped service key for the collector when your LangSmith plan supports service keys. -Otherwise, create a personal access token for the collector. -Record the target workspace ID from LangSmith settings because this configuration sends `X-Tenant-Id` explicitly. -For key types, permissions, and the workspace ID location, refer to [Create an account and API key](https://docs.langchain.com/langsmith/create-account-api-key). - -Set the credential only in the host shell that starts the collector. -The following endpoint is for the default US LangSmith Cloud deployment. - -```bash -read -rsp "LangSmith API key: " LANGSMITH_API_KEY -printf '\n' -export LANGSMITH_API_KEY -export LANGSMITH_WORKSPACE_ID='replace-with-workspace-id' -export LANGSMITH_PROJECT=nemoclaw-dcode -export LANGSMITH_OTLP_TRACES_ENDPOINT=https://api.smith.langchain.com/otel/v1/traces -``` - -Use `https://eu.api.smith.langchain.com/otel/v1/traces` for the EU deployment, `https://apac.api.smith.langchain.com/otel/v1/traces` for the GCP-hosted APAC deployment, or `https://aws.api.smith.langchain.com/otel/v1/traces` for the AWS-hosted US deployment. -For a self-hosted deployment, append `/api/v1/otel/v1/traces` to the LangSmith instance origin, for example `https://langsmith.example.com/api/v1/otel/v1/traces`. -The self-hosted OTLP base is `/api/v1/otel`, and the per-signal traces exporter adds `/v1/traces`. -The `X-Tenant-Id` header in the collector configuration selects the workspace and is required for organization-scoped service keys. -For current endpoint guidance and supported OpenTelemetry field mappings, refer to [Trace with OpenTelemetry](https://docs.langchain.com/langsmith/trace-with-opentelemetry). - -### Find the Private Host Bind Address - -Resolve `host.openshell.internal` from the target sandbox, then verify that the resulting private IPv4 address belongs to a host interface. -This recipe intentionally supports the Linux Docker topology and fails closed if the address is empty, public, or not assigned to the host. - -```bash -OTLP_BIND_IP="$( - nemo-deepagents "$SANDBOX_NAME" exec -- \ - sh -lc "getent ahostsv4 host.openshell.internal | awk 'NR == 1 { print \$1 }'" -)" - -if [ -z "$OTLP_BIND_IP" ]; then - printf '%s\n' 'Could not resolve host.openshell.internal from the sandbox.' >&2 - exit 1 -fi - -case "$OTLP_BIND_IP" in - 10.*|192.168.*|172.1[6-9].*|172.2[0-9].*|172.3[01].*) ;; - *) - printf 'Refusing non-private collector bind address: %s\n' "$OTLP_BIND_IP" >&2 - exit 1 - ;; -esac - -if ! ip -o -4 address show \ - | awk '{ sub(/\/.*/, "", $4); print $4 }' \ - | grep -Fxq "$OTLP_BIND_IP"; then - printf 'Address is not assigned to this host: %s\n' "$OTLP_BIND_IP" >&2 - exit 1 -fi - -printf 'Collector bind address: %s\n' "$OTLP_BIND_IP" -``` - -Binding to the bridge address prevents ordinary LAN exposure, but other trusted local containers can still have a route to it. -Use a host firewall or equivalent ACL if your Docker host runs containers outside your trust boundary. -NemoClaw does not support shared multi-user hosts as a security boundary. - -### Configure the Collector - -Create an owner-only directory for the collector configuration. - -```bash -export OTEL_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nemoclaw/otel" -install -d -m 700 "$OTEL_CONFIG_DIR" -``` - -Save the following configuration as `$OTEL_CONFIG_DIR/collector.yaml`. -The `debug` exporter uses basic verbosity, which records receipt counts in the collector log without printing complete span payloads. -This example deliberately preserves the useful trace content selected by the explicit sandbox opt-in. -Add organization-required filtering or redaction processors before `batch` if your data policy requires them. -For a LangSmith-specific example, refer to [Trace redaction through an OpenTelemetry Collector](https://docs.langchain.com/langsmith/otel-gateway-trace-redaction). - -```yaml -receivers: - otlp: - protocols: - http: - endpoint: 0.0.0.0:4318 - -processors: - memory_limiter: - check_interval: 1s - limit_mib: 256 - spike_limit_mib: 64 - batch: {} - -exporters: - debug: - verbosity: basic - otlphttp/langsmith: - traces_endpoint: "${env:LANGSMITH_OTLP_TRACES_ENDPOINT}" - headers: - x-api-key: "${env:LANGSMITH_API_KEY}" - Langsmith-Project: "${env:LANGSMITH_PROJECT}" - X-Tenant-Id: "${env:LANGSMITH_WORKSPACE_ID}" - sending_queue: - enabled: true - queue_size: 1000 - retry_on_failure: - enabled: true - -extensions: - health_check: - endpoint: 0.0.0.0:13133 - -service: - extensions: [health_check] - pipelines: - traces: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [debug, otlphttp/langsmith] -``` - -Restrict the configuration file to the current host user. - -```bash -chmod 600 "$OTEL_CONFIG_DIR/collector.yaml" -``` - -The receiver uses `0.0.0.0` only inside the collector container. -The Docker command in the next section publishes it on the host's exact private bridge address rather than every host interface. - -### Start and Verify the Collector - -Pull the pinned Contrib image and validate the effective configuration before starting a long-running collector. -The Contrib distribution is used because it contains the processors and extensions in this configuration. -The commands run the collector as your current host user so it can read the owner-only bind-mounted configuration without widening its file mode. - -```bash -export COLLECTOR_IMAGE=ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.155.0@sha256:4935caa35e9a4cb387e35732e8fb22b2b5759af8d12e7043357f03837f6e8df5 -: "${LANGSMITH_API_KEY:?Set LANGSMITH_API_KEY in this host shell.}" -: "${LANGSMITH_WORKSPACE_ID:?Set LANGSMITH_WORKSPACE_ID in this host shell.}" -: "${LANGSMITH_PROJECT:?Set LANGSMITH_PROJECT in this host shell.}" -: "${LANGSMITH_OTLP_TRACES_ENDPOINT:?Set LANGSMITH_OTLP_TRACES_ENDPOINT in this host shell.}" -: "${OTLP_BIND_IP:?Run the private bind address step first.}" -: "${OTEL_CONFIG_DIR:?Run the collector configuration step first.}" -docker pull "$COLLECTOR_IMAGE" -docker run --rm \ - --user "$(id -u):$(id -g)" \ - --read-only \ - --tmpfs /tmp:rw,noexec,nosuid,size=16m \ - --cap-drop ALL \ - --security-opt no-new-privileges:true \ - --memory 512m \ - --pids-limit 128 \ - --env LANGSMITH_API_KEY \ - --env LANGSMITH_WORKSPACE_ID \ - --env LANGSMITH_PROJECT \ - --env LANGSMITH_OTLP_TRACES_ENDPOINT \ - --mount "type=bind,src=${OTEL_CONFIG_DIR}/collector.yaml,dst=/etc/otelcol-contrib/config.yaml,readonly" \ - "$COLLECTOR_IMAGE" \ - validate --config=/etc/otelcol-contrib/config.yaml -``` - -An invalid configuration exits nonzero and prints the component or field that needs correction. -Start the collector only after validation succeeds. - -```bash -docker run --detach \ - --name nemoclaw-otel-langsmith \ - --restart unless-stopped \ - --user "$(id -u):$(id -g)" \ - --read-only \ - --tmpfs /tmp:rw,noexec,nosuid,size=16m \ - --cap-drop ALL \ - --security-opt no-new-privileges:true \ - --memory 512m \ - --pids-limit 128 \ - --log-opt max-size=10m \ - --log-opt max-file=3 \ - --publish "${OTLP_BIND_IP}:4318:4318/tcp" \ - --publish 127.0.0.1:13133:13133/tcp \ - --env LANGSMITH_API_KEY \ - --env LANGSMITH_WORKSPACE_ID \ - --env LANGSMITH_PROJECT \ - --env LANGSMITH_OTLP_TRACES_ENDPOINT \ - --mount "type=bind,src=${OTEL_CONFIG_DIR}/collector.yaml,dst=/etc/otelcol-contrib/config.yaml,readonly" \ - "$COLLECTOR_IMAGE" \ - --config=/etc/otelcol-contrib/config.yaml - -unset LANGSMITH_API_KEY -``` - -Users who can control the Docker daemon can inspect the collector process and its environment. -Use your organization's container secret injection mechanism instead of environment variables when Docker operator access is outside the credential trust boundary. - -Verify the loopback-only health endpoint and the published receiver address. - -```bash -curl -fsS http://127.0.0.1:13133/ -docker port nemoclaw-otel-langsmith 4318/tcp -docker logs --tail 30 nemoclaw-otel-langsmith -``` - -The port output must show the value of `$OTLP_BIND_IP`, not `0.0.0.0` or `[::]`. - -### Verify Traces End to End - -Run a short headless Deep Agents Code task to generate a managed trace. - -```bash -nemo-deepagents "$SANDBOX_NAME" exec -- \ - dcode -n "Reply with the single word traced." -``` - -Confirm that the collector received a trace batch and did not report a LangSmith exporter error. - -```bash -docker logs --since 5m nemoclaw-otel-langsmith 2>&1 | tail -n 100 -``` - -The basic debug exporter prints a trace count without printing the full payload. -Then open the project named by `$LANGSMITH_PROJECT` in the [LangSmith UI](https://smith.langchain.com/) and confirm that the new trace is present. -Both checks are required because the debug exporter can succeed while the remote LangSmith exporter fails. -The LangSmith trace should include bounded model inputs and outputs rather than metadata alone. -A representative task that invokes a tool should also show its bounded arguments and result on the associated tool span. -LangGraph node scopes intentionally remain operation-only as described in the export boundary above. - -### Stop or Disable Trace Export - -NemoClaw does not start, stop, upgrade, or remove this operator-owned collector container. -Stop and restart the host collector without changing the sandbox configuration. -While the collector is stopped, trace delivery fails open and Deep Agents Code continues working. - -```bash -docker stop nemoclaw-otel-langsmith -docker start nemoclaw-otel-langsmith -``` - -To revoke the sandbox's collector reachability immediately, remove the policy preset. -This does not change the recorded observability choice. -A later rebuild restores the matching preset on Balanced and Open tiers, while Restricted continues to suppress it. - -```bash -nemo-deepagents "$SANDBOX_NAME" policy-remove observability-otlp-local --yes -``` - -To disable instrumentation persistently, use the transactional rebuild negative flag. -NemoClaw performs the state-preserving recreation while preserving managed MCP providers and adapter state. -Finish active `dcode` tasks before running the command. - -```bash -nemo-deepagents "$SANDBOX_NAME" rebuild --no-observability --yes -``` - -Remove the collector only after every sandbox that uses it has been disabled or had the policy removed. - -```bash -docker rm -f nemoclaw-otel-langsmith -``` - -Recreate the collector container after changing its configuration, endpoint, project, workspace, or API key. - -### Troubleshoot Trace Export - -Use the following checks to isolate each hop in the export path. -For additional collector diagnostics, refer to [Troubleshooting the OpenTelemetry Collector](https://opentelemetry.io/docs/collector/troubleshooting/). - -| Symptom | Check and action | -| --- | --- | -| Collector exits at startup | Run the validation command again, then inspect `docker logs nemoclaw-otel-langsmith`. Confirm that the image is the Contrib `0.155.0` image and that all four `LANGSMITH_*` variables were set when the container was created. | -| Port `4318` is already allocated | Run `ss -ltnp 'sport = :4318'` and stop the conflicting listener. The managed sandbox endpoint is fixed, so changing the collector port does not work. | -| Collector is healthy but logs no trace count | Run `policy-list` and add `observability-otlp-local` if it is absent. Confirm that `docker port` shows the current `$OTLP_BIND_IP`. Run `nemo-deepagents rebuild --observability --yes` if the existing sandbox was originally started without the opt-in. | -| Collector logs `401` | Replace an invalid or expired LangSmith API key, then recreate the collector container. | -| Collector logs `403` | Confirm the service key can write to the target workspace and that `LANGSMITH_WORKSPACE_ID` matches that workspace. Organization-scoped service keys require `X-Tenant-Id`. | -| Collector logs `404` | Confirm that `LANGSMITH_OTLP_TRACES_ENDPOINT` uses the correct US, EU, GCP-hosted APAC, AWS-hosted US, or self-hosted API base and ends in `/otel/v1/traces`. | -| Collector logs `429` | Review LangSmith ingestion and plan limits, then allow the configured sending queue and retry policy to drain. | -| Debug exporter logs traces but the LangSmith project is empty | Inspect the same collector log for remote exporter errors, then verify the endpoint, project, workspace ID, and API key. | -| Agent succeeds while every trace check fails | This is expected fail-open behavior. Troubleshoot the policy, receiver bind, collector health, and remote exporter independently rather than using the agent exit status as delivery evidence. | - + Deep Agents trace export now has focused Monitoring pages. + Review [Understand Deep Agents Trace Export](../monitoring/understand-deepagents-trace-export) before you enable the exporter. + Follow [Set Up Deep Agents Trace Export](../monitoring/set-up-deepagents-trace-export) to configure the policy and host collector. + Use [Verify Deep Agents Trace Export](../monitoring/verify-deepagents-trace-export) to prove delivery or diagnose a failure. + Use [Manage Deep Agents Trace Export](../monitoring/manage-deepagents-trace-export) to stop, disable, reconfigure, or remove tracing. @@ -725,6 +353,7 @@ There is no dashboard port or long-running gateway process for this harness. - [Choose an Inference Provider](../inference/learn-and-choose/choose-inference-provider) explains how to choose a provider and model. - [Understand Sandbox State](../manage-sandboxes/state-and-backups/understand-sandbox-state) explains `/sandbox/.deepagents`, memory, skills, and what NemoClaw preserves. - [Create and Restore Snapshots](../manage-sandboxes/state-and-backups/create-and-restore-snapshots) explains snapshot and rebuild preservation. +- [Set Up Deep Agents Trace Export](../monitoring/set-up-deepagents-trace-export) configures the policy and host collector. - [Network Policies](../reference/network-policies#local-otlp-trace-export) explains the local collector egress preset. - [Troubleshooting](../reference/troubleshooting) covers common setup and runtime issues. - [Add an MCP Server](../manage-sandboxes/mcp-servers/add-an-mcp-server) explains managed MCP configuration for Deep Agents sandboxes. diff --git a/docs/index.yml b/docs/index.yml index ccfc1c2c8e..9a6a6fe661 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -278,9 +278,33 @@ navigation: - page: "Customize the Network Policy" path: _build/agent-variants/network-policy/customize-network-policy.openclaw.generated.mdx slug: customize-network-policy + - section: "Configure Policies" + slug: configure-policies + contents: + - page: "Change the Baseline Policy" + path: _build/agent-variants/network-policy/change-baseline-network-policy.openclaw.generated.mdx + slug: change-baseline-network-policy + - page: "Apply Policy Presets" + path: _build/agent-variants/network-policy/apply-policy-presets.openclaw.generated.mdx + slug: apply-policy-presets + - page: "Create Custom Presets" + path: _build/agent-variants/network-policy/create-custom-policy-presets.openclaw.generated.mdx + slug: create-custom-policy-presets + - page: "Configure Raw TLS" + path: _build/agent-variants/network-policy/configure-raw-tls-passthrough.openclaw.generated.mdx + slug: configure-raw-tls-passthrough + - page: "Replace the Live Policy" + path: _build/agent-variants/network-policy/replace-live-network-policy.openclaw.generated.mdx + slug: replace-live-network-policy + - page: "Explain Policy to Agents" + path: _build/agent-variants/network-policy/explain-network-policy-to-agents.openclaw.generated.mdx + slug: explain-network-policy-to-agents - page: "Integration Policy Examples" path: _build/agent-variants/network-policy/integration-policy-examples.openclaw.generated.mdx slug: integration-policy-examples + - page: "Set Up Gmail With an App Password" + path: _build/agent-variants/network-policy/set-up-gmail-with-an-app-password.openclaw.generated.mdx + slug: set-up-gmail-with-an-app-password - section: "Deployment" slug: deployment collapsed: open-by-default @@ -576,6 +600,22 @@ navigation: - page: "Deploy to a Headless Server" path: _build/agent-variants/deployment/deploy-to-headless-server.deepagents.generated.mdx slug: deploy-to-headless-server + - section: "Monitoring" + slug: monitoring + collapsed: open-by-default + contents: + - page: "Understand Trace Export" + path: monitoring/understand-deepagents-trace-export.mdx + slug: understand-deepagents-trace-export + - page: "Set Up Trace Export" + path: monitoring/set-up-deepagents-trace-export.mdx + slug: set-up-deepagents-trace-export + - page: "Verify Trace Export" + path: monitoring/verify-deepagents-trace-export.mdx + slug: verify-deepagents-trace-export + - page: "Manage Trace Export" + path: monitoring/manage-deepagents-trace-export.mdx + slug: manage-deepagents-trace-export - section: "Security" slug: security collapsed: open-by-default @@ -890,9 +930,33 @@ navigation: - page: "Customize the Network Policy" path: _build/agent-variants/network-policy/customize-network-policy.hermes.generated.mdx slug: customize-network-policy + - section: "Configure Policies" + slug: configure-policies + contents: + - page: "Change the Baseline Policy" + path: _build/agent-variants/network-policy/change-baseline-network-policy.hermes.generated.mdx + slug: change-baseline-network-policy + - page: "Apply Policy Presets" + path: _build/agent-variants/network-policy/apply-policy-presets.hermes.generated.mdx + slug: apply-policy-presets + - page: "Create Custom Presets" + path: _build/agent-variants/network-policy/create-custom-policy-presets.hermes.generated.mdx + slug: create-custom-policy-presets + - page: "Configure Raw TLS" + path: _build/agent-variants/network-policy/configure-raw-tls-passthrough.hermes.generated.mdx + slug: configure-raw-tls-passthrough + - page: "Replace the Live Policy" + path: _build/agent-variants/network-policy/replace-live-network-policy.hermes.generated.mdx + slug: replace-live-network-policy + - page: "Explain Policy to Agents" + path: _build/agent-variants/network-policy/explain-network-policy-to-agents.hermes.generated.mdx + slug: explain-network-policy-to-agents - page: "Integration Policy Examples" path: _build/agent-variants/network-policy/integration-policy-examples.hermes.generated.mdx slug: integration-policy-examples + - page: "Set Up Gmail With an App Password" + path: _build/agent-variants/network-policy/set-up-gmail-with-an-app-password.hermes.generated.mdx + slug: set-up-gmail-with-an-app-password - section: "Deployment" slug: deployment collapsed: open-by-default diff --git a/docs/inference/set-up-vllm.mdx b/docs/inference/set-up-vllm.mdx index 1474c9157f..7704403c85 100644 --- a/docs/inference/set-up-vllm.mdx +++ b/docs/inference/set-up-vllm.mdx @@ -270,17 +270,19 @@ curl -fsSL https://www.nvidia.com/nemoclaw.sh | \ Set `NEMOCLAW_VLLM_MODEL=` before onboarding to select a model without prompting. NemoClaw applies the registered `vllm serve` arguments, including the reasoning parser, tool-call parser, and `--max-model-len`. -| Slug | Hugging Face model | Notes | -|---|---|---| -| `qwen3.6-27b` | `Qwen/Qwen3.6-27B-FP8` | Supported override. | -| `qwen3.6-35b-a3b-nvfp4` | `nvidia/Qwen3.6-35B-A3B-NVFP4` | DGX Spark default. | -| `nemotron-3-nano-4b` | `nvidia/NVIDIA-Nemotron-3-Nano-4B-FP8` | Generic Linux NVIDIA GPU default. | -| `deepseek-v4-flash` | `deepseek-ai/DeepSeek-V4-Flash` | DGX Station profile default outside express install. | -| `nemotron-3-ultra-550b-a55b` | `nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4` | DGX Station express-install selection with a pinned model revision and model-specific vLLM image. | -| `deepseek-r1-distill-70b` | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | Gated and requires license acceptance. | +| Slug | Hugging Face model | Supported host profiles | Notes | +|---|---|---|---| +| `qwen3.6-27b` | `Qwen/Qwen3.6-27B-FP8` | DGX Spark, DGX Station, Linux with an NVIDIA GPU | Supported override. | +| `qwen3.6-35b-a3b-nvfp4` | `nvidia/Qwen3.6-35B-A3B-NVFP4` | DGX Spark | DGX Spark default. | +| `nemotron-3-nano-4b` | `nvidia/NVIDIA-Nemotron-3-Nano-4B-FP8` | DGX Spark, DGX Station, Linux with an NVIDIA GPU | Generic Linux NVIDIA GPU default. | +| `deepseek-v4-flash` | `deepseek-ai/DeepSeek-V4-Flash` | DGX Station | DGX Station profile default outside express install. | +| `nemotron-3-ultra-550b-a55b` | `nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4` | DGX Station | DGX Station express-install selection with a pinned model revision and model-specific vLLM image. | +| `deepseek-r1-distill-70b` | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | DGX Spark, DGX Station, Linux with an NVIDIA GPU | Gated and requires license acceptance. | Slugs are case-insensitive, and NemoClaw also accepts the full Hugging Face model ID. An unrecognized value fails before image or model downloads and prints the valid slugs. +A recognized override that does not support the detected host also fails before image or model downloads. +The error names the selected model and detected host profile. Gated models require a Hugging Face token and license acceptance. Follow [Authenticate Hugging Face Downloads](#authenticate-hugging-face-downloads) before onboarding so NemoClaw can forward the token temporarily to the one-shot model downloader. diff --git a/docs/monitoring/manage-deepagents-trace-export.mdx b/docs/monitoring/manage-deepagents-trace-export.mdx new file mode 100644 index 0000000000..12d8f9be1c --- /dev/null +++ b/docs/monitoring/manage-deepagents-trace-export.mdx @@ -0,0 +1,71 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Manage Deep Agents Trace Export" +sidebar-title: "Manage Trace Export" +description: "Stop, disable, reconfigure, or remove Deep Agents trace export and its host collector." +description-agent: "Manages Deep Agents trace export. Use when stopping the collector, revoking reachability, disabling instrumentation, rotating collector settings, or removing the collector." +keywords: ["manage deep agents traces", "disable nemoclaw observability", "remove otel collector"] +content: + type: "how_to" +--- +Manage sandbox instrumentation and the operator-owned host collector as separate lifecycle controls. +NemoClaw does not start, stop, upgrade, or remove the collector. + +## Set the Sandbox Name + +Set the target sandbox in the host shell: + +```bash +export SANDBOX_NAME=my-dcode +``` + +## Stop or Restart the Collector + +Stop and restart the collector without changing the sandbox: + +```bash +docker stop nemoclaw-otel-langsmith +docker start nemoclaw-otel-langsmith +``` + +While the collector is stopped, trace delivery fails open and Deep Agents Code continues working. + +## Revoke Collector Reachability + +Remove the policy preset to revoke collector reachability immediately: + +```bash +nemo-deepagents "$SANDBOX_NAME" policy-remove observability-otlp-local --yes +``` + +Removing the preset does not clear the recorded observability choice. +A later rebuild restores the preset on Balanced and Open tiers. +The Restricted tier continues to suppress it. + +## Disable Trace Export + +Disable instrumentation persistently with a transactional rebuild: + +```bash +nemo-deepagents "$SANDBOX_NAME" rebuild --no-observability --yes +``` + +Finish active `dcode` tasks before running the rebuild. +NemoClaw preserves declared agent state, managed MCP providers, and adapter state. + +## Remove or Reconfigure the Collector + +Remove the collector only after every sandbox that uses it has tracing disabled or the preset removed: + +```bash +docker rm -f nemoclaw-otel-langsmith +``` + +Recreate the collector after changing its configuration, endpoint, project, workspace, or API key. + +## Related Topics + +- [Set Up Deep Agents Trace Export](set-up-deepagents-trace-export) configures the policy and collector. +- [Verify Deep Agents Trace Export](verify-deepagents-trace-export) proves local and remote delivery. +- [Understand Deep Agents Trace Export](understand-deepagents-trace-export) explains fail-open behavior and trust boundaries. diff --git a/docs/monitoring/set-up-deepagents-trace-export.mdx b/docs/monitoring/set-up-deepagents-trace-export.mdx new file mode 100644 index 0000000000..230c21827d --- /dev/null +++ b/docs/monitoring/set-up-deepagents-trace-export.mdx @@ -0,0 +1,286 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Set Up Deep Agents Trace Export" +sidebar-title: "Set Up Trace Export" +description: "Enable Deep Agents trace export and configure a host OpenTelemetry collector." +description-agent: "Sets up Deep Agents trace export. Use when enabling observability, recovering the OTLP policy, binding a local collector, or exporting to LangSmith." +keywords: ["set up deep agents otlp", "nemoclaw observability collector", "langsmith otel collector"] +content: + type: "how_to" +--- +Enable Deep Agents trace export, then configure an operator-owned collector on the host. +This example uses Linux with Docker and the OpenTelemetry Collector Contrib `0.155.0` image. +Do not publish the unauthenticated receiver as `0.0.0.0:4318` on the host. +For general image and configuration-file mechanics, refer to [Install the Collector with Docker](https://opentelemetry.io/docs/collector/install/docker/). + + +Review [Understand Deep Agents Trace Export](understand-deepagents-trace-export) before enabling the exporter. +The traces can contain sensitive application data, and the local receiver has no authentication. + + +## Enable Trace Export + +Set the sandbox name in the host shell. +Opt in during initial onboarding: + +```bash +export SANDBOX_NAME=my-dcode +nemo-deepagents onboard --name "$SANDBOX_NAME" --observability +``` + +NemoClaw records the choice with the onboarding session and sandbox. +Resume and rebuild operations preserve the choice. + +To enable tracing on an existing sandbox, use the transactional rebuild opt-in. +Finish active `dcode` tasks because Deep Agents Code backup refuses to capture state while a task is running. +The transaction preserves declared agent state, managed MCP providers, and adapter state while it recreates the sandbox. + +```bash +export SANDBOX_NAME=my-dcode +nemo-deepagents "$SANDBOX_NAME" rebuild --observability --yes +``` + +Changing the setting requires a new sandbox process because it changes the startup environment. + +## Recover a Skipped Policy + +Balanced and Open policy tiers add the `observability-otlp-local` preset during onboarding. +The Restricted tier suppresses it. +`NEMOCLAW_POLICY_MODE=skip` skips policy application and reconciliation during non-interactive onboarding. +On a new sandbox, either choice leaves the preset inactive. +On an existing sandbox, skip mode leaves the live policy unchanged. + +Inspect the effective policy: + +```bash +nemo-deepagents "$SANDBOX_NAME" policy-list +``` + +If `observability-otlp-local` is not active, preview and apply it: + +```bash +nemo-deepagents "$SANDBOX_NAME" policy-add observability-otlp-local --dry-run +nemo-deepagents "$SANDBOX_NAME" policy-add observability-otlp-local --yes +``` + +The preset permits only `POST /v1/traces` to `host.openshell.internal:4318` from `/opt/venv/bin/python3*`. +On the Restricted tier, the next onboarding or rebuild reconciliation removes this manually added preset unless you change tiers. + +## Create LangSmith Credentials + +LangSmith is one possible downstream backend for the backend-neutral receiver. +Create a workspace-scoped service key when your LangSmith plan supports service keys. +Otherwise, create a personal access token for the collector. +Record the target workspace ID because the configuration sends `X-Tenant-Id`. +For current key types and the workspace ID location, refer to [Create an account and API key](https://docs.langchain.com/langsmith/create-account-api-key). + +Set the credential only in the host shell that starts the collector. +The following endpoint is for the default US LangSmith Cloud deployment: + +```bash +read -rsp "LangSmith API key: " LANGSMITH_API_KEY +printf '\n' +export LANGSMITH_API_KEY +export LANGSMITH_WORKSPACE_ID='replace-with-workspace-id' +export LANGSMITH_PROJECT=nemoclaw-dcode +export LANGSMITH_OTLP_TRACES_ENDPOINT=https://api.smith.langchain.com/otel/v1/traces +``` + +Choose the endpoint for the LangSmith Cloud deployment: + +- Default US: `https://api.smith.langchain.com/otel/v1/traces` +- EU: `https://eu.api.smith.langchain.com/otel/v1/traces` +- GCP-hosted APAC: `https://apac.api.smith.langchain.com/otel/v1/traces` +- AWS-hosted US: `https://aws.api.smith.langchain.com/otel/v1/traces` + +For a self-hosted deployment, append `/api/v1/otel/v1/traces` to the LangSmith instance origin. +The self-hosted OTLP base is `/api/v1/otel`, and the traces exporter adds `/v1/traces`. +Organization-scoped service keys require the `X-Tenant-Id` header. +For endpoint guidance and supported field mappings, refer to [Trace with OpenTelemetry](https://docs.langchain.com/langsmith/trace-with-opentelemetry). + +## Find the Private Host Bind Address + +Resolve `host.openshell.internal` from the target sandbox. +Verify that the resulting private IPv4 address belongs to a host interface. +The following command fails when the address is empty, public, or not assigned to the host: + +```bash +OTLP_BIND_IP="$( + nemo-deepagents "$SANDBOX_NAME" exec -- \ + sh -lc "getent ahostsv4 host.openshell.internal | awk 'NR == 1 { print \$1 }'" +)" + +if [ -z "$OTLP_BIND_IP" ]; then + printf '%s\n' 'Could not resolve host.openshell.internal from the sandbox.' >&2 + exit 1 +fi + +case "$OTLP_BIND_IP" in + 10.*|192.168.*|172.1[6-9].*|172.2[0-9].*|172.3[01].*) ;; + *) + printf 'Refusing non-private collector bind address: %s\n' "$OTLP_BIND_IP" >&2 + exit 1 + ;; +esac + +if ! ip -o -4 address show \ + | awk '{ sub(/\/.*/, "", $4); print $4 }' \ + | grep -Fxq "$OTLP_BIND_IP"; then + printf 'Address is not assigned to this host: %s\n' "$OTLP_BIND_IP" >&2 + exit 1 +fi + +printf 'Collector bind address: %s\n' "$OTLP_BIND_IP" +``` + +Binding to the bridge address prevents ordinary LAN exposure. +Other trusted local containers can still have a route to it. +Use a host firewall or ACL when the Docker host runs containers outside your trust boundary. +NemoClaw does not support shared multi-user hosts as a security boundary. + +## Configure the Collector + +Create an owner-only directory: + +```bash +export OTEL_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nemoclaw/otel" +install -d -m 700 "$OTEL_CONFIG_DIR" +``` + +Save this configuration as `$OTEL_CONFIG_DIR/collector.yaml`. +The `debug` exporter records receipt counts without printing complete span payloads. +Add organization-required filtering or redaction processors before `batch`. +For one LangSmith example, refer to [Trace redaction through an OpenTelemetry Collector](https://docs.langchain.com/langsmith/otel-gateway-trace-redaction). + +```yaml +receivers: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + +processors: + memory_limiter: + check_interval: 1s + limit_mib: 256 + spike_limit_mib: 64 + batch: {} + +exporters: + debug: + verbosity: basic + otlphttp/langsmith: + traces_endpoint: "${env:LANGSMITH_OTLP_TRACES_ENDPOINT}" + headers: + x-api-key: "${env:LANGSMITH_API_KEY}" + Langsmith-Project: "${env:LANGSMITH_PROJECT}" + X-Tenant-Id: "${env:LANGSMITH_WORKSPACE_ID}" + sending_queue: + enabled: true + queue_size: 1000 + retry_on_failure: + enabled: true + +extensions: + health_check: + endpoint: 0.0.0.0:13133 + +service: + extensions: [health_check] + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [debug, otlphttp/langsmith] +``` + +Restrict the configuration: + +```bash +chmod 600 "$OTEL_CONFIG_DIR/collector.yaml" +``` + +The receiver uses `0.0.0.0` only inside the collector container. +The Docker command publishes it on the exact private bridge address. + +## Validate and Start the Collector + +Pull the pinned Contrib image. +Validate the effective configuration before starting the long-running collector. +The commands run the collector as the current host user so it can read the owner-only configuration. + +```bash +export COLLECTOR_IMAGE=ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.155.0@sha256:4935caa35e9a4cb387e35732e8fb22b2b5759af8d12e7043357f03837f6e8df5 +: "${LANGSMITH_API_KEY:?Set LANGSMITH_API_KEY in this host shell.}" +: "${LANGSMITH_WORKSPACE_ID:?Set LANGSMITH_WORKSPACE_ID in this host shell.}" +: "${LANGSMITH_PROJECT:?Set LANGSMITH_PROJECT in this host shell.}" +: "${LANGSMITH_OTLP_TRACES_ENDPOINT:?Set LANGSMITH_OTLP_TRACES_ENDPOINT in this host shell.}" +: "${OTLP_BIND_IP:?Run the private bind address step first.}" +: "${OTEL_CONFIG_DIR:?Run the collector configuration step first.}" +docker pull "$COLLECTOR_IMAGE" +docker run --rm \ + --user "$(id -u):$(id -g)" \ + --read-only \ + --tmpfs /tmp:rw,noexec,nosuid,size=16m \ + --cap-drop ALL \ + --security-opt no-new-privileges:true \ + --memory 512m \ + --pids-limit 128 \ + --env LANGSMITH_API_KEY \ + --env LANGSMITH_WORKSPACE_ID \ + --env LANGSMITH_PROJECT \ + --env LANGSMITH_OTLP_TRACES_ENDPOINT \ + --mount "type=bind,src=${OTEL_CONFIG_DIR}/collector.yaml,dst=/etc/otelcol-contrib/config.yaml,readonly" \ + "$COLLECTOR_IMAGE" \ + validate --config=/etc/otelcol-contrib/config.yaml +``` + +An invalid configuration exits nonzero and identifies the field that needs correction. +Start the collector only after validation succeeds: + +```bash +docker run --detach \ + --name nemoclaw-otel-langsmith \ + --restart unless-stopped \ + --user "$(id -u):$(id -g)" \ + --read-only \ + --tmpfs /tmp:rw,noexec,nosuid,size=16m \ + --cap-drop ALL \ + --security-opt no-new-privileges:true \ + --memory 512m \ + --pids-limit 128 \ + --log-opt max-size=10m \ + --log-opt max-file=3 \ + --publish "${OTLP_BIND_IP}:4318:4318/tcp" \ + --publish 127.0.0.1:13133:13133/tcp \ + --env LANGSMITH_API_KEY \ + --env LANGSMITH_WORKSPACE_ID \ + --env LANGSMITH_PROJECT \ + --env LANGSMITH_OTLP_TRACES_ENDPOINT \ + --mount "type=bind,src=${OTEL_CONFIG_DIR}/collector.yaml,dst=/etc/otelcol-contrib/config.yaml,readonly" \ + "$COLLECTOR_IMAGE" \ + --config=/etc/otelcol-contrib/config.yaml + +unset LANGSMITH_API_KEY +``` + +Users who control the Docker daemon can inspect the collector process and environment. +Use your organization's container secret injection mechanism when Docker operator access is outside the credential trust boundary. + +Verify the health endpoint and published receiver address: + +```bash +curl -fsS http://127.0.0.1:13133/ +docker port nemoclaw-otel-langsmith 4318/tcp +docker logs --tail 30 nemoclaw-otel-langsmith +``` + +The port output must show `$OTLP_BIND_IP`, not `0.0.0.0` or `[::]`. + +## Next Steps + +- [Verify Deep Agents Trace Export](verify-deepagents-trace-export) confirms local and remote delivery. +- [Manage Deep Agents Trace Export](manage-deepagents-trace-export) covers stop, disable, reconfiguration, and removal operations. +- [Understand Deep Agents Trace Export](understand-deepagents-trace-export) explains capture and trust boundaries. +- [Network Policies](../reference/network-policies#local-otlp-trace-export) documents the local collector preset. diff --git a/docs/monitoring/understand-deepagents-trace-export.mdx b/docs/monitoring/understand-deepagents-trace-export.mdx new file mode 100644 index 0000000000..51e1cbabbc --- /dev/null +++ b/docs/monitoring/understand-deepagents-trace-export.mdx @@ -0,0 +1,87 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Understand Deep Agents Trace Export" +sidebar-title: "Understand Trace Export" +description: "Review the data, redaction limits, transport, and trust boundaries for Deep Agents trace export." +description-agent: "Explains Deep Agents trace export boundaries. Use when evaluating captured data, redaction limits, OTLP transport, fail-open behavior, or collector trust." +keywords: ["deep agents trace export", "nemoclaw otlp privacy", "dcode observability security"] +content: + type: "concept" +--- +NemoClaw can export Deep Agents Code traces to an OTLP/HTTP collector that you operate on the host. +Review the data and trust boundaries before you enable the exporter. + +## Understand the Export Path + +The sandbox always targets `http://host.openshell.internal:4318/v1/traces`. +The host collector owns the remote backend, credentials, TLS, batching, retry, and optional filtering. +Changing from LangSmith to another OTLP-compatible backend does not require a sandbox rebuild or policy change. + +The sandbox reports `service.name=nemoclaw-langchain-deepagents-code`. +The OTLP library adds standard transport headers such as content type and content length. +The managed exporter cannot add operator-supplied custom or authentication headers. +It cannot select a remote endpoint or receive a backend credential. + +Native LangSmith tracing and ambient OpenTelemetry exporter configuration remain disabled inside the sandbox. +Do not put `LANGSMITH_API_KEY` or another backend credential in the sandbox. + +Exporter initialization, delivery, and flush failures do not stop Deep Agents Code work. +This fail-open behavior keeps tracing outages from blocking the agent. +Successful agent work does not prove that traces were delivered. + +## Review Captured Data + +Trace export is off by default and requires an explicit onboarding or rebuild choice. +When enabled, the exporter can include bounded prompts, model responses, tool arguments, tool results, operation names, model and tool names, and success or error information. +Treat the traces as sensitive application data. + +Managed capture selects at most 8,000 source characters from each captured string before adding truncation metadata. +It limits each mapping or sequence to 50 items and limits nesting to 8 levels. +Each captured value also has an aggregate budget of 2,048 traversed nodes and 50,000 source string characters. +Repeated or cyclic containers become a reference-omission marker. + +After bounding a value, a JSON encoding longer than 50,000 characters becomes a constant opaque marker and a 16,000-character serialized preview. +Other opaque objects become the same constant marker without reading their class name or string representation. +Binary values become their byte count. + +Dictionary key names are bounded, and credential-shaped matches in key names become ``. +When a dictionary key matches a recognized credential, header, cookie, password, token, checkpoint, resume, or interrupt class, its value becomes ``. +Original exception text becomes a stable redacted error. + +Model request traces include only bounded messages and a sanitized model identifier. +They exclude request headers, `model_settings`, `response_format`, and tool definitions or schemas. + +Model and tool spans carry bounded content for debugging. +LangGraph node scopes export only bounded node names, a static integration label, and success or error status. +They omit graph inputs and outputs, callback metadata, checkpoint payloads, and interrupt or resume values. + +The exporter also applies a best-effort scrub pass to captured strings. +It replaces recognized provider API keys, bearer tokens, private key blocks, and similar values with ``. +Identifier fields use the identifier-safe text `redacted-secret`. + +This pattern-based pass is not exhaustive. +An obfuscated secret, an unrecognized credential shape, or other sensitive text can still be exported. +Complete redaction depends on upstream content controls and the processors in the host collector. + +## Treat the Receiver as a Trust Boundary + + +The `observability-otlp-local` preset authorizes `/opt/venv/bin/python3*`. +This permission covers the managed Python environment rather than only the `dcode` launcher. +Sandbox Python can forge spans, resource attributes, and `service.name`. +The collector must not use trace fields as authenticated tenant identity. +Any process that can reach the receiver can submit trace content without a receiver credential. + + +Bind the receiver only to the private sandbox bridge. +Use it only with trusted local sandboxes. +Apply your organization's filtering or redaction requirements before remote export. +This path is not a multi-tenant identity or data-loss-prevention boundary. + +## Next Steps + +- [Set Up Deep Agents Trace Export](set-up-deepagents-trace-export) enables the sandbox and configures a host collector. +- [Verify Deep Agents Trace Export](verify-deepagents-trace-export) proves local and remote delivery. +- [Manage Deep Agents Trace Export](manage-deepagents-trace-export) stops, disables, reconfigures, or removes trace export. +- [Credential Storage](../security/credential-storage) explains host and sandbox credential boundaries. diff --git a/docs/monitoring/verify-deepagents-trace-export.mdx b/docs/monitoring/verify-deepagents-trace-export.mdx new file mode 100644 index 0000000000..2c90d0ad5c --- /dev/null +++ b/docs/monitoring/verify-deepagents-trace-export.mdx @@ -0,0 +1,69 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Verify Deep Agents Trace Export" +sidebar-title: "Verify Trace Export" +description: "Verify Deep Agents trace delivery and diagnose each export hop." +description-agent: "Verifies Deep Agents trace export. Use when proving local and remote delivery or diagnosing OTLP failures." +keywords: ["verify deep agents traces", "trace delivery diagnosis", "troubleshoot otlp collector"] +content: + type: "how_to" +--- +Verify the local collector and downstream backend independently. +Deep Agents work continues when export fails, so the agent exit status is not delivery evidence. + +## Set the Sandbox Name + +Set the target sandbox in the host shell: + +```bash +export SANDBOX_NAME=my-dcode +``` + +## Verify Traces End to End + +Run a short headless task to generate a managed trace: + +```bash +nemo-deepagents "$SANDBOX_NAME" exec -- \ + dcode -n "Reply with the single word traced." +``` + +Confirm that the collector received a trace batch and did not report a downstream exporter error: + +```bash +docker logs --since 5m nemoclaw-otel-langsmith 2>&1 | tail -n 100 +``` + +The basic debug exporter prints a trace count without printing the full payload. +Open the project named by `$LANGSMITH_PROJECT` in the [LangSmith UI](https://smith.langchain.com/). +Confirm that the new trace is present. +Both checks are required because the debug exporter can succeed while the remote exporter fails. + +The LangSmith trace should include bounded model inputs and outputs. +A representative tool task should also show bounded arguments and results on the tool span. +LangGraph node scopes remain operation-only as described in [Understand Deep Agents Trace Export](understand-deepagents-trace-export). + +## Troubleshoot Trace Export + +Use these checks to isolate each hop. +For additional collector diagnostics, refer to [Troubleshooting the OpenTelemetry Collector](https://opentelemetry.io/docs/collector/troubleshooting/). + +| Symptom | Check and action | +| --- | --- | +| Collector exits at startup | Run the validation command again, then inspect `docker logs nemoclaw-otel-langsmith`. Confirm that the image is the Contrib `0.155.0` image and that all four `LANGSMITH_*` variables were set when the container was created. | +| Port `4318` is already allocated | Run `ss -ltnp 'sport = :4318'` and stop the conflicting listener. The managed sandbox endpoint is fixed, so changing the collector port does not work. | +| Collector is healthy but logs no trace count | Run `policy-list` and add `observability-otlp-local` if it is absent. Confirm that `docker port` shows the current `$OTLP_BIND_IP`. Run `nemo-deepagents rebuild --observability --yes` if the sandbox was started without the opt-in. | +| Collector logs `401` | Replace an invalid or expired LangSmith API key, then recreate the collector. | +| Collector logs `403` | Confirm that the service key can write to the target workspace and that `LANGSMITH_WORKSPACE_ID` matches that workspace. Organization-scoped service keys require `X-Tenant-Id`. | +| Collector logs `404` | Confirm that `LANGSMITH_OTLP_TRACES_ENDPOINT` uses the correct US, EU, GCP-hosted APAC, AWS-hosted US, or self-hosted API base and ends in `/otel/v1/traces`. | +| Collector logs `429` | Review LangSmith ingestion and plan limits, then allow the configured queue and retry policy to drain. | +| Debug exporter logs traces but the LangSmith project is empty | Inspect the collector log for remote exporter errors. Verify the endpoint, project, workspace ID, and API key. | +| Agent succeeds while every trace check fails | This is expected fail-open behavior. Check the policy, receiver bind, collector health, and remote exporter instead of using the agent exit status as delivery evidence. | + +## Related Topics + +- [Set Up Deep Agents Trace Export](set-up-deepagents-trace-export) configures the policy and collector. +- [Manage Deep Agents Trace Export](manage-deepagents-trace-export) covers stop, disable, reconfiguration, and removal operations. +- [Understand Deep Agents Trace Export](understand-deepagents-trace-export) explains privacy and trust boundaries. +- [Troubleshooting](../reference/troubleshooting) covers broader sandbox and runtime failures. diff --git a/docs/network-policy/apply-policy-presets.mdx b/docs/network-policy/apply-policy-presets.mdx new file mode 100644 index 0000000000..4b0e1f2707 --- /dev/null +++ b/docs/network-policy/apply-policy-presets.mdx @@ -0,0 +1,107 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Apply Policy Presets" +sidebar-title: "Apply Policy Presets" +description: "Add, reapply, list, or remove policy presets for a running NemoClaw sandbox." +description-agent: "Applies and manages policy presets for a running sandbox. Use when adding maintained integration access, previewing preset scope, reapplying an edited preset, or removing access." +keywords: ["nemoclaw policy presets", "policy-add", "policy-remove"] +content: + type: "how_to" +skill: + priority: 10 +--- +Use policy presets to add reviewed network access to one running sandbox without replacing its current policy. +NemoClaw records applied presets so rebuild and restore operations can replay them. + + +Use `$$nemoclaw policy-add` to merge a preset into the running policy. +The OpenShell `policy set` command replaces the live policy instead of merging it. +Follow [Replace the Live Network Policy](replace-live-network-policy) only when you need full-policy replacement. + + +## Choose a Maintained Preset + +During onboarding, the selected [policy tier](../../reference/network-policies#policy-tiers) determines which maintained presets are enabled by default. +The interactive preset screen lets you add or remove individual presets. +Messaging channel choices are scoped to the active agent, so unsupported channel presets do not appear. + +List the presets available to the sandbox: + +```bash +$$nemoclaw policy-list +``` + +For the maintained preset catalog and guided service workflows, refer to [Common Integration Policy Examples](../integration-policy-examples). + +## Preview and Apply a Preset + +Use `--dry-run` to review the endpoints, rules, and binaries before applying the preset: + +```bash +$$nemoclaw my-assistant policy-add pypi --dry-run +$$nemoclaw my-assistant policy-add pypi --yes +``` + +Omit the preset name to use the interactive picker: + +```bash +$$nemoclaw my-assistant policy-add +``` + +Pass a preset name with `--yes` for scripted workflows. +Set `NEMOCLAW_NON_INTERACTIVE=1` instead of `--yes` to use the same non-interactive flow through an environment variable. + +## Reapply an Edited Preset + +Run the same `policy-add` command after you edit a maintained or recorded custom preset. +NemoClaw compares the preset with the live policy. +If the content differs, it applies the changed content. +You do not need to remove the preset first. + +The merge starts from the round-trippable base policy returned by `openshell policy get --base`. +It excludes provider-composed `_provider_*` entries because OpenShell reserves that namespace and rejects it in `policy set`. +Existing presets and baseline entries remain in place. + +## List and Remove Presets + +List every preset recorded for the sandbox: + +```bash +$$nemoclaw policy-list +``` + +Remove a preset when the sandbox no longer needs its access: + +```bash +$$nemoclaw my-assistant policy-remove pypi --yes +``` + +`policy-remove` accepts maintained and custom preset names. + +## Understand Persistence + +Dynamic changes apply to the current live policy. +NemoClaw also records maintained presets and custom presets applied through `--from-file` or `--from-dir`. +The custom preset record includes the full YAML content. +Snapshot restore and rebuild replay the recorded presets, even when the original custom file no longer exists. + +`$$nemoclaw rebuild` reapplies every recorded policy preset to the recreated sandbox. +For baseline changes that apply to every future sandbox, follow [Change the Baseline Network Policy](change-baseline-network-policy). + +## Approve One Request + +For one-off access, approve a blocked request in the OpenShell TUI: + +```bash +openshell term +``` + +Use the TUI to test a destination before deciding whether it belongs in a maintained or custom preset. +For the complete approval workflow, refer to [Approve or Deny Network Requests](../approve-network-requests). + +## Related Topics + +- [Create Custom Policy Presets](create-custom-policy-presets) adds an endpoint that no maintained preset covers. +- [Explain Network Policy to Agents](../explain-network-policy-to-agents) summarizes active and missing presets. +- [Commands](../../reference/commands#$$nemoclaw-name-policy-add) lists every policy command flag. diff --git a/docs/network-policy/change-baseline-network-policy.mdx b/docs/network-policy/change-baseline-network-policy.mdx new file mode 100644 index 0000000000..2059b37e0d --- /dev/null +++ b/docs/network-policy/change-baseline-network-policy.mdx @@ -0,0 +1,91 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Change the Baseline Network Policy" +sidebar-title: "Change the Baseline Policy" +description: "Edit the policy that NemoClaw applies when it creates a sandbox." +description-agent: "Changes the baseline sandbox network policy. Use when adding durable endpoints to every future sandbox or maintaining blueprint policy additions." +keywords: ["nemoclaw baseline network policy", "sandbox policy yaml", "blueprint policy additions"] +content: + type: "how_to" +skill: + priority: 10 +--- +Change the baseline policy when every future sandbox needs the same durable endpoint access. +NemoClaw reads the policy from the host when it creates the sandbox. + +## Prerequisites + +- Use a NemoClaw source checkout on the host. +- Keep the OpenShell CLI on your `PATH`. + + +Make policy file changes on the host. +The sandbox discards changes made only inside the sandbox when it is recreated. + + +## Edit the Policy File + + +Open `nemoclaw-blueprint/policies/openclaw-sandbox.yaml` and add or modify endpoint entries. + + +Open `agents/hermes/policy-additions.yaml` and add or modify endpoint entries. + + +Edit YAML manually when a maintained preset does not cover the required host, such as a reviewed public partner API. +Each entry in the `network_policies` section defines an endpoint group with these fields: + +`endpoints` +: Host and port pairs that the sandbox can reach. + +`binaries` +: Executables allowed to use the endpoint. + +`rules` +: HTTP methods and paths that the endpoint permits. + +`allow_encoded_slash` +: Allows percent-encoded slashes such as `%2F` in request paths. +Leave this field disabled unless the service uses encoded slashes in its documented route format, such as ClawHub scoped package names. + +To include a maintained preset in the baseline policy, merge its `network_policies` entries into the applicable baseline file. +Use [Apply Policy Presets](apply-policy-presets) when you need to add a preset to one running sandbox. + + + +## Add Blueprint Policy Additions + +If you maintain a custom blueprint, add extra policy entries under `components.policy.additions` in `nemoclaw-blueprint/blueprint.yaml`. +NemoClaw validates those entries with the same policy schema used by preset files. +During sandbox creation, it fetches the live policy, merges the additions into `network_policies`, and applies the merged policy through OpenShell. +The run metadata records the applied additions so you can audit the blueprint-level entries that were active. + + + +## Re-Run Onboarding + +Apply the updated baseline by running onboarding again: + +```bash +$$nemoclaw onboard +``` + +The wizard reads the modified policy file and applies it to the sandbox. + +## Verify the Policy + +Check that the sandbox is running with the updated policy: + +```bash +$$nemoclaw status +``` + +Use `$$nemoclaw policy-list` to inspect the tracked preset state. +Use `openshell policy get ` when you need to inspect the effective OpenShell policy. + +## Related Topics + +- [Customize the Network Policy](../customize-network-policy) helps you choose the correct policy workflow. +- [Create Custom Policy Presets](create-custom-policy-presets) adds durable access for one sandbox without changing the baseline. +- [Network Policies](../../reference/network-policies) explains the baseline policy schema and tiers. diff --git a/docs/network-policy/configure-raw-tls-passthrough.mdx b/docs/network-policy/configure-raw-tls-passthrough.mdx new file mode 100644 index 0000000000..47b200e593 --- /dev/null +++ b/docs/network-policy/configure-raw-tls-passthrough.mdx @@ -0,0 +1,86 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Configure Raw TLS Passthrough" +sidebar-title: "Configure Raw TLS" +description: "Use a scoped raw TLS tunnel when an allowed endpoint cannot use OpenShell L7 inspection." +description-agent: "Configures scoped raw TLS passthrough with tls skip. Use when a Cloudflare-fronted endpoint or direct TLS protocol fails through the inspected proxy." +keywords: ["openshell tls skip", "nemoclaw raw tls passthrough", "network policy connect tunnel"] +content: + type: "how_to" +skill: + priority: 10 +--- +Use raw TLS passthrough only when an allowed endpoint requires direct TLS negotiation. +Keep L7 inspection for every endpoint that supports it. + +## Identify the TLS Failure + +OpenShell normally terminates TLS for allowed HTTPS endpoints so it can inspect traffic. +The proxy creates a new TLS connection to the upstream, including endpoints with `access: full`. +Some Cloudflare-fronted upstreams reset that new handshake. +Clients can report `ECONNRESET` or a TLS error such as `curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL`. + +Protocols that require direct TLS negotiation can fail in the same way. +For example, the WhatsApp HTTP/1.1 Noise-over-WebSocket handshake cannot use the proxy's HTTP/2 ALPN negotiation. + +## Create a Passthrough Preset + +Set `access: full` and `tls: skip` for the exact endpoint: + +```yaml +preset: + name: cf-fronted-api + description: "Cloudflare-fronted API that resets re-originated TLS" +network_policies: + cf_fronted_api: + name: cf_fronted_api + endpoints: + - host: api.example.com + port: 443 + access: full + tls: skip + binaries: + - { path: /usr/local/bin/node } +``` + +Save the file as `nemoclaw-blueprint/policies/presets/cf-fronted-api.yaml`. +The filename without `.yaml` must match `preset.name`. + +Apply the catalog preset: + +```bash +$$nemoclaw my-assistant policy-add cf-fronted-api +``` + +Run the same command after editing the file. +NemoClaw compares the preset with the live policy and applies changed content. + +The maintained `whatsapp` channel preset uses this structure for `web.whatsapp.com`. + +Refer to `src/lib/messaging/channels/whatsapp/policy/openclaw.yaml` for an example. + + +Refer to `src/lib/messaging/channels/whatsapp/policy/hermes.yaml` for an example. + +It combines `tls: skip` tunnel endpoints with inspected `protocol: rest` endpoints. + +## Understand the Security Boundary + + +`tls: skip` disables L7 inspection and egress-boundary credential resolution for that endpoint. +The proxy cannot filter the HTTP method, path, or body after it creates the tunnel. +Endpoint `rules` cannot constrain what the agent sends through the tunnel. +The proxy also cannot replace an OpenShell credential placeholder inside the encrypted request. +This configuration does not unblock endpoints that require both raw passthrough and egress-boundary credential resolution. + + +The declared host, port, and `binaries` scope remain in effect. +Use `tls: skip` only for the exact hosts that require raw passthrough. +Do not use a broad wildcard. + +## Related Topics + +- [Create Custom Policy Presets](create-custom-policy-presets) explains custom preset validation and application. +- [Apply Policy Presets](apply-policy-presets) explains reapplication and persistence. +- [OpenShell Policy Schema](https://docs.nvidia.com/openshell/latest/reference/policy-schema.html) provides the complete endpoint schema. diff --git a/docs/network-policy/create-custom-policy-presets.mdx b/docs/network-policy/create-custom-policy-presets.mdx new file mode 100644 index 0000000000..29a0c69b2c --- /dev/null +++ b/docs/network-policy/create-custom-policy-presets.mdx @@ -0,0 +1,191 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Create Custom Policy Presets" +sidebar-title: "Create Custom Presets" +description: "Author and apply a scoped network policy preset for an endpoint that NemoClaw does not include." +description-agent: "Creates and applies custom policy presets. Use when adding a reviewed endpoint, applying preset files, or allowing a URL-based MCP server." +keywords: ["nemoclaw custom policy preset", "policy-add from-file", "url mcp network policy"] +content: + type: "how_to" +skill: + priority: 10 +--- +Create a custom preset when a sandbox needs a reviewed endpoint that no maintained NemoClaw preset covers. +Custom presets add scoped access to one sandbox without changing the baseline policy. + + +Custom preset hosts bypass NemoClaw's review process and can widen sandbox egress. +Review every host before applying a custom preset, especially when the file originates outside your team. + + +## Author a Preset + +Create a preset-format YAML file: + +```yaml +preset: + name: my-service-api + description: "Reviewed external service" +network_policies: + my-service-api: + name: my-service-api + endpoints: + - host: api.example.com + port: 443 + protocol: rest + enforcement: enforce + rules: + - allow: { method: GET, path: "/**" } + binaries: + - { path: /usr/local/bin/node } +``` + +The top-level `preset.name` must be a lowercase RFC 1123 label with letters, digits, and hyphens. +It must not collide with a maintained preset name such as `slack` or `pypi`. +Rename `preset.name` if NemoClaw reports a collision. + +Each endpoint must name a specific host or a scoped subdomain wildcard such as `*.example.com`. +NemoClaw rejects catch-all destinations, including `*`, `0.0.0.0`, `0.0.0.0/0`, `::`, and `::/0`. +Rule matchers must match the endpoint protocol. + +| Protocol | Rule fields | +|----------|-------------| +| REST | `method` and `path`; `method` accepts standard HTTP methods or `*` | +| WebSocket | `method` and `path`; `method` accepts `GET`, `WEBSOCKET_TEXT`, or `*` | +| JSON-RPC | `method` only | +| MCP | `method` with optional `tool` or `params.name` | + +The same protocol-specific matcher shape applies to `deny_rules`. + +User-authored presets must not declare `allowed_ips` for ordinary endpoints. +NemoClaw rejects that field in files passed through `--from-file` or `--from-dir` because it can widen the private ranges that OpenShell checks during SSRF protection. +Use hostnames, ports, protocols, methods, paths, and binary restrictions instead. +The only exception is the `host.openshell.internal` bridge endpoint for explicit sandbox-to-host service access. + +## Apply a Single File + +Preview the file before you apply it: + +```bash +$$nemoclaw my-assistant policy-add --from-file ./presets/my-service-api.yaml --dry-run +$$nemoclaw my-assistant policy-add --from-file ./presets/my-service-api.yaml --yes +``` + +NemoClaw records the complete YAML content with the sandbox. +You can remove the preset later without keeping the original file. + +## Apply Every File in a Directory + +Apply preset files in lexicographic order: + +```bash +$$nemoclaw my-assistant policy-add --from-dir ./presets/ --yes +``` + +Processing stops at the first failure. +NemoClaw does not remove presets that it already applied. +Fix the failing file and run the command again to continue. + +## Add a Preset to the Source Catalog + +Save a maintained local preset under `nemoclaw-blueprint/policies/presets/`. +The filename without `.yaml` must match `preset.name`. +The preset catalog reads `preset.name`, while `policy-add ` loads `presets/.yaml`. +A mismatch can list a preset that the named command cannot load. + +Apply the catalog preset by name: + +```bash +$$nemoclaw my-assistant policy-add my-service-api +``` + +Run the same command after editing the file. +NemoClaw compares the preset with the live policy and applies changed content. + +## Remove a Custom Preset + +Remove the preset by its recorded name: + +```bash +$$nemoclaw my-assistant policy-remove my-service-api --yes +``` + +Run `$$nemoclaw policy-list` to see every maintained and custom preset recorded for the sandbox. + +## Configure a URL-Based MCP Server + +Prefer the managed workflow in [Add an MCP Server](../../manage-sandboxes/mcp-servers/add-an-mcp-server) when the server uses authenticated HTTPS Streamable HTTP. +Use this custom policy recipe only for an agent-native URL registration that is outside the managed workflow. +Adding a URL such as `https://mcp.example.com/mcp` can cause a denied CONNECT tunnel. +The proxy returns `HTTP 403 Forbidden` when the target host is not in the default allowlist. +The related MCP client output contains this message: + +```text +CONNECT tunnel failed, response 403 +``` + +This recipe applies only when URL-based MCP traffic uses the sandbox proxy and fails with this CONNECT response. +An OAuth MCP login failure such as `getaddrinfo EAI_AGAIN` is a different transport problem. +A direct-DNS path that bypasses the proxy is also a different problem. +Widening this allowlist does not fix either case. + +Add the MCP host, exact Streamable HTTP route, required methods, and only the binary that opens the connection: + +```yaml +preset: + name: my-mcp + description: "Custom URL-based MCP server" +network_policies: + my_mcp: + name: my_mcp + endpoints: + - host: mcp.example.com + port: 443 + protocol: rest + enforcement: enforce + rules: + - allow: { method: GET, path: "/mcp" } + - allow: { method: POST, path: "/mcp" } + - allow: { method: DELETE, path: "/mcp" } + binaries: + - { path: /usr/local/bin/node } +``` + +Streamable HTTP clients can use `DELETE` on the same endpoint to terminate a session. +Keep that method scoped to the exact MCP route. +Do not replace the route with `/**` unless the server contract requires every path. + +Save the file as `nemoclaw-blueprint/policies/presets/my-mcp.yaml`. +Apply it by name: + +```bash +$$nemoclaw my-assistant policy-add my-mcp +``` + +NemoClaw previews the effective egress scope and prompts for confirmation before applying it. +For a publicly routed host that passes SSRF checks, invoke the MCP tool again and confirm that the CONNECT tunnel succeeds. + +The `binaries` list must include only the process that opens the connection. +The example assumes the Node runtime opens the MCP connection. +Replace the example path with the requesting binary that OpenShell reports in `openshell term`. +Shell-invoked clients need their own binary path, such as `/usr/bin/curl`. +Confirm a candidate path inside the sandbox: + +```bash +$$nemoclaw my-assistant exec -- which node +``` + +A preset with an endpoint but no matching binary authorizes no process, so requests still fail. +OpenShell uses `protocol: rest` for this HTTP-based policy even though Streamable HTTP MCP carries JSON-RPC. + +An allowlist entry does not disable OpenShell SSRF protection or create host routes. +If the hostname resolves to a private, loopback, or link-local address, establish the required host or VPN route. +Then follow the approved private-destination configuration. +Refer to [Agent cannot reach a host-side HTTP service](../../reference/troubleshooting#agent-cannot-reach-a-host-side-http-service) for routing and private-destination diagnostics. + +## Related Topics + +- [Apply Policy Presets](apply-policy-presets) explains preset persistence and reapplication. +- [Configure Raw TLS Passthrough](configure-raw-tls-passthrough) covers endpoints that cannot use L7 inspection. +- [Network Policies](../../reference/network-policies) describes the policy schema. diff --git a/docs/network-policy/customize-network-policy.mdx b/docs/network-policy/customize-network-policy.mdx index 3872a639a2..1b6951c209 100644 --- a/docs/network-policy/customize-network-policy.mdx +++ b/docs/network-policy/customize-network-policy.mdx @@ -3,541 +3,84 @@ # SPDX-License-Identifier: Apache-2.0 title: "Customize the Sandbox Network Policy" sidebar-title: "Customize the Network Policy" -description: "Add, remove, or modify allowed endpoints in the sandbox policy." -description-agent: "Adds, removes, or modifies allowed endpoints in the sandbox policy. Use when customizing network policy, changing egress rules, or configuring sandbox endpoint access." +description: "Choose the supported workflow for changing sandbox network access." +description-agent: "Routes network policy changes to their canonical workflow. Use when choosing between baseline edits, policy presets, custom presets, raw TLS, live replacement, and agent policy context." keywords: ["customize nemoclaw network policy", "sandbox egress policy configuration"] content: type: "how_to" skill: priority: 10 --- -Add, remove, or modify the endpoints the sandbox can reach. - -The NemoClaw repository declares the sandbox policy in a YAML file, and [NVIDIA OpenShell](https://github.com/NVIDIA/OpenShell) enforces it at runtime. -NemoClaw supports both static policy changes that persist across restarts and dynamic updates applied to a running sandbox through the OpenShell CLI. +Choose the policy workflow that matches the scope and persistence of the network access change. +NemoClaw declares sandbox policy in YAML, and [NVIDIA OpenShell](https://github.com/NVIDIA/OpenShell) enforces it at runtime. + +| Goal | Use this workflow | +|---|---| +| Change every future sandbox for an agent | [Change the Baseline Network Policy](configure-policies/change-baseline-network-policy) | +| Add or remove a maintained preset for one sandbox | [Apply Policy Presets](configure-policies/apply-policy-presets) | +| Add a reviewed endpoint that no maintained preset covers | [Create Custom Policy Presets](configure-policies/create-custom-policy-presets) | +| Allow direct TLS negotiation for an exact endpoint | [Configure Raw TLS Passthrough](configure-policies/configure-raw-tls-passthrough) | +| Replace the complete live policy | [Replace the Live Network Policy](configure-policies/replace-live-network-policy) | +| Give the sandbox agent a redacted policy summary | [Explain Network Policy to Agents](explain-network-policy-to-agents) | +| Approve or deny one blocked request | [Approve or Deny Network Requests](approve-network-requests) | -If the sandbox needs to reach an HTTP service running on the host, expose the service on a host IP that the OpenShell gateway can reach. -Apply a custom NemoClaw preset with `$$nemoclaw policy-add --from-file`. -Do not rely on `host.docker.internal` as a general host-service path because it bypasses the OpenShell policy path and may not be reachable in every sandbox runtime. +If a sandbox needs an HTTP service on the host, expose the service on a host IP that the OpenShell gateway can reach. +Apply a custom preset with `$$nemoclaw policy-add --from-file`. +Do not rely on `host.docker.internal` as a general host-service path because it bypasses the OpenShell policy path and may not be reachable. Refer to [Agent cannot reach a host-side HTTP service](../reference/troubleshooting#agent-cannot-reach-a-host-side-http-service). Adding a host to the egress policy permits a connection only when the endpoint, port, method, and binary rules match. -OpenShell still applies SSRF protection separately, so it can deny a request when the final address resolves to a loopback, private, link-local, or otherwise blocked internal range. -If a package installer or browser runtime download still fails with an SSRF-style denial after you add the public host, install that binary into the sandbox image at build time with [`$$nemoclaw onboard --from`](../reference/commands#--from-dockerfile) instead of relying on runtime egress. +OpenShell applies SSRF protection separately. +It can deny a request when the final address resolves to a loopback, private, link-local, or blocked internal range. +If a package installer or browser download still fails after you allow the public host, install the binary at build time. +Use [`$$nemoclaw onboard --from`](../reference/commands#--from-dockerfile) instead of runtime egress. -## Prerequisites - -- A running NemoClaw sandbox for dynamic changes, or the NemoClaw source repository for static changes. -- The OpenShell CLI on your `PATH`. - -> [!IMPORTANT] -> Make static policy edits on the host, not inside the sandbox. -> The sandbox image includes a small set of operational tools such as `vi`, `jq`, and `dos2unix`, but host-side policy files remain the durable source of truth. -> The sandbox discards changes made only inside the sandbox when it is recreated. - ## Static Changes -Static changes modify the baseline policy file and take effect after the next sandbox creation. - -### Edit the Policy File - - -Open `nemoclaw-blueprint/policies/openclaw-sandbox.yaml` and add or modify endpoint entries. - -To include a built-in preset in the baseline policy, merge its `network_policies` entries into this file and re-run `$$nemoclaw onboard`. - -To apply a preset to a running sandbox, use `$$nemoclaw policy-add` under [Dynamic Changes](#dynamic-changes). -That updates the live policy and does not edit `openclaw-sandbox.yaml`. - - -Open the Hermes policy additions and shared sandbox policy files under `agents/hermes/` and `nemoclaw-blueprint/policies/`, then add or modify endpoint entries. - -To include a built-in preset in the baseline policy, merge its `network_policies` entries into the appropriate policy file and re-run `$$nemoclaw onboard`. - -To apply a preset to a running sandbox, use `$$nemoclaw policy-add` under [Dynamic Changes](#dynamic-changes). -That updates the live policy and does not edit the baseline policy files. - - -Edit YAML manually when you need to allow custom hosts that a preset does not cover, such as an internal API or a weather service. - -Each entry in the `network` section defines an endpoint group with the following fields: - -`endpoints` -: Host and port pairs that the sandbox can reach. - -`binaries` -: Executables allowed to use this endpoint. - -`rules` -: HTTP methods and paths that are permitted. - -`allow_encoded_slash` -: Allows percent-encoded slashes such as `%2F` in request paths. Leave this disabled unless the service uses encoded slashes as part of its documented route format, such as ClawHub scoped package names. - -### Re-Run Onboard - -Apply the updated policy by re-running the onboard wizard: - -```bash -$$nemoclaw onboard -``` - -The wizard reads the modified policy file and applies it to the sandbox. - -### Verify the Policy - -Check that the sandbox is running with the updated policy: - -```bash -$$nemoclaw status -``` - -### Add Blueprint Policy Additions - -If you maintain a custom blueprint, add extra policy entries under `components.policy.additions` in `nemoclaw-blueprint/blueprint.yaml`. -NemoClaw validates those entries with the same policy schema used by preset files, fetches the live policy during sandbox creation, merges the additions into `network_policies`, and applies the merged policy through OpenShell. -The applied additions are recorded in the run metadata so you can audit which blueprint-level policy entries were active for that sandbox run. +Static changes modify the policy source that NemoClaw reads during sandbox creation. +Follow [Change the Baseline Network Policy](configure-policies/change-baseline-network-policy) to edit agent policy files, add blueprint policy additions, rerun onboarding, and verify the result. ## Dynamic Changes -Dynamic changes apply a policy update to a running sandbox without restarting it. - -> [!WARNING] -> `openshell policy set` **replaces** the sandbox's live policy with the contents of the file you provide. -> It does not merge. -> A running sandbox's live policy is the baseline policy plus every preset that was layered on during onboarding. -> Applying a file that contains only the baseline (or only a single preset) silently drops every other preset that was in effect. - -### Add a Preset File with `policy-add` (Recommended) - -This path preserves existing policy entries and is the only NemoClaw-supported flow for merging new entries into a running policy. - -1. Create a preset-format YAML file under `nemoclaw-blueprint/policies/presets/`, for example `nemoclaw-blueprint/policies/presets/influxdb.yaml`: - - ```yaml - preset: - name: influxdb - description: "InfluxDB time-series database" - network_policies: - influxdb: - name: influxdb - endpoints: - - host: influxdb.internal.example.com - port: 8086 - protocol: rest - enforcement: enforce - rules: - - allow: { method: GET, path: "/**" } - - allow: { method: POST, path: "/api/v2/write" } - binaries: - - { path: /usr/bin/curl } - ``` - -2. Apply it to the running sandbox: - -```bash -$$nemoclaw my-assistant policy-add -``` - -NemoClaw reads the round-trippable base policy with `openshell policy get --base`, structurally merges your preset's `network_policies` into it, and writes the merged result back. -Provider-composed `_provider_*` entries are excluded because OpenShell reserves that namespace and rejects it in `policy set`. -Existing presets and the baseline remain in place. -The preset file under `presets/` also persists across sandbox recreations. - -### Custom Recipe for Raw TLS Passthrough with `tls: skip` - -OpenShell's egress proxy terminates TLS for allowed HTTPS endpoints so it can inspect traffic. -The proxy creates a new TLS connection to the upstream, including for endpoints with `access: full`. -Some Cloudflare-fronted upstreams reset that new handshake. -The host remains allowed, but clients report `ECONNRESET` or a TLS error such as `curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL`. -Protocols that require direct TLS negotiation can fail in the same way. -For example, WhatsApp's HTTP/1.1-only Noise-over-WebSocket handshake cannot use the proxy's HTTP/2 ALPN negotiation. - -Use a raw L4 CONNECT tunnel when the endpoint requires direct TLS negotiation. -Set `access: full` and `tls: skip`. -The proxy passes the encrypted bytes without modification, and the sandbox client negotiates TLS with the upstream: - -```yaml -preset: - name: cf-fronted-api - description: "Cloudflare-fronted API that resets re-originated TLS" -network_policies: - cf_fronted_api: - name: cf_fronted_api - endpoints: - - host: api.example.com - port: 443 - access: full - tls: skip - binaries: - - { path: /usr/local/bin/node } -``` - -Save the file as `nemoclaw-blueprint/policies/presets/cf-fronted-api.yaml`. -The filename without `.yaml` must match `preset.name`. -Apply the catalog preset to the running sandbox by name: - -```bash -$$nemoclaw my-assistant policy-add cf-fronted-api -``` - -The preset catalog reads `preset.name`, but `policy-add ` loads `presets/.yaml`. -If these values differ, the catalog can list a preset that `policy-add` cannot load. -After you edit the preset file, run the same command again. -`policy-add` compares the preset with the live policy and applies the changed content. - -The maintained `whatsapp` channel preset uses this structure for `web.whatsapp.com`. -Refer to `src/lib/messaging/channels/whatsapp/policy/openclaw.yaml` for an example. -It combines `tls: skip` tunnel endpoints with inspected `protocol: rest` endpoints. - - -`tls: skip` disables L7 inspection and egress-boundary credential resolution for that endpoint. -The proxy cannot filter the HTTP method, path, or body after it creates the tunnel. -Endpoint `rules` therefore cannot constrain what the agent sends through the tunnel. -The proxy also cannot replace an OpenShell credential placeholder inside the encrypted request. -This recipe does not unblock endpoints that require both raw passthrough and egress-boundary credential resolution. -The declared host, port, and `binaries` scope remain in effect. -Use `tls: skip` only for the exact hosts that require raw passthrough. -Do not use a broad wildcard. -Keep L7 inspection for every endpoint that supports it. - - -### Custom Recipe: URL-Based MCP Server - -Adding a Streamable HTTP MCP server URL to OpenClaw (for example `https://mcp.example.com/mcp`) can result in the sandbox proxy denying the CONNECT tunnel with `HTTP 403 Forbidden` because the target host is not in the default allowlist. -The symptom in `~/.openclaw/logs` or in the MCP tool output is: - -```text -CONNECT tunnel failed, response 403 -``` - -This recipe applies only when URL-based MCP traffic uses the sandbox proxy and fails with that CONNECT 403 response. -An OAuth MCP login failure such as `getaddrinfo EAI_AGAIN`, or any direct-DNS path that bypasses the proxy, is a separate transport problem and is not fixed by widening this allowlist. - -Add a preset with the MCP host, the exact Streamable HTTP MCP route, the HTTP methods that route uses (`GET`, `POST`, and `DELETE`), and only the process binary that opens the connection. -Streamable HTTP MCP clients can use `DELETE` on the same endpoint to terminate a session, so keep that method scoped to the exact MCP route instead of widening the path: - -```yaml -preset: - name: my-mcp - description: "Custom URL-based MCP server" -network_policies: - my_mcp: - name: my_mcp - endpoints: - - host: mcp.example.com - port: 443 - protocol: rest - enforcement: enforce - rules: - - allow: { method: GET, path: "/mcp" } - - allow: { method: POST, path: "/mcp" } - - allow: { method: DELETE, path: "/mcp" } - binaries: - - { path: /usr/local/bin/node } -``` - -Save it as `nemoclaw-blueprint/policies/presets/my-mcp.yaml`. -The filename without `.yaml` must match `preset.name`. -Apply it to the running sandbox by name: - -```bash -$$nemoclaw my-assistant policy-add my-mcp -``` - -NemoClaw previews the effective egress scope that the preset would open, including `mcp.example.com`, and prompts for confirmation before applying. -For a publicly routed host that passes the separate SSRF checks, re-invoke the MCP tool and confirm that the CONNECT tunnel to `mcp.example.com:443` succeeds. - - -The `binaries` list must include only the process that opens the connection. -The example assumes the Node runtime opens the MCP connection, so it lists `/usr/local/bin/node`; use `/usr/local/bin/openclaw` instead if that executable is the connection opener in your installation. -MCP client tools invoked directly from a shell need their own binary path, such as `/usr/bin/curl`. -Confirm the paths inside the sandbox with `$$nemoclaw my-assistant exec -- which node` and `$$nemoclaw my-assistant exec -- which openclaw`, since the sandbox image and install method can change these locations. -A preset that lists only the endpoint but no matching binary widens the allowlist but no process is authorized to use it, so requests still fail. -OpenShell uses `protocol: rest` for this HTTP-based policy even though Streamable HTTP MCP carries JSON-RPC rather than REST semantics. - - - -Keep each rule scoped to the exact MCP endpoint, such as `/mcp`; do not replace it with `/**` unless the server contract genuinely requires every path. -An allowlist entry does not disable OpenShell's SSRF protection or create host routes. -If the MCP hostname resolves to a private, loopback, or link-local address, adding the policy alone does not make it reachable; establish the required host or VPN route and follow your deployment's approved private-destination configuration. -Refer to [Agent cannot reach a host-side HTTP service](../reference/troubleshooting#agent-cannot-reach-a-host-side-http-service) for routing and private-destination diagnostics. -`preset.name` must be a lowercase RFC 1123 label (letters, digits, and hyphens; no underscores). -The `network_policies` key can use underscores because that field feeds the policy schema rather than the preset filename. - - -### Export, Edit, and Set the Base Policy - -Use this path only when you cannot add a file under the NemoClaw source tree. -Start from the current base policy so the presets layered on at onboarding stay in the file you apply. -Requires OpenShell 0.0.72+ for the round-trippable `policy get --base` and `policy set --wait` syntax. -Use NemoClaw to validate the base policy and strip the OpenShell metadata header before writing your editable copy. - -```bash -$$nemoclaw my-assistant policy-get > current-policy.yaml -``` - -The command exits non-zero instead of emitting a partial policy when retrieval or validation fails. -Do not use `--raw` for this workflow because raw output retains the metadata header. - -Edit `current-policy.yaml` to add your entries under `network_policies:`, keeping the existing `version` field intact, then apply: - -```bash -openshell policy set --policy current-policy.yaml --wait my-assistant -``` - -### Scope of Dynamic Changes - -Dynamic changes apply only to the current session. -When the sandbox stops, the running policy resets to the baseline policy plus the presets recorded for the sandbox. -Custom presets applied through `$$nemoclaw policy-add --from-file` or `--from-dir` are recorded with the sandbox, including their full YAML content. -Snapshot restore and rebuild replay those recorded presets, so they survive sandbox recreation even if the original files are no longer on disk. -For permanent baseline changes that apply to every future sandbox, edit the source policy for the target agent and re-run `$$nemoclaw onboard`. - -### Approve Requests Interactively - -For one-off access, approve blocked requests in the OpenShell TUI instead of editing the baseline policy: - -```bash -openshell term -``` - -Use this flow to test a destination before you decide whether it belongs in a permanent preset or custom policy file. +Dynamic changes update a running sandbox. +Use [Apply Policy Presets](configure-policies/apply-policy-presets) for reviewed additions that NemoClaw records and replays. +Use [Approve or Deny Network Requests](approve-network-requests) for one-off access. +Use [Replace the Live Network Policy](configure-policies/replace-live-network-policy) only when a preset cannot express the complete change. ## Policy Presets -NemoClaw ships preset policy files for common integrations in `nemoclaw-blueprint/policies/presets/`. -Apply a preset as-is or use it as a starting template for a custom policy. -For guided post-install examples, refer to [Common Integration Policy Examples](integration-policy-examples). - -During onboarding, the [policy tier](../reference/network-policies#policy-tiers) you select determines which presets are enabled by default. -You can add or remove individual presets in the interactive preset screen that follows tier selection. -Built-in preset choices are scoped to the sandbox's active agent, so unsupported messaging channel presets do not appear in `policy-list` or the interactive `policy-add` picker for agents without matching channel policy files. - -Available presets: - -| Preset | Endpoints | -|--------|-----------| -| `brave` | Brave Search API | -| `brew` | Homebrew (Linuxbrew) package manager | -| `discord` | Discord API, gateway, and CDN access | -| `github` | GitHub and GitHub REST API | -| `huggingface` | Hugging Face Hub (download-only) and inference router | -| `jira` | Atlassian Jira API | -| `local-inference` | Local Ollama and vLLM through the host gateway | -| `npm` | npm and Yarn registries | -| `openclaw-pricing` | OpenClaw model-pricing reference fetch (LiteLLM and OpenRouter) | -| `outlook` | Microsoft 365 and Outlook | -| `pypi` | Python Package Index | -| `slack` | Slack API and webhooks | -| `tavily` | Tavily Search API | -| `telegram` | Telegram Bot API | -| `wechat` | WeChat (personal) iLink Bot API (experimental) | -| `whatsapp` | WhatsApp Web messaging (experimental) | - -To apply a preset to a running sandbox: - -```bash -$$nemoclaw policy-add -``` - - -Preset selection is interactive when you omit a preset name. -Pass a preset name with `--yes` for scripted workflows. - - -For example, to interactively add PyPI access to a running sandbox: - -```bash -$$nemoclaw my-assistant policy-add -``` - -To list which presets are applied to a sandbox: - -```bash -$$nemoclaw policy-list -``` - - -To include a preset in the baseline, merge its entries into `openclaw-sandbox.yaml` and re-run `$$nemoclaw onboard`. - - -To include a preset in the baseline, merge its entries into the Hermes policy additions and re-run `$$nemoclaw onboard`. - - - -The `openshell policy set --policy --wait ` command operates on raw policy files and does not accept the `preset:` metadata block used in preset YAML files. -Use `$$nemoclaw policy-add` for presets. - - -For scripted workflows, `policy-add` and `policy-remove` accept the preset name as a positional argument: - -```bash -$$nemoclaw my-assistant policy-add pypi --yes -$$nemoclaw my-assistant policy-remove pypi --yes -``` - -Set `NEMOCLAW_NON_INTERACTIVE=1` instead of `--yes` to drive the same flow from an environment variable. -Refer to [Commands](../reference/commands#$$nemoclaw-name-policy-add) for the full flag reference. - -`$$nemoclaw rebuild` reapplies every policy preset to the recreated sandbox, so presets survive an agent-version upgrade without manual reapplication. +Maintained policy presets cover common integrations and package services. +Follow [Apply Policy Presets](configure-policies/apply-policy-presets) to preview, apply, reapply, list, or remove them. +For guided service workflows, refer to [Common Integration Policy Examples](integration-policy-examples). ## Custom Preset Files -Apply a user-authored preset YAML file to a running sandbox without editing the baseline or using `openshell policy set`. - -### Authoring - -A custom preset follows the same shape as the built-in ones under `nemoclaw-blueprint/policies/presets/`: - -```yaml -preset: - name: my-internal-api - description: "Internal service" -network_policies: - my-internal-api: - name: my-internal-api - endpoints: - - host: api.example.internal - port: 443 - protocol: rest - enforcement: enforce - rules: - - allow: { method: GET, path: "/**" } - binaries: - - { path: /usr/local/bin/node } -``` - -The top-level `preset.name` must be a lowercase RFC 1123 label (letters, digits, hyphens) and must not collide with a built-in preset name such as `slack` or `pypi`. -Rename `preset.name` if NemoClaw refuses to apply the file because of a collision. -Each endpoint must name a specific host or a scoped subdomain wildcard such as `*.example.com`. -NemoClaw rejects catch-all destinations including `*`, `0.0.0.0`, `0.0.0.0/0`, `::`, and `::/0` before it applies a custom preset. -Rule matchers must match the endpoint protocol. -REST and WebSocket rules require `method` and `path`; REST accepts standard HTTP methods or `*`, while WebSocket accepts `GET`, `WEBSOCKET_TEXT`, or `*`. -JSON-RPC rules accept only `method`, and MCP rules accept `method` plus optional `tool` or `params.name` matchers. -The same protocol-specific matcher shape applies to `deny_rules`. -User-authored presets must not declare `allowed_ips` for ordinary endpoints. -NemoClaw rejects that field in files passed through `--from-file` or `--from-dir` because it can widen the private-address ranges that OpenShell checks during SSRF protection. -Use hostnames, ports, protocols, methods, paths, and binary restrictions instead. -The only exception is the `host.openshell.internal` bridge endpoint used for explicit sandbox-to-host service access. - -### Apply a Single File - -```bash -$$nemoclaw my-assistant policy-add --from-file ./presets/my-internal-api.yaml -``` - -Use `--dry-run` to preview endpoints without applying changes. -Use `--yes` or export `NEMOCLAW_NON_INTERACTIVE=1` to skip the confirmation prompt. - -### Apply Every File in a Directory - -```bash -$$nemoclaw my-assistant policy-add --from-dir ./presets/ --yes -``` - -NemoClaw processes files in lexicographic order. -Processing stops at the first failure. -NemoClaw does not roll back presets that were already applied. -Fix the failing file and re-run the command to continue. - - -Custom preset hosts bypass NemoClaw's review process and can widen sandbox egress to arbitrary destinations. -Review every host in a custom preset before applying it, especially when the file originates outside your team. - +Custom preset files add reviewed endpoint access without changing the baseline. +Follow [Create Custom Policy Presets](configure-policies/create-custom-policy-presets) to author, validate, apply, and remove a custom preset. +That page also contains the URL-based MCP server recipe formerly located in this guide. -### Remove a Custom Preset +## Raw TLS Passthrough -NemoClaw records custom presets applied with `--from-file` or `--from-dir` in the sandbox registry alongside their full YAML content. -Remove them by name without keeping the original file on disk: +Some endpoints require direct TLS negotiation and fail through inspected L7 proxying. +Follow [Configure Raw TLS Passthrough](configure-policies/configure-raw-tls-passthrough) for the bounded `access: full` and `tls: skip` recipe. -```bash -$$nemoclaw my-assistant policy-remove my-internal-api --yes -``` +## Live Policy Replacement -`policy-remove` accepts both built-in and custom preset names. -Run `$$nemoclaw policy-list` to see every preset currently applied to the sandbox. +OpenShell `policy set` replaces the complete live policy. +Follow [Replace the Live Network Policy](configure-policies/replace-live-network-policy) to export the round-trippable base, preserve existing entries, and apply a validated replacement. ## Agent Policy Context -When an agent runs in the sandbox, it needs a compact view of the active policy so it can decide whether a host or integration is allowed and what to suggest when something fails. -`$$nemoclaw policy-explain` prints that view as a redacted summary. -The summary includes the recorded tier, applied presets and their allowed host categories, known presets that are not applied, inspect/add/remove commands that change policy, and support boundaries between NemoClaw, OpenShell, and the agent. - -```bash -$$nemoclaw my-assistant policy-explain -``` - -Pass `--json` to emit the same context as a structured object the agent can read: - -```bash -$$nemoclaw my-assistant policy-explain --json -``` - -During onboarding, NemoClaw seeds the rendered context inside the sandbox at `/sandbox/.openclaw/workspace/POLICY.md`. -It refreshes that file on every `policy-add` or `policy-remove`, so the in-sandbox agent picks it up when it scans the workspace. -Pass `--write` to refresh that file on demand without changing the policy: - -```bash -$$nemoclaw my-assistant policy-explain --write -``` - -The output is intentionally redacted. -Network policy rule bodies, credential metadata, and binary allowlists are not included. -Only host stems and category-level summaries appear. -Host stems that resolve to RFC 1918 ranges (10/8, 172.16/12, 192.168/16), loopback (127/8, `::1`), link-local (169.254/16, `fe80::/10`), cloud metadata (`169.254.169.254`), unique-local IPv6 (`fc00::/7`), reserved zero (0.0.0.0/8), CGNAT (100.64/10), benchmarking (198.18/15), `localhost`, and the internal DNS suffixes `.local`, `.internal`, `.lan`, `.home`, `.home.arpa`, `.corp`, `.intra`, `.intranet`, `.localdomain` are dropped from `allowedHostCategories` and surface as a `redactedHostCount`. - -Each active preset also carries a `verification` field that tells the agent whether the OpenShell gateway actually enforces it: - -| Status | Meaning | -|--------|---------| -| `verified` | Registry lists the preset and the gateway confirms it is enforced. Safe to treat the host stems as allowed. | -| `registry-only` | Registry lists the preset but the gateway does not enforce it (drift). Treat allowed hosts as unverified. The agent should not assume the traffic will reach the host. | -| `gateway-only` | Gateway enforces a preset the registry does not list. Reported as active so the agent does not misclassify allowed hosts as blocked. | -| `gateway-unavailable` | Could not probe the gateway (no live snapshot). The whole report is advisory; rely on `nemoclaw policy-list` once the gateway is reachable. | - -The context also documents how the agent should classify a failed host or integration attempt. -The classifier evaluates rules in order so HTTP 403 has a single interpretation per call. -When the host matches an applied preset, the request is treated as an authentication failure. -Otherwise, the request is treated as a policy denial. - -1. `unsupported`: The caller asserts the capability is not offered for this sandbox, such as a messaging channel that the active agent does not support. - The agent should surface the limitation without retrying. -2. `missing-approval`: The host is allowed by an applied preset and the request was refused with HTTP 401. - The network path is open. - Credentials are missing or invalid. -3. `missing-approval` (low confidence): The host is allowed by an applied preset and the request was refused with HTTP 403. - This is ambiguous because OpenShell policies enforce by method, path, protocol, and binary, so a 403 on an allowed host can still be a finer-grained policy denial rather than missing credentials. - Confirm credentials first, then run `openshell policy get` to check whether the specific method or path is blocked. -4. `blocked-by-policy`: Either the host is not allowed by any applied preset and either an existing built-in or custom preset declares it (apply that preset), or the request is refused with a network-block error code (`EHOSTUNREACH`, `ENETUNREACH`, `ENOTFOUND`, `ECONNREFUSED`, `ETIMEDOUT`, `EAI_AGAIN`) or HTTP 403. - The same network-block codes also surface as `blocked-by-policy` (low confidence) when the host is on an applied but unverified preset (`registry-only` or `gateway-unavailable`), because a block code on a host the registry says should be allowed is the strongest signal that the gateway is not enforcing the preset. -5. `unknown`: None of the above apply. - The agent should surface the underlying error. - A network-block code on a host that matches a verified preset stays `unknown` because the gateway has confirmed enforcement, so the block must be an upstream connectivity failure rather than a policy denial. - -Each classification also carries a `confidence` field set to `high` or `low`. -Low-confidence verdicts mean the agent should report multiple possibilities to the user instead of treating the next-step recommendation as authoritative. -Common low-confidence triggers are: - -- HTTP 403 on an active host (ambiguous between missing credentials and a finer-grained OpenShell denial by method, path, protocol, or binary). -- The matched preset is `registry-only` (the registry lists it but the gateway does not enforce it), so the agent must not assume the host is reachable. -- The matched preset is `gateway-unavailable` (no live gateway snapshot was available), so the verdict is registry-derived and advisory. - -Callers that already hold a verified gateway snapshot can pass it to the classifier so verdicts about hosts on verified presets stay high-confidence. - -Use the classification to pick the next step. -For `blocked-by-policy`, run `$$nemoclaw policy-add ` or author a [custom preset](#custom-preset-files). -For `missing-approval`, confirm the API token and scopes for the integration. -For `unsupported`, surface the limitation to the user without retrying. +Agents need a redacted view of active presets and policy verification state. +Follow [Explain Network Policy to Agents](explain-network-policy-to-agents) to print or refresh that context and interpret failure classifications. ## Related Topics -- [Approve or Deny Agent Network Requests](approve-network-requests) for real-time operator approval. -- [Common Integration Policy Examples](integration-policy-examples) for maintained preset examples such as Outlook, messaging, GitHub, Jira, web search, package managers, Hugging Face, and local inference. -- [Network Policies](../reference/network-policies) for the full baseline policy reference. -- OpenShell [Policy Schema](https://docs.nvidia.com/openshell/latest/reference/policy-schema.html) for the full YAML policy schema reference. -- OpenShell [Sandbox Policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.html) for applying, iterating, and debugging policies at the OpenShell layer. +- [Common Integration Policy Examples](integration-policy-examples) provides maintained service workflows. +- [Network Policies](../reference/network-policies) is the canonical policy reference. +- [OpenShell Policy Schema](https://docs.nvidia.com/openshell/latest/reference/policy-schema.html) provides the complete YAML schema. +- [OpenShell Sandbox Policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.html) explains OpenShell-layer policy iteration. diff --git a/docs/network-policy/explain-network-policy-to-agents.mdx b/docs/network-policy/explain-network-policy-to-agents.mdx new file mode 100644 index 0000000000..d4bdd937ad --- /dev/null +++ b/docs/network-policy/explain-network-policy-to-agents.mdx @@ -0,0 +1,96 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Explain Network Policy to Agents" +sidebar-title: "Explain Policy to Agents" +description: "Generate a redacted policy summary that helps an agent classify network failures." +description-agent: "Explains the active network policy to sandbox agents. Use when generating a redacted policy summary, interpreting verification status, or classifying network failures." +keywords: ["nemoclaw policy-explain", "agent network policy context", "POLICY.md"] +content: + type: "how_to" +skill: + priority: 10 +--- +Use `policy-explain` to give a sandbox agent a compact, redacted view of its active network policy. +The summary helps the agent distinguish policy denials, missing credentials, unsupported capabilities, and upstream failures. + +## Print the Policy Context + +Print the redacted summary: + +```bash +$$nemoclaw my-assistant policy-explain +``` + +Pass `--json` when a tool needs a structured object: + +```bash +$$nemoclaw my-assistant policy-explain --json +``` + + +During OpenClaw onboarding, NemoClaw writes the rendered context to `/sandbox/.openclaw/workspace/POLICY.md`. +It refreshes that file after `policy-add` or `policy-remove`. +Refresh the file without changing policy: + +```bash +$$nemoclaw my-assistant policy-explain --write +``` + + +For Hermes, use the printed Markdown or JSON through an operator-controlled prompt or file workflow. +The `--write` target is the OpenClaw workspace and is not a Hermes agent-context integration. + + +## Understand Redaction + +The summary includes the recorded tier, applied presets, allowed host categories, known presets that are not applied, and policy management commands. +It also explains the support boundaries between NemoClaw, OpenShell, and the agent. + +The output omits network rule bodies, credential metadata, and binary allowlists. +It includes only host stems and category-level summaries. +NemoClaw drops private, loopback, link-local, metadata, unique-local, reserved, CGNAT, benchmarking, and internal-suffix hosts from `allowedHostCategories`. +It reports their count in `redactedHostCount`. + +## Interpret Verification Status + +Each active preset includes a `verification` value: + +| Status | Meaning | +|--------|---------| +| `verified` | The registry lists the preset, and the gateway confirms enforcement. | +| `registry-only` | The registry lists the preset, but the gateway does not enforce it. Treat the allowed hosts as unverified. | +| `gateway-only` | The gateway enforces a preset that the registry does not list. | +| `gateway-unavailable` | NemoClaw could not probe the gateway. Treat the report as advisory until the gateway is reachable. | + +## Classify a Failed Request + +The classifier evaluates conditions in this order: + +1. `unsupported` means the active agent does not offer the asserted capability. + Surface the limitation without retrying. +2. `missing-approval` with high confidence means a host on an applied preset returned HTTP 401. + The network path is open, but credentials are missing or invalid. +3. `missing-approval` with low confidence means a host on an applied preset returned HTTP 403. + Confirm credentials, then inspect the effective policy for a method, path, protocol, or binary denial. +4. `blocked-by-policy` means no applied preset allows the host or the request returned a network-block error. + Apply an applicable preset or create a custom preset. +5. `unknown` means no classification matched. + Surface the underlying error. + +Network-block error codes include `EHOSTUNREACH`, `ENETUNREACH`, `ENOTFOUND`, `ECONNREFUSED`, `ETIMEDOUT`, and `EAI_AGAIN`. +A block code on a host from a `registry-only` or `gateway-unavailable` preset produces a low-confidence policy verdict. +A block code on a host from a verified preset stays `unknown` because the gateway already confirmed enforcement. + +Each verdict includes `confidence` set to `high` or `low`. +Low confidence means the agent must report multiple possibilities instead of treating one next step as authoritative. + +For `blocked-by-policy`, run `$$nemoclaw policy-add ` or follow [Custom Preset Files](customize-network-policy#custom-preset-files). +For `missing-approval`, confirm the API token and scopes. +For `unsupported`, surface the limitation without retrying. + +## Related Topics + +- [Apply Policy Presets](configure-policies/apply-policy-presets) changes the recorded preset set. +- [Create Custom Policy Presets](configure-policies/create-custom-policy-presets) adds a reviewed custom destination. +- [Network Policies](../reference/network-policies) explains policy enforcement and tiers. diff --git a/docs/network-policy/integration-policy-examples.mdx b/docs/network-policy/integration-policy-examples.mdx index 9d448f2ef2..c7698bbead 100644 --- a/docs/network-policy/integration-policy-examples.mdx +++ b/docs/network-policy/integration-policy-examples.mdx @@ -47,27 +47,27 @@ An approval updates the running policy, but it does not create a reviewable Nemo NemoClaw ships maintained policy presets for common services in `nemoclaw-blueprint/policies/presets/`. Messaging channel presets are scoped to the sandbox's active agent; if an agent does not have a matching channel policy, that channel preset is omitted from `policy-list` and `policy-add ` reports it as unknown. -| Workflow | Preset | -|----------|--------| -| Brave Search | `brave` | -| Homebrew packages | `brew` | -| Discord messaging | `discord` | -| GitHub and GitHub API | `github` | -| Gmail IMAP and SMTP | `gmail` | -| Hugging Face Hub and Inference API | `huggingface` | -| Jira and Atlassian Cloud | `jira` | -| Local Ollama or vLLM through the host gateway | `local-inference` | -| OpenClaw model-pricing reference fetch | `openclaw-pricing` | -| npm and Yarn packages | `npm` | -| Microsoft 365, Outlook, and Graph API | `outlook` | -| Public reference APIs | `public-reference` | -| Python Package Index | `pypi` | -| Slack messaging | `slack` | -| Tavily Search | `tavily` | -| Telegram Bot API | `telegram` | -| Weather and geocoding APIs | `weather` | -| WeChat (personal) iLink Bot API (experimental) | `wechat` | -| WhatsApp Web messaging (experimental) | `whatsapp` | +| Workflow | Preset | Agent support | +|----------|--------|---------------| +| Brave Search | `brave` | OpenClaw | +| Homebrew packages | `brew` | OpenClaw and Hermes | +| Discord messaging | `discord` | OpenClaw and Hermes | +| GitHub and GitHub API | `github` | OpenClaw and Hermes | +| Gmail IMAP and SMTP | `gmail` | OpenClaw and Hermes | +| Hugging Face Hub and Inference API | `huggingface` | OpenClaw and Hermes | +| Jira and Atlassian Cloud | `jira` | OpenClaw and Hermes | +| Local Ollama or vLLM through the host gateway | `local-inference` | OpenClaw and Hermes | +| OpenClaw model-pricing reference fetch | `openclaw-pricing` | OpenClaw | +| npm and Yarn packages | `npm` | OpenClaw and Hermes | +| Microsoft 365, Outlook, and Graph API | `outlook` | OpenClaw and Hermes | +| Public reference APIs | `public-reference` | OpenClaw and Hermes | +| Python Package Index | `pypi` | OpenClaw and Hermes | +| Slack messaging | `slack` | OpenClaw and Hermes | +| Tavily Search | `tavily` | OpenClaw and Hermes | +| Telegram Bot API | `telegram` | OpenClaw and Hermes | +| Weather and geocoding APIs | `weather` | OpenClaw and Hermes | +| WeChat (personal) iLink Bot API (experimental) | `wechat` | OpenClaw and Hermes | +| WhatsApp Web messaging (experimental) | `whatsapp` | OpenClaw and Hermes | Preview the endpoints before applying: @@ -406,199 +406,19 @@ $$nemoclaw my-assistant status ## Gmail With an App Password -Use the `gmail` preset when a Python script needs to receive mail through IMAP or send mail through SMTP with a Gmail App Password. -The preset allows only `/usr/bin/python3` to open raw TLS connections to `imap.gmail.com:993` and `smtp.gmail.com:465`. -OpenShell enforces the exact hosts, ports, and binary, but it cannot inspect individual IMAP or SMTP commands inside the encrypted connections. -This preset does not grant Gmail REST API, Google OAuth, or service-account endpoints. - - -Google recommends [App Passwords](https://support.google.com/accounts/answer/185833) only for clients that cannot use Sign in with Google. -This workflow stores the App Password inside the sandbox, where the agent can read it while the file exists. -Create an App Password only for this workflow, delete the uploaded file, and revoke the App Password after the task. - - -### Prerequisites - -Prepare the Google Account before applying the preset: - -- Turn on 2-Step Verification for the Google Account. -- Create an App Password for the sandbox workflow. -- Confirm that the account or Google Workspace administrator permits IMAP and App Passwords. - -Google documents the TLS endpoints and ports in [IMAP, POP, and SMTP](https://developers.google.com/workspace/gmail/imap/imap-smtp). - -### Apply the Preset - -Preview and apply the preset from the host: - -```bash -$$nemoclaw my-assistant policy-add gmail --dry-run -$$nemoclaw my-assistant policy-add gmail --yes -``` - -### Upload the App Password - -Create `gmail_config.json` on the host outside any source checkout: - -```json -{ - "email": "your-address@gmail.com", - "app_password": "<16-character-app-password>" -} -``` - -Restrict the host file, prepare a sandbox directory, upload the file, and restrict the uploaded copy: - -```bash -chmod 600 /path/to/gmail_config.json -$$nemoclaw my-assistant exec -- mkdir -p /sandbox/hand -$$nemoclaw my-assistant upload /path/to/gmail_config.json /sandbox/hand/gmail_config.json -$$nemoclaw my-assistant exec -- chmod 600 /sandbox/hand/gmail_config.json -``` - -Do not commit `gmail_config.json` or paste its contents into chat, logs, issues, or pull requests. - -### Download Recent Attachments - -Save this standard-library example as `download_attachments.py` on the host. -It reads the 10 most recent messages without marking them as read and writes attachments under `/sandbox/hand/gmail_attachments`: - -```python -import imaplib -import json -from email import policy -from email.parser import BytesParser -from pathlib import Path - -ROOT = Path("/sandbox/hand") -CONFIG = json.loads((ROOT / "gmail_config.json").read_text(encoding="utf-8")) -ATTACHMENTS = ROOT / "gmail_attachments" -ATTACHMENTS.mkdir(mode=0o700, parents=True, exist_ok=True) -ATTACHMENTS.chmod(0o700) - -with imaplib.IMAP4_SSL("imap.gmail.com", 993) as mailbox: - mailbox.login(CONFIG["email"], CONFIG["app_password"]) - status, _ = mailbox.select("INBOX", readonly=True) - if status != "OK": - raise RuntimeError("Could not select the Gmail inbox") - - status, search_data = mailbox.search(None, "ALL") - if status != "OK": - raise RuntimeError("Could not search the Gmail inbox") - - for message_id in search_data[0].split()[-10:]: - status, message_data = mailbox.fetch(message_id, "(BODY.PEEK[])") - if status != "OK": - continue - raw_message = next( - (entry[1] for entry in message_data if isinstance(entry, tuple)), - None, - ) - if raw_message is None: - continue - - message = BytesParser(policy=policy.default).parsebytes(raw_message) - for part in message.walk(): - filename = part.get_filename() - payload = part.get_payload(decode=True) - if part.get_content_disposition() != "attachment" or not filename or payload is None: - continue - safe_name = Path(filename.replace("\\", "/")).name - destination = ATTACHMENTS / f"{message_id.decode()}-{safe_name}" - destination.write_bytes(payload) - destination.chmod(0o600) - print(destination) -``` - -Upload and run the script, then copy the attachment directory back to the host: - -```bash -$$nemoclaw my-assistant upload ./download_attachments.py /sandbox/hand/download_attachments.py -$$nemoclaw my-assistant exec -- python3 /sandbox/hand/download_attachments.py -$$nemoclaw my-assistant download /sandbox/hand/gmail_attachments/ ./gmail_attachments/ -``` - -Treat every downloaded attachment as untrusted content. -Do not execute an attachment in the sandbox or on the host without reviewing it. - -### Send a Test Message - -Save this standard-library example as `send_email.py` on the host. -The example sends a test message back to the configured account: - -```python -import json -import smtplib -from email.message import EmailMessage -from pathlib import Path - -config = json.loads( - Path("/sandbox/hand/gmail_config.json").read_text(encoding="utf-8") -) -message = EmailMessage() -message["From"] = config["email"] -message["To"] = config["email"] -message["Subject"] = "NemoClaw Gmail policy test" -message.set_content("Sent through the NemoClaw Gmail policy preset.") - -with smtplib.SMTP_SSL("smtp.gmail.com", 465, timeout=30) as smtp: - smtp.login(config["email"], config["app_password"]) - smtp.send_message(message) -``` - -Upload and run the script: - -```bash -$$nemoclaw my-assistant upload ./send_email.py /sandbox/hand/send_email.py -$$nemoclaw my-assistant exec -- python3 /sandbox/hand/send_email.py -``` - -### Remove Credentials and Access - -Delete the host and uploaded credential files, along with the temporary sandbox files, after downloading any attachments you need: - -```bash -rm -f /path/to/gmail_config.json -$$nemoclaw my-assistant exec -- rm -f /sandbox/hand/gmail_config.json -$$nemoclaw my-assistant exec -- rm -f /sandbox/hand/download_attachments.py /sandbox/hand/send_email.py -$$nemoclaw my-assistant exec -- rm -rf /sandbox/hand/gmail_attachments -$$nemoclaw my-assistant policy-remove gmail --yes -``` - -Removing the preset does not delete uploaded files or revoke the App Password. -Revoke the dedicated App Password in your Google Account when the sandbox no longer needs it. +Use the `gmail` preset for Python IMAP or SMTP workflows that use a dedicated Gmail App Password. +Follow [Set Up Gmail With an App Password](set-up-gmail-with-an-app-password) for the security boundary, prerequisites, examples, and cleanup steps. ## Inspect or Replace the Live Policy -Use `policy-list` for normal preset state: - -```bash -$$nemoclaw my-assistant policy-list -``` - -Use the NemoClaw policy export when you need an editable copy of the round-trippable base policy. -Requires OpenShell 0.0.72+ for the round-trippable `policy get --base` and `policy set --wait` syntax. - -```bash -$$nemoclaw my-assistant policy-get > current-policy.yaml -``` - -The export strips OpenShell metadata and exits non-zero if the base policy cannot be retrieved or validated. -Do not add `--raw` when you plan to edit and reapply the file. - -If you must replace the live policy, edit the policy file and apply it back to the sandbox: - -```bash -openshell policy set --policy current-policy.yaml --wait my-assistant -``` - -`openshell policy set` replaces the live policy with the file you provide. -It does not accept a preset file that starts with a `preset:` block, and it does not merge a single endpoint into the existing policy. -Use `$$nemoclaw my-assistant policy-add` for maintained NemoClaw presets. +Use `policy-list` for normal preset state. +Follow [Replace the Live Network Policy](configure-policies/replace-live-network-policy) only when you need to export, edit, and replace the complete policy. +Use [Apply Policy Presets](configure-policies/apply-policy-presets) to merge maintained or custom preset entries. ## Next Steps - [Approve or Deny Agent Network Requests](approve-network-requests) for the interactive OpenShell TUI flow. -- [Customize the Sandbox Network Policy](customize-network-policy) for static policy edits and raw OpenShell policy files. +- [Customize the Sandbox Network Policy](customize-network-policy) to choose the correct policy workflow. +- [Set Up Gmail With an App Password](set-up-gmail-with-an-app-password) for the full Gmail IMAP and SMTP workflow. - [Choose Messaging Channels](../manage-sandboxes/messaging-channels/choose-messaging-channels) for Telegram, Discord, Slack, WeChat, WhatsApp, and Microsoft Teams configuration. - [Commands](../reference/commands) for the full `policy-get`, `policy-add`, `policy-list`, `policy-remove`, and `channels` command reference. diff --git a/docs/network-policy/replace-live-network-policy.mdx b/docs/network-policy/replace-live-network-policy.mdx new file mode 100644 index 0000000000..aea08dc437 --- /dev/null +++ b/docs/network-policy/replace-live-network-policy.mdx @@ -0,0 +1,75 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Replace the Live Network Policy" +sidebar-title: "Replace the Live Policy" +description: "Export, edit, validate, and replace the complete live policy for a NemoClaw sandbox." +description-agent: "Replaces the complete live sandbox policy. Use when a full policy edit cannot use NemoClaw policy presets." +keywords: ["openshell policy set", "nemoclaw policy-get", "replace live network policy"] +content: + type: "how_to" +skill: + priority: 10 +--- +Replace the live policy only when you cannot express the change as a NemoClaw preset. +This workflow requires OpenShell 0.0.72+. + + +`openshell policy set` replaces the sandbox's live policy with the file you provide. +It does not merge. +A running policy contains the baseline plus every preset layered during onboarding and later operations. +Applying a file that contains only one part silently removes the other entries. + + +## Export the Base Policy + +Start from the current round-trippable base policy so the applied presets remain in the file: + +```bash +$$nemoclaw my-assistant policy-get > current-policy.yaml +``` + +The command retrieves and validates the base policy. +It exits nonzero instead of writing partial output when retrieval or validation fails. +Do not use `--raw` because raw output retains the OpenShell metadata header. + +## Edit the Complete Policy + +Edit `current-policy.yaml`. +Add entries under `network_policies` and keep the existing `version` field. +Preserve every baseline and preset entry that the sandbox still needs. + +The `openshell policy set` command accepts a raw policy file. +It does not accept a preset file that starts with a `preset:` metadata block. +Use [Apply Policy Presets](apply-policy-presets) when a maintained or custom preset can express the change. + +## Apply the Replacement + +Apply the complete file: + +```bash +openshell policy set --policy current-policy.yaml --wait my-assistant +``` + +The change applies to the running sandbox. +For a durable source-of-truth change, update the baseline policy or record a custom preset with NemoClaw. + +## Verify the Result + +Inspect the tracked preset state: + +```bash +$$nemoclaw my-assistant policy-list +``` + +Inspect the effective OpenShell policy before testing the endpoint: + +```bash +openshell policy get my-assistant +``` + +## Related Topics + +- [Create Custom Policy Presets](create-custom-policy-presets) records scoped additions with the sandbox. +- [Change the Baseline Network Policy](change-baseline-network-policy) changes every future sandbox. +- [Approve or Deny Network Requests](../approve-network-requests) handles one-off access. diff --git a/docs/network-policy/set-up-gmail-with-an-app-password.mdx b/docs/network-policy/set-up-gmail-with-an-app-password.mdx new file mode 100644 index 0000000000..2488d65096 --- /dev/null +++ b/docs/network-policy/set-up-gmail-with-an-app-password.mdx @@ -0,0 +1,187 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Set Up Gmail With an App Password" +description: "Configure Gmail IMAP and SMTP access for a Python workflow with a dedicated App Password." +description-agent: "Configures Gmail IMAP and SMTP access for a Python workflow with a dedicated App Password. Use when applying the Gmail policy preset, uploading an App Password, downloading Gmail attachments, sending a test message, or removing Gmail credentials and access." +keywords: ["nemoclaw gmail app password", "gmail imap smtp policy", "gmail attachment download"] +content: + type: "how_to" +skill: + priority: 15 +--- +Use the `gmail` preset when a Python script needs to receive mail through IMAP or send mail through SMTP with a Gmail App Password. +The preset allows only `/usr/bin/python3` to open raw TLS connections to `imap.gmail.com:993` and `smtp.gmail.com:465`. + +OpenShell enforces the exact hosts, ports, and binary, but it cannot inspect individual IMAP or SMTP commands inside the encrypted connections. +This preset does not grant Gmail REST API, Google OAuth, or service-account endpoints. + + +Google recommends [App Passwords](https://support.google.com/accounts/answer/185833) only for clients that cannot use Sign in with Google. +This workflow stores the App Password inside the sandbox, where the agent can read it while the file exists. +Create an App Password only for this workflow. +Delete the uploaded file after the task. +Revoke the App Password after the task. + + +## Prerequisites + +Prepare the Google Account before applying the preset: + +- Turn on 2-Step Verification for the Google Account. +- Create an App Password for the sandbox workflow. +- Confirm that the account or Google Workspace administrator permits IMAP and App Passwords. + +Google documents the TLS endpoints and ports in [IMAP, POP, and SMTP](https://developers.google.com/workspace/gmail/imap/imap-smtp). + +## Apply the Preset + +Run these commands from the host: + +```bash +$$nemoclaw my-assistant policy-add gmail --dry-run +$$nemoclaw my-assistant policy-add gmail --yes +``` + +## Upload the App Password + +Create `gmail_config.json` on the host outside any source checkout: + +```json +{ + "email": "your-address@gmail.com", + "app_password": "<16-character-app-password>" +} +``` + +Restrict the host file. +Prepare a sandbox directory. +Upload the file. +Restrict the uploaded copy: + +```bash +chmod 600 /path/to/gmail_config.json +$$nemoclaw my-assistant exec -- mkdir -p /sandbox/hand +$$nemoclaw my-assistant upload /path/to/gmail_config.json /sandbox/hand/gmail_config.json +$$nemoclaw my-assistant exec -- chmod 600 /sandbox/hand/gmail_config.json +``` + +Do not commit `gmail_config.json` or paste its contents into chat, logs, issues, or pull requests. + +## Download Recent Attachments + +Save this standard-library example as `download_attachments.py` on the host. +It reads the 10 most recent messages without marking them as read and writes attachments under `/sandbox/hand/gmail_attachments`: + +```python +import imaplib +import json +from email import policy +from email.parser import BytesParser +from pathlib import Path + +ROOT = Path("/sandbox/hand") +CONFIG = json.loads((ROOT / "gmail_config.json").read_text(encoding="utf-8")) +ATTACHMENTS = ROOT / "gmail_attachments" +ATTACHMENTS.mkdir(mode=0o700, parents=True, exist_ok=True) +ATTACHMENTS.chmod(0o700) + +with imaplib.IMAP4_SSL("imap.gmail.com", 993) as mailbox: + mailbox.login(CONFIG["email"], CONFIG["app_password"]) + status, _ = mailbox.select("INBOX", readonly=True) + if status != "OK": + raise RuntimeError("Could not select the Gmail inbox") + + status, search_data = mailbox.search(None, "ALL") + if status != "OK": + raise RuntimeError("Could not search the Gmail inbox") + + for message_id in search_data[0].split()[-10:]: + status, message_data = mailbox.fetch(message_id, "(BODY.PEEK[])") + if status != "OK": + continue + raw_message = next( + (entry[1] for entry in message_data if isinstance(entry, tuple)), + None, + ) + if raw_message is None: + continue + + message = BytesParser(policy=policy.default).parsebytes(raw_message) + for part in message.walk(): + filename = part.get_filename() + payload = part.get_payload(decode=True) + if part.get_content_disposition() != "attachment" or not filename or payload is None: + continue + safe_name = Path(filename.replace("\\", "/")).name + destination = ATTACHMENTS / f"{message_id.decode()}-{safe_name}" + destination.write_bytes(payload) + destination.chmod(0o600) + print(destination) +``` + +Upload the script. +Run the script. +Copy the attachment directory back to the host: + +```bash +$$nemoclaw my-assistant upload ./download_attachments.py /sandbox/hand/download_attachments.py +$$nemoclaw my-assistant exec -- python3 /sandbox/hand/download_attachments.py +$$nemoclaw my-assistant download /sandbox/hand/gmail_attachments/ ./gmail_attachments/ +``` + +Treat every downloaded attachment as untrusted content. +Do not execute an attachment in the sandbox or on the host without reviewing it. + +## Send a Test Message + +Save this standard-library example as `send_email.py` on the host. +The example sends a test message back to the configured account: + +```python +import json +import smtplib +from email.message import EmailMessage +from pathlib import Path + +config = json.loads( + Path("/sandbox/hand/gmail_config.json").read_text(encoding="utf-8") +) +message = EmailMessage() +message["From"] = config["email"] +message["To"] = config["email"] +message["Subject"] = "NemoClaw Gmail policy test" +message.set_content("Sent through the NemoClaw Gmail policy preset.") + +with smtplib.SMTP_SSL("smtp.gmail.com", 465, timeout=30) as smtp: + smtp.login(config["email"], config["app_password"]) + smtp.send_message(message) +``` + +Run these commands: + +```bash +$$nemoclaw my-assistant upload ./send_email.py /sandbox/hand/send_email.py +$$nemoclaw my-assistant exec -- python3 /sandbox/hand/send_email.py +``` + +## Remove Credentials and Access + +Delete the host and uploaded credential files, along with the temporary sandbox files, after downloading any attachments you need: + +```bash +rm -f /path/to/gmail_config.json +$$nemoclaw my-assistant exec -- rm -f /sandbox/hand/gmail_config.json +$$nemoclaw my-assistant exec -- rm -f /sandbox/hand/download_attachments.py /sandbox/hand/send_email.py +$$nemoclaw my-assistant exec -- rm -rf /sandbox/hand/gmail_attachments +$$nemoclaw my-assistant policy-remove gmail --yes +``` + +Removing the preset does not delete uploaded files or revoke the App Password. +Revoke the dedicated App Password in your Google Account when the sandbox no longer needs it. + +## Related Topics + +- [Common Integration Policy Examples](integration-policy-examples) lists other maintained integration presets. +- [Apply Policy Presets](configure-policies/apply-policy-presets) explains preset persistence and reapplication. +- [Credential Storage](../security/credential-storage) explains NemoClaw credential boundaries. diff --git a/docs/reference/commands.mdx b/docs/reference/commands.mdx index a45290a485..4e48d45812 100644 --- a/docs/reference/commands.mdx +++ b/docs/reference/commands.mdx @@ -328,7 +328,8 @@ $$nemoclaw my-dcode rebuild --no-observability --yes Removing the `observability-otlp-local` policy stops delivery immediately but does not clear the recorded opt-in. A later rebuild restores the preset on Balanced and Open tiers, while Restricted continues to suppress it. -For the complete collector setup, privacy boundary, policy recovery, verification, and a host-side LangSmith exporter example, refer to [Quickstart with LangChain Deep Agents Code](/user-guide/deepagents/get-started/quickstart#export-traces-through-a-local-collector). +For policy recovery and the host-side LangSmith exporter example, refer to [Set Up Deep Agents Trace Export](/user-guide/deepagents/monitoring/set-up-deepagents-trace-export). +Review [Understand Deep Agents Trace Export](/user-guide/deepagents/monitoring/understand-deepagents-trace-export) for the privacy boundary, [Verify Deep Agents Trace Export](/user-guide/deepagents/monitoring/verify-deepagents-trace-export) for delivery checks, and [Manage Deep Agents Trace Export](/user-guide/deepagents/monitoring/manage-deepagents-trace-export) for lifecycle operations. @@ -3648,7 +3649,8 @@ Collector and exporter failures are non-fatal to agent work. Native LangSmith tracing and ambient OTLP configuration remain disabled in the sandbox. The explicit opt-in can export bounded prompts, responses, tool arguments, tool results, and operational metadata, so operators must treat trace payloads as sensitive application data. The collector must enforce the operator's filtering and redaction requirements before remote forwarding because the local policy applies to the managed Python interpreter and does not provide authenticated tenant identity. -For the complete receiver contract and a runnable LangSmith collector setup, refer to [Quickstart with LangChain Deep Agents Code](/user-guide/deepagents/get-started/quickstart#export-traces-through-a-local-collector). +For a runnable LangSmith collector setup, refer to [Set Up Deep Agents Trace Export](/user-guide/deepagents/monitoring/set-up-deepagents-trace-export). +For the receiver trust contract, refer to [Understand Deep Agents Trace Export](/user-guide/deepagents/monitoring/understand-deepagents-trace-export). diff --git a/docs/reference/network-policies.mdx b/docs/reference/network-policies.mdx index 9baf8db73f..49f81de9fe 100644 --- a/docs/reference/network-policies.mdx +++ b/docs/reference/network-policies.mdx @@ -216,7 +216,7 @@ Sandbox Python can forge spans and resource attributes. The explicit `--observability` opt-in can export bounded prompts, responses, tool arguments, tool results, and operational metadata. Managed size and recognized-key redaction do not detect secrets embedded in ordinary content values. The collector must enforce the operator's filtering and redaction requirements before forwarding traces, and it must not treat span fields such as `service.name` as authenticated tenant identity. -For a safe host binding, policy recovery commands, a runnable collector, and end-to-end verification, refer to [Export Traces Through a Local Collector](../get-started/quickstart#export-traces-through-a-local-collector). +For a safe host binding, policy recovery commands, and a runnable collector, refer to [Set Up Deep Agents Trace Export](../monitoring/set-up-deepagents-trace-export). diff --git a/docs/reference/platform-support.mdx b/docs/reference/platform-support.mdx index c6bb5a5508..aa8a407c71 100644 --- a/docs/reference/platform-support.mdx +++ b/docs/reference/platform-support.mdx @@ -161,7 +161,7 @@ They are listed here so launch material, sales conversations, and support triage | Item | Status | Why | |------|--------|-----| | Podman / other container runtimes | Unsupported | Onboard surfaces an explicit unsupported-runtime error for Podman (`src/lib/onboard/fatal-runtime-preflight.ts` prints the rejection; `src/lib/onboard/preflight.ts` flags the unsupported runtime upstream). Only Docker Engine, Docker Desktop, and Colima are supported. See issue #420 (closed). | -| Intel Mac (macOS x86_64) | Unsupported | OpenShell does not publish macOS x86_64 standalone gateway assets. Install hard-fails on x86_64 macOS (`scripts/install-openshell.sh:689`). See issue #954 (closed). | +| Intel Mac (macOS x86_64) | Unsupported | OpenShell does not publish macOS x86_64 standalone gateway assets. The top-level installer rejects Intel Mac hosts before release-ref resolution or downloads (`install.sh:108`), and the OpenShell installer retains a downstream asset guard (`scripts/install-openshell.sh:689`). See issue #954 (closed). | | Non-Ubuntu/Debian Linux distros | Unsupported | Installer assumes `apt-get`. Fedora/Rocky/Alma/Arch/NixOS are not validated and the installer's package-manager probes do not cover them. See open issue #899 (Fedora hang). | | Native Kubernetes or OpenShift deployments | Unsupported | NemoClaw runs the sandbox as a Docker container, not a Kubernetes pod. The default Docker-driver topology does not embed k3s. Operator-managed K8s/OpenShift deployments are out of scope; see issue #407 (community OpenShift through agent-sandbox CRD). | | Air-gapped / offline installs | Unsupported | Onboard assumes network reachability for package fetches, container pulls, and provider validation. See open issues #4872 and #2218 (production-deployment epic covering air-gapped support, China network guidance, multi-host topology). | diff --git a/docs/security/advisory-early-warning.md b/docs/security/advisory-early-warning.md index 22cb2ff377..ce6e837153 100644 --- a/docs/security/advisory-early-warning.md +++ b/docs/security/advisory-early-warning.md @@ -4,54 +4,44 @@ # Advisory Early Warning and Audit Provenance Status: correlation module, scan CLI, and audit provenance implemented. -Scheduled operation and the response policy are a separate follow-up, gated on -product/security-owner sign-off recorded on issue #7338 (evidence from #7276). - -Public upstream GitHub Security Advisories are often published weeks before the -global reviewed ecosystem record that `npm audit` enforces. For -`fast-uri` (GHSA-4c8g-83qw-93j6) the upstream repository advisory appeared on -June 29 while the reviewed record propagated on July 21, so the same vulnerable -version audited clean at 18:46 UTC and reported High at 20:09 UTC. This page -documents the early-warning correlation that narrows that gap and the -provenance every audit now records so such timelines are provable from retained -artifacts. - -The correlation draws on all three types of the global advisory database, which -contribute differently: - -- reviewed records are the corpus `npm audit` enforces — a match here means - package-level enforcement is imminent or already active, and the signal - confirms the reviewed gate will catch it; -- unreviewed records are NVD-sourced and often appear before curation reaches - the reviewed feed — they usually lack a verified npm mapping, so they flow - through the ambiguous, informational-only path and provide the earlier - heads-up; -- malware records name npm packages published as malware — a match against the - reviewed inventory correlates like any other record and is equally - non-blocking. - -Polling upstream *repository* advisories directly (the earliest public signal, -e.g. `fastify/fast-uri`'s own advisory) needs a package-to-repository map and -is the planned extension; the correlation module already accepts that record -shape unchanged. - -## How the early-warning correlation works - -- `scripts/lib/advisory-early-warning.mts` correlates GitHub Security Advisory - JSON (repository-level and global records share the shape) with the reviewed - npm inventory and emits structured signals: +Scheduled operation and the response policy are a separate follow-up. +Product and security owner sign-off on issue #7338 gates that work, based on evidence from #7276. + +Public upstream GitHub Security Advisories are often published weeks before the global reviewed ecosystem record that `npm audit` enforces. +For `fast-uri` (GHSA-4c8g-83qw-93j6), the upstream repository advisory appeared on June 29, while the reviewed record propagated on July 21. +The same vulnerable version audited clean at 18:46 UTC and reported High at 20:09 UTC. + +This page documents the early-warning correlation that narrows that gap. +It also documents the provenance that each audit records so retained artifacts can prove these timelines. + +The correlation draws on all three types of the global advisory database: + +- Reviewed records are the corpus that `npm audit` enforces. + A match means package-level enforcement is imminent or active, and the signal confirms that the reviewed gate detects it. +- Unreviewed records come from NVD and often appear before curation reaches the reviewed feed. + They usually lack a verified npm mapping, so they follow the ambiguous, informational path and provide earlier notice. +- Malware records name npm packages published as malware. + A match against the reviewed inventory correlates like any other record and remains non-blocking. + +Polling upstream repository advisories directly requires a package-to-repository map. +These advisories can provide the earliest public signal, such as the advisory from `fastify/fast-uri`. +This polling is the planned extension, and the correlation module already accepts that record shape unchanged. + +## How the Early-Warning Correlation Works + +- `scripts/lib/advisory-early-warning.mts` correlates GitHub Security Advisory JSON with the reviewed npm inventory. + Repository-level and global records share the same shape. + The module emits structured signals: `{advisoryId, package, vulnerableRange, matchedVersions, source, confidence, action}`. -- The inventory is derived from `ci/reviewed-npm-audit.json`: every committed - archive package spec plus the installed packages of each locked graph's - `package-lock.json`. -- Confidence is encoded, never guessed: only an exact npm ecosystem + - package-name + parseable semver-range match yields `confidence: "exact"` and - `action: "investigate"`. Name collisions from non-npm (CPE-derived) records - and unparseable ranges yield `confidence: "ambiguous"` and - `action: "informational"`. Ambiguous matches never block or mutate a release. -- The reviewed npm audit gate (`scripts/audit-reviewed-npm-graph.mts`, enforced - in CI) remains enabled and authoritative for exact npm package/version-range - decisions. The early-warning path only triggers investigation and rescanning. +- The inventory comes from `ci/reviewed-npm-audit.json`. + It contains each committed archive package spec and the installed packages from each locked graph's `package-lock.json`. +- Confidence is encoded instead of inferred. + Only an exact npm ecosystem, package name, and parseable semantic-version range match yields `confidence: "exact"` and `action: "investigate"`. + Name collisions from non-npm, CPE-derived records and unparseable ranges yield `confidence: "ambiguous"` and `action: "informational"`. + Ambiguous matches never block or mutate a release. +- The reviewed npm audit gate in `scripts/audit-reviewed-npm-graph.mts` remains enabled in CI. + It is authoritative for exact npm package and version-range decisions. + The early-warning path triggers only investigation and rescanning. `scripts/advisory-early-warning-scan.mts` is the CLI over the module. It reads only local files and exits 0 whether or not signals are found. @@ -68,34 +58,30 @@ node --experimental-strip-types scripts/advisory-early-warning-scan.mts \ --advisories advisories.json --output signals.json ``` -Advisory records come from the GitHub `/advisories` API — all three types, -paginated, filtered by `affects=` batches of the inventory package names. - -Running this correlation on a schedule and routing signals to an alert -destination is deliberately not wired up yet: #7338 requires product/security -owners to define the supported historical-image scope, rescan ownership, alert -destination, and response expectations first. A follow-up adds the scheduled -workflow once that sign-off is recorded on the issue. - -## Provenance recorded per audit - -Each reviewed npm audit report now has a `*.provenance.json` sidecar -(`coverage/reviewed-npm-audit/` artifacts, and `npm-audit.provenance.json` for -the WeChat locked runtime graph audit) recording: - -- scanner identity: `npm audit`, npm version, Node.js version; -- the configured registry, with URL credentials removed, plus the derived bulk - advisory endpoint npm posts the dependency graph to (npm >= 7 has no - quick-audit fallback: on request failure npm reports no advisory data, and - the note records this); -- run start and finish timestamps (ISO 8601); -- the audited graph label and committed package specs; -- the raw machine-readable report path (`rawReportPath`, by convention - relative to the directory containing the sidecar); -- the GHSA advisory ids extracted from the report; and -- a `failure` marker when the audit attempt itself failed, so the sidecar - still records the attempt. - -Comparing the `advisoryIds` of consecutive retained runs identifies the last -comparable non-detection and the first detection of a newly surfaced advisory, -even when an unrelated finding failed the earlier run. +Advisory records come from the GitHub `/advisories` API. +The request includes all three types, uses pagination, and filters `affects=` by batches of inventory package names. + +Running this correlation on a schedule and routing signals to an alert destination is not implemented. +Issue #7338 requires product and security owners to define the supported historical-image scope, rescan ownership, alert destination, and response expectations. +A follow-up adds the scheduled workflow after the issue records that sign-off. + +## Provenance Recorded for Each Audit + +Each reviewed npm audit report has a `*.provenance.json` sidecar. +The sidecars include `coverage/reviewed-npm-audit/` artifacts and `npm-audit.provenance.json` for the WeChat locked runtime graph audit. +Each sidecar records: + +- Scanner identity, including `npm audit`, npm version, and Node.js version. +- The configured registry with URL credentials removed. + The sidecar also records the derived bulk advisory endpoint where npm posts the dependency graph. + npm 7 and newer have no quick-audit fallback. + When the request fails, npm reports no advisory data, and the note records this condition. +- Run start and finish timestamps in ISO 8601 format. +- The audited graph label and committed package specs. +- The raw machine-readable report path in `rawReportPath`. + By convention, the path is relative to the directory that contains the sidecar. +- The GHSA advisory IDs extracted from the report. +- A `failure` marker when the audit attempt fails, so the sidecar still records the attempt. + +Comparing the `advisoryIds` of consecutive retained runs identifies the last comparable non-detection and the first detection of a newly surfaced advisory. +This comparison remains possible when an unrelated finding failed the earlier run. diff --git a/docs/security/credential-storage.mdx b/docs/security/credential-storage.mdx index a52818044b..deb3d8a93d 100644 --- a/docs/security/credential-storage.mdx +++ b/docs/security/credential-storage.mdx @@ -88,7 +88,7 @@ Rerun onboarding when you change providers because the provider selection and cr NemoClaw supports opt-in, backend-neutral OTLP tracing for the managed Deep Agents harness through an operator-run host collector. The sandbox sends traces only to the fixed local receiver and does not receive `LANGSMITH_API_KEY`, remote OTLP exporter headers, or backend credentials. Native LangSmith tracing and ambient OpenTelemetry exporter configuration remain disabled inside `dcode`. -Keep backend credentials in the host collector, and refer to [Export Traces Through a Local Collector](../get-started/quickstart#export-traces-through-a-local-collector) for the supported setup. +Keep backend credentials in the host collector, and refer to [Understand Deep Agents Trace Export](../monitoring/understand-deepagents-trace-export) for the supported boundary. NemoClaw still keeps non-secret operational state under `~/.nemoclaw/` (such as the sandbox registry). diff --git a/test/deepagents-monitoring-published-routes.test.ts b/test/deepagents-monitoring-published-routes.test.ts new file mode 100644 index 0000000000..3bb595bec3 --- /dev/null +++ b/test/deepagents-monitoring-published-routes.test.ts @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { readFileSync } from "node:fs"; +import path from "node:path"; + +import { describe, expect, it } from "vitest"; +import { + buildPublishedRouteIndex, + findBrokenPublishedRoutes, + resolvePageLinksByText, +} from "../scripts/check-docs-published-routes.mts"; + +const TRACE_SOURCES = [ + "monitoring/understand-deepagents-trace-export.mdx", + "monitoring/set-up-deepagents-trace-export.mdx", + "monitoring/verify-deepagents-trace-export.mdx", + "monitoring/manage-deepagents-trace-export.mdx", +] as const; +const QUICKSTART_SOURCE = "get-started/quickstart-langchain-deepagents-code.mdx"; + +function readDoc(source: string): string { + return readFileSync(path.join(process.cwd(), "docs", source), "utf8"); +} + +describe("Deep Agents monitoring published routes", () => { + it("publishes focused trace pages only in the Deep Agents guide", () => { + const index = buildPublishedRouteIndex(); + + for (const source of TRACE_SOURCES) { + const slug = source + .split("/") + .at(-1) + ?.replace(/\.mdx$/, ""); + expect(index.sourceToRoutes.get(source)?.map(({ route }) => route)).toEqual([ + `/user-guide/deepagents/monitoring/${slug}`, + ]); + expect(findBrokenPublishedRoutes(source, index)).toEqual([]); + expect(index.routes.has(`/user-guide/openclaw/monitoring/${slug}`)).toBe(false); + expect(index.routes.has(`/user-guide/hermes/monitoring/${slug}`)).toBe(false); + } + }); + + it("keeps the Quickstart compatibility pointer on the focused setup path", () => { + const index = buildPublishedRouteIndex(); + + expect(findBrokenPublishedRoutes(QUICKSTART_SOURCE, index)).toEqual([]); + expect([ + ...resolvePageLinksByText(QUICKSTART_SOURCE, "Set Up Deep Agents Trace Export", index), + ]).toEqual([ + { + fromRoute: "/user-guide/deepagents/get-started/quickstart", + published: true, + resolved: "/user-guide/deepagents/monitoring/set-up-deepagents-trace-export", + target: "../monitoring/set-up-deepagents-trace-export", + }, + ]); + expect(readDoc(QUICKSTART_SOURCE)).toContain('id="export-traces-through-a-local-collector"'); + }); +}); diff --git a/test/network-policies-published-routes.test.ts b/test/network-policies-published-routes.test.ts index 14ac6f3a06..a241ef066c 100644 --- a/test/network-policies-published-routes.test.ts +++ b/test/network-policies-published-routes.test.ts @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +import { readFileSync } from "node:fs"; +import path from "node:path"; + import { describe, expect, it } from "vitest"; import { buildPublishedRouteIndex, @@ -10,7 +13,21 @@ import { const NETWORK_POLICIES_SOURCE = "reference/network-policies.mdx"; const CUSTOMIZE_POLICY_SOURCE = "network-policy/customize-network-policy.mdx"; +const INTEGRATION_POLICY_SOURCE = "network-policy/integration-policy-examples.mdx"; +const GMAIL_SOURCE = "network-policy/set-up-gmail-with-an-app-password.mdx"; const APPROVAL_LINK_TEXT = "Approve or Deny Agent Network Requests"; +const GMAIL_LINK_TEXT = "Set Up Gmail With an App Password"; +const CONFIGURATION_SOURCES = [ + "network-policy/change-baseline-network-policy.mdx", + "network-policy/apply-policy-presets.mdx", + "network-policy/create-custom-policy-presets.mdx", + "network-policy/configure-raw-tls-passthrough.mdx", + "network-policy/replace-live-network-policy.mdx", +] as const; + +function readDoc(source: string): string { + return readFileSync(path.join(process.cwd(), "docs", source), "utf8"); +} describe("shared Network Policies published routes", () => { it("keeps the approval guide link inside variants that publish it (#6601)", () => { @@ -42,4 +59,74 @@ describe("shared Network Policies published routes", () => { expect(findBrokenPublishedRoutes(CUSTOMIZE_POLICY_SOURCE, index)).toEqual([]); }); + + it("publishes focused policy configuration pages for OpenClaw and Hermes", () => { + const index = buildPublishedRouteIndex(); + + for (const source of CONFIGURATION_SOURCES) { + expect( + index.sourceToRoutes + .get(source) + ?.map(({ route }) => route) + .sort((a, b) => a.localeCompare(b)), + ).toEqual([ + `/user-guide/hermes/network-policy/configure-policies/${source + .split("/") + .at(-1) + ?.replace(/\.mdx$/, "")}`, + `/user-guide/openclaw/network-policy/configure-policies/${source + .split("/") + .at(-1) + ?.replace(/\.mdx$/, "")}`, + ]); + expect(findBrokenPublishedRoutes(source, index)).toEqual([]); + } + }); + + it("publishes the Gmail task only where the integration hub is available", () => { + const index = buildPublishedRouteIndex(); + + expect( + index.sourceToRoutes + .get(GMAIL_SOURCE) + ?.map(({ route }) => route) + .sort((a, b) => a.localeCompare(b)), + ).toEqual([ + "/user-guide/hermes/network-policy/set-up-gmail-with-an-app-password", + "/user-guide/openclaw/network-policy/set-up-gmail-with-an-app-password", + ]); + expect(findBrokenPublishedRoutes(GMAIL_SOURCE, index)).toEqual([]); + expect( + index.routes.has("/user-guide/deepagents/network-policy/set-up-gmail-with-an-app-password"), + ).toBe(false); + }); + + it("keeps the Gmail compatibility section linked to its focused page", () => { + const index = buildPublishedRouteIndex(); + + expect(findBrokenPublishedRoutes(INTEGRATION_POLICY_SOURCE, index)).toEqual([]); + expect( + [...resolvePageLinksByText(INTEGRATION_POLICY_SOURCE, GMAIL_LINK_TEXT, index)].sort((a, b) => + a.fromRoute.localeCompare(b.fromRoute), + ), + ).toEqual([ + { + fromRoute: "/user-guide/hermes/network-policy/integration-policy-examples", + published: true, + resolved: "/user-guide/hermes/network-policy/set-up-gmail-with-an-app-password", + target: "set-up-gmail-with-an-app-password", + }, + { + fromRoute: "/user-guide/openclaw/network-policy/integration-policy-examples", + published: true, + resolved: "/user-guide/openclaw/network-policy/set-up-gmail-with-an-app-password", + target: "set-up-gmail-with-an-app-password", + }, + ]); + }); + + it("preserves compatibility anchors on the retained policy routes", () => { + expect(readDoc(CUSTOMIZE_POLICY_SOURCE)).toContain("## Custom Preset Files"); + expect(readDoc(INTEGRATION_POLICY_SOURCE)).toContain("## Gmail With an App Password"); + }); }); diff --git a/test/policy-roundtrip-docs.test.ts b/test/policy-roundtrip-docs.test.ts index 7fb0fdc387..fbdcd2331b 100644 --- a/test/policy-roundtrip-docs.test.ts +++ b/test/policy-roundtrip-docs.test.ts @@ -7,8 +7,7 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; const ROUND_TRIP_DOCS = [ - "docs/network-policy/customize-network-policy.mdx", - "docs/network-policy/integration-policy-examples.mdx", + "docs/network-policy/replace-live-network-policy.mdx", "docs/reference/cli-selection-guide.mdx", "docs/reference/network-policies.mdx", ]; @@ -19,10 +18,10 @@ function readDoc(docPath: string): string { describe("policy round-trip documentation examples", () => { it("keeps the URL-based MCP recipe least-privilege and narrowly scoped (#5322)", () => { - const text = readDoc("docs/network-policy/customize-network-policy.mdx"); + const text = readDoc("docs/network-policy/create-custom-policy-presets.mdx"); const section = text - .split("### Custom Recipe: URL-Based MCP Server")[1] - ?.split("### Export, Edit, and Set the Base Policy")[0]; + .split("## Configure a URL-Based MCP Server")[1] + ?.split("## Related Topics")[0]; expect(section).toBeDefined(); expect(section).toContain('- allow: { method: GET, path: "/mcp" }'); @@ -32,10 +31,10 @@ describe("policy round-trip documentation examples", () => { expect(section?.match(/- \{ path: \/usr\/local\/bin\//g)).toHaveLength(1); expect(section).toContain("only the process that opens the connection"); expect(section).toContain("terminate a session"); - expect(section).toContain("do not replace it with `/**`"); - expect(section).toContain("does not disable OpenShell's SSRF protection"); + expect(section).toContain("Do not replace the route with `/**`"); + expect(section).toContain("does not disable OpenShell SSRF protection"); expect(section).toContain("getaddrinfo EAI_AGAIN"); - expect(section).toContain("is not fixed by widening this allowlist"); + expect(section).toContain("Widening this allowlist does not fix"); }); it("uses the NemoClaw base-policy export instead of a metadata-stripping pipeline", () => { From ee9836cd37688f3f8cbff7dfb3458202b8ca262b Mon Sep 17 00:00:00 2001 From: Miyoung Choi Date: Fri, 24 Jul 2026 13:45:10 -0700 Subject: [PATCH 2/3] docs(security): clarify offline NVD reconciliation Signed-off-by: Miyoung Choi --- docs/security/advisory-early-warning.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/security/advisory-early-warning.md b/docs/security/advisory-early-warning.md index 5b7e6b51b6..7868379579 100644 --- a/docs/security/advisory-early-warning.md +++ b/docs/security/advisory-early-warning.md @@ -147,10 +147,11 @@ The #7338 acceptance criteria classify each finding as a reviewed-mapping delay, The ideal trigger is the earliest public upstream disclosure, evaluated against the exact dependency inventory on a schedule that does not depend on how far any one build progressed. Mapping each demonstrated gap to a mechanism: -- Reviewed-mapping delay (`fast-uri` and plausibly the Jaeger propagator): The correlation path fetches unreviewed NVD-sourced records alongside reviewed and malware records. +- Reviewed-mapping delay (`fast-uri` and plausibly the Jaeger propagator): The correlation path reads unreviewed NVD-sourced records alongside reviewed and malware records from the supplied advisory file. + It also reads previously fetched NVD responses supplied through `--nvd-records`; the CLI does not fetch them. + The planned scheduled workflow will fetch those NVD records, pass them to the CLI, and run every six hours after the #7338 sign-off. A disclosure that names an inventory package raises a signal before the reviewed mapping exists. NVD reconciliation provides supplementary corroboration. - Running it every six hours is the scheduled workflow, gated on the #7338 sign-off. Polling upstream repository advisories directly is not implemented. This earliest public signal requires a package-to-repository map and remains the planned extension. - Audit or rescan coverage gap (`@opentelemetry/core` and the limit on the Jaeger conclusion): The scheduled scan correlates every advisory type against the full reviewed inventory every six hours, independent of build execution order. From 53b026370f4b26e3591560911088b5235e465b4e Mon Sep 17 00:00:00 2001 From: Miyoung Choi Date: Fri, 24 Jul 2026 13:51:28 -0700 Subject: [PATCH 3/3] docs(network-policy): bound Gmail IMAP connection Signed-off-by: Miyoung Choi --- docs/network-policy/set-up-gmail-with-an-app-password.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/network-policy/set-up-gmail-with-an-app-password.mdx b/docs/network-policy/set-up-gmail-with-an-app-password.mdx index 2488d65096..db39ba57ec 100644 --- a/docs/network-policy/set-up-gmail-with-an-app-password.mdx +++ b/docs/network-policy/set-up-gmail-with-an-app-password.mdx @@ -86,7 +86,7 @@ ATTACHMENTS = ROOT / "gmail_attachments" ATTACHMENTS.mkdir(mode=0o700, parents=True, exist_ok=True) ATTACHMENTS.chmod(0o700) -with imaplib.IMAP4_SSL("imap.gmail.com", 993) as mailbox: +with imaplib.IMAP4_SSL("imap.gmail.com", 993, timeout=30) as mailbox: mailbox.login(CONFIG["email"], CONFIG["app_password"]) status, _ = mailbox.select("INBOX", readonly=True) if status != "OK":