fix(sandbox): rewrite #2109 proxy fix as http.request wrapper - #1
Merged
Merged
Conversation
…NVIDIA#2178) (NVIDIA#2298) ## Summary Fixes NVIDIA#2178 (NV QA UAT: \`node\` still reports v20 after installer claims v22.22.2 was installed). When \`scripts/install.sh\` upgrades Node via nvm, \`nvm use 22\` only takes effect inside the installer's subshell — the user's parent shell still resolves \`node\` to the pre-install version until they reload. The existing generic \`source <profile>\` hint at the bottom of the installer is easy to miss. Two layers: ### 1. Loud warning adjacent to install line ``` [INFO] Node.js installed via nvm: v22.22.2 (default alias) [WARN] Your current shell may still resolve `node` to an older version until you reload it. To activate v22.22.2 in this shell: exec "$SHELL" -l # (or) nvm use 22 ``` ### 2. Opt-in auto-activation prompt (new) At the end of \`print_done\`, when the upgrade path actually ran AND the user is on a real TTY AND \`--non-interactive\` is not set: ``` Reload your shell now to activate Node v22.22.2? [Y/n] ``` On accept → \`exec \"\$SHELL\" -l\`, replacing the installer process so \`node --version\` prints v22 in the very next prompt with zero extra user action. On decline → noop (warning + manual command still on screen). ## Gates preserving scriptability - \`NON_INTERACTIVE=1\` / \`--non-interactive\` → skip prompt (keeps CI-style flows quiet) - stdin not a TTY (e.g. \`curl | bash\`) → skip prompt (keeps chained invocations like \`curl | bash && nemoclaw onboard\` working) - Upgrade path didn't run (Node was already >= 22) → skip prompt (nothing to reload for) In all skipped cases the loud warning + manual command remain visible. ## Test plan - [x] \`npx vitest run --project cli test/install-preflight.test.ts\` — two new tests pass (hint presence, helper gating + exec path) - [x] \`bash -n scripts/install.sh\` syntax OK; \`install.sh --help\` unaffected 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Installer now reports the exact Node.js version with nvm-specific messaging, warns that the current shell may still resolve an older Node, and prints an explicit pasteable command to activate the new version in the current session. * **Tests** * Added tests that verify the installer’s upgrade messaging and presence of the activation instructions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary This PR tightens typing around agent manifest parsing in `src/lib/agent-defs.ts` by replacing the old catch-all record type with recursive manifest value guards. That keeps the YAML loader and field readers typed more precisely, reduces a hotspot in the manifest loader, and adds coverage for invalid top-level manifest payloads. ## Changes - replace `UnknownRecord` in `src/lib/agent-defs.ts` with recursive `ManifestValue` and `ManifestRecord` types - validate parsed YAML manifests with `isManifestRecord()` while still accepting scalar values emitted by `js-yaml`, including timestamp `Date` objects - add a regression test in `src/lib/agent-defs.test.ts` that rejects non-object manifest payloads ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification - [x] `npx prek run --all-files` passes - [x] `npm test` passes - [x] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) ## AI Disclosure - [x] AI-assisted — tool: OpenAI Codex --- Signed-off-by: Carlos Villela <cvillela@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added validation test to ensure agent manifest configuration is properly structured as an object. * **Bug Fixes** * Strengthened agent manifest parsing validation to reject malformed configuration files and enforce stricter type constraints on configuration values. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Carlos Villela <cvillela@nvidia.com>
…VIDIA#2243) ## Summary Add `test/e2e/test-diagnostics.sh` with 5 end-to-end test cases covering CLI version output, debug snapshots, credential sanitization in debug tarballs, sandbox inference config visibility, and credential list safety. Integrates as `diagnostics-e2e` job in `nightly-e2e.yaml`. ## Related Issue Closes NVIDIA#2242 ## Changes - **Version output (TC-DIAG-04):** Runs `nemoclaw --version`, verifies output matches semver pattern and exits with code 0. No sandbox needed. - **Quick debug snapshot (TC-DIAG-02):** Runs `nemoclaw debug --quick --output <path>`, verifies a non-empty archive is produced within 30 seconds. No sandbox needed. - **Full debug tarball + credential sanitization (TC-DIAG-01):** Runs `nemoclaw debug --output <path>`, extracts the tarball, greps all files for the real API key value and `nvapi-` patterns. Verifies no credentials found in any collected file. - **Sandbox inference config (TC-DIAG-05):** Reads `openclaw.json` inside the sandbox via SSH, verifies the model field is present. Runs `nemoclaw status` from the host and verifies the Model field appears in output. - **Credentials list safety (TC-DIAG-03):** Runs `nemoclaw credentials list`, verifies key names are shown but the real API key value is not exposed. Handles the CI case where the credential store is empty (API key passed via env var). - **Nightly integration:** Added `diagnostics-e2e` job to `nightly-e2e.yaml` with 45-minute timeout, artifact upload on failure, and wired into `notify-on-failure`. ## Type of Change - Code change (feature, bug fix, or refactor) ## Verification - `npx prek run --all-files` passes - Tests added or updated for new or changed behavior - No secrets, API keys, or credentials committed - Verified on CI: all PASS on ubuntu-latest ## AI Disclosure - AI-assisted — tool: Cursor --- Signed-off-by: Truong Nguyen <tgnguyen@nvidia.com> Made with [Cursor](https://cursor.com) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added an end-to-end diagnostics test suite covering version checks, debug/export operations, credential handling (preventing secret leakage), sandbox onboarding/status, per-test PASS/FAIL/SKIP reporting, timestamped logs, and overall timeout support. * **Chores** * Nightly CI now runs diagnostics, uploads diagnostic logs on failure, and extends failure notifications so diagnostics failures trigger the existing alert workflow. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Truong Nguyen <tgnguyen@nvidia.com>
## Summary Fix TC-NET-03 always skipping on nightly by switching from a base-policy-whitelisted endpoint to one only reachable via preset. ## Related Issue Fixes NVIDIA#2274 ## Changes - **TC-NET-03:** Switched from `api.telegram.org` (whitelisted in base sandbox policy, always reachable) to `slack.com` (only reachable after applying slack preset). The blocked → add preset → reachable flow is now actually tested. - **TC-NET-04:** Switched from `slack.com` to `api.atlassian.com` (jira preset) because TC-NET-03 now applies the slack preset earlier in the suite. Each test uses a unique endpoint to avoid interference. - **Nightly workflow:** Added `NEMOCLAW_POLICY_TIER: restricted` to the `network-policy-e2e` job env to ensure no presets are applied during initial setup. - **install_nemoclaw():** Added `NEMOCLAW_POLICY_TIER=restricted` to the install.sh call so the initial onboard also uses restricted tier. ## Type of Change - Code change (feature, bug fix, or refactor) ## Verification - `npx prek run --all-files` passes - Verified on CI: 10/10 PASS, 0 SKIP on ubuntu-latest ## AI Disclosure - AI-assisted — tool: Cursor --- Signed-off-by: Truong Nguyen <tgnguyen@nvidia.com> Made with [Cursor](https://cursor.com) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * E2E network-policy tests updated to target different service integrations (Slack and Atlassian) and to align their checks and messages with those integrations. * **Chores** * Installation and test environments standardized to use the "restricted" policy tier. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Truong Nguyen <tgnguyen@nvidia.com>
…IA#2279) install.sh previously delegated all OpenShell CLI install/upgrade to `nemoclaw onboard`. When onboard is skipped (host preflight blocks, user aborts, interrupted session) the version gate never runs, so a curl|bash upgrade could leave openshell stale even though the new NemoClaw release declares a higher min_openshell_version. Run install-openshell.sh at the tail of install_nemoclaw instead. The script is idempotent — it exits 0 if the installed version is already within [MIN_VERSION, MAX_VERSION], so calling it every install is free on the happy path. The onboard-side check at onboard.ts:2664-2706 stays in place as a safety net for direct `nemoclaw onboard` invocations outside the installer. Fixes NVIDIA#2272. <!-- markdownlint-disable MD041 --> ## Summary <!-- 1-3 sentences: what this PR does and why. --> ## Related Issue <!-- Fixes #NNN or Closes #NNN. Remove this section if none. --> ## Changes <!-- Bullet list of key changes. --> ## Type of Change - [X] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification <!-- Check each item you ran and confirmed. Leave unchecked items you skipped. --> - [X] `npx prek run --all-files` passes - [X] `npm test` passes - [ ] Tests added or updated for new or changed behavior - [X] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) ## AI Disclosure <!-- If an AI agent authored or co-authored this PR, check the box and name the tool. Remove this section for fully human-authored PRs. --> - [X] AI-assisted — tool: Claude Code<!-- e.g., Claude Code, Cursor, GitHub Copilot --> --- <!-- DCO sign-off required by CI. Run: git config user.name && git config user.email --> Signed-off-by: Tinson Lai <tinsonl@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Installer now runs the OpenShell CLI installation/upgrade during initial setup so it’s available immediately instead of waiting for a later onboarding step. * OpenShell installation/upgrade is attempted on every install to ensure the CLI is present and kept up to date. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Tinson Lai <tinsonl@nvidia.com> Co-authored-by: Claude <noreply@anthropic.com>
…uild (NVIDIA#2302) ## Summary - `sandboxRebuild()` called `onboard({ resume: true })` without passing the session's stored `fromDockerfile`, causing the conflict check to reject the resume (`requestedFrom=null` vs `recordedFrom="/path/to/Dockerfile"`) - This made `nemoclaw <name> rebuild` and `nemoclaw upgrade-sandboxes` fail unconditionally for any sandbox created with `--from` - Fix reads the stored `fromDockerfile` from session metadata and passes it through to `onboard()` Fixes NVIDIA#2301 ## Test plan - [x] New test: rebuild does not hit fromDockerfile conflict when session has a stored `--from` path - [x] Existing NVIDIA#2201 regression tests still pass (agent syncing unaffected) - [x] All 3 rebuild tests pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed rebuild operations to properly preserve and use the stored Dockerfile source configuration, preventing errors when resuming sessions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
NVIDIA#2296) ## Summary - Add `ws-proxy-fix.ts` preload script that patches `https.request()` to detect WebSocket upgrade requests and inject a CONNECT tunnel agent, fixing Discord gateway connections through the OpenShell L7 proxy - Wire the preload into `nemoclaw-start.sh` (entrypoint + proxy-env.sh persistence for connect sessions) - Add blueprint TypeScript compilation infrastructure (`tsconfig.json`, `build:blueprint` script) Closes NVIDIA#1570 ## Details Node.js 22's `EnvHttpProxyAgent` (activated by `NODE_USE_ENV_PROXY=1`) sends forward proxy requests instead of CONNECT tunnels for HTTPS WebSocket upgrades. The OpenShell L7 proxy correctly rejects these with HTTP 400, breaking the Discord gateway connection. The preload intercepts `https.request()` calls that contain an `Upgrade: websocket` header and replaces the default agent with one that establishes a proper CONNECT tunnel through the proxy, then upgrades to TLS. Non-WebSocket HTTPS requests pass through unchanged. Belt-and-suspenders: if the caller (OpenClaw) already provides a custom agent, the preload steps aside — no double-tunnelling. Works regardless of any upstream OpenClaw fix. ## Test plan - [x] `npx vitest run test/service-env.test.ts` — 39 tests pass (5 new) - [x] `npm run build:blueprint` — clean TS compilation - [x] `npm run typecheck:cli` — clean type-check - [x] `npx prek run --all-files` — all relevant hooks pass (test-cli failures are pre-existing environmental) - [ ] E2E: deploy sandbox with Discord channel, verify gateway connects <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Adds a preload that enables HTTPS-proxy CONNECT tunneling for Discord gateway WebSocket upgrades when a proxy is configured * Start script now auto-applies the preload to launched sessions * **Bug Fixes** * Improved handling of WebSocket-upgrade requests over HTTPS proxies to prevent connection failures and port duplication * **Chores** * Blueprint compilation added to the CLI build * **Tests** * Added unit and e2e tests covering proxy injection and gateway handshake flows <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…lnerability (NVIDIA#2277) (NVIDIA#2297) ## Summary Extract common entrypoint functions from `scripts/nemoclaw-start.sh` (OpenClaw) and `agents/hermes/start.sh` (Hermes) into a shared shell library (`scripts/lib/sandbox-init.sh`). This fixes an active Hermes vulnerability (same class as NVIDIA#2181), prevents the two entrypoints from drifting further apart, and establishes reusable primitives for future agent types. ## Related Issue Fixes NVIDIA#2277 ## Changes - **`scripts/lib/sandbox-init.sh`** (new): Shared library with security primitives — `emit_sandbox_sourced_file()`, `validate_tmp_permissions()`, `drop_capabilities()`, `verify_config_integrity()`, `lock_rc_files()`, `cleanup_on_signal()`, `validate_config_symlinks()`, `harden_config_symlinks()`, `configure_messaging_channels()` - **`agents/hermes/start.sh`**: Sources shared library. **Security fix**: `.bashrc`/`.profile` now locked to 444 via `lock_rc_files()` (was wide open). Proxy config now uses `emit_sandbox_sourced_file` (root:root 444) instead of inline append to writable `.bashrc`. `validate_tmp_permissions()` gate added before service launch. - **`scripts/nemoclaw-start.sh`**: Sources shared library. Replaced inline capsh block, `verify_config_integrity()`, symlink validation, messaging channels, cleanup, and proxy-env writing with shared versions. Proxy-env.sh now written via `emit_sandbox_sourced_file` (444 instead of 644). - **`test/sandbox-init.test.ts`** (new): 28 tests covering all shared library functions independently - **`test/nemoclaw-start.test.ts`**: Updated tests for shared `cleanup_on_signal` pattern (replaces inline `cleanup()`) - **`test/service-env.test.ts`**: Updated sed extraction anchors for `emit_sandbox_sourced_file` pattern; added 444 permission assertion ### Hermes vulnerability fix summary | Control | Before | After | |---|---|---| | `.bashrc`/`.profile` locked? | **No — wide open** | ✅ chmod 444 via `lock_rc_files` | | Proxy config | **Inline in writable .bashrc** | ✅ Standalone 444 file via `emit_sandbox_sourced_file` | | `/tmp` permission validation | **Missing** | ✅ `validate_tmp_permissions` before service launch | | Future fixes auto-applied? | **No — manual port** | ✅ Both source same library | ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification - [x] `npx prek run --all-files` passes (shellcheck, shfmt, eslint, prettier, gitleaks all pass; test runner has pre-existing Docker-dependent failures on main) - [x] `npm test` passes (sandbox-init 28/28, service-env 34/34, nemoclaw-start 68/68; pre-existing install-preflight failures unrelated to this PR) - [x] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) ## AI Disclosure - [x] AI-assisted — tool: Claude Code (pi agent) --- Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Centralized and hardened sandbox startup logic with stricter /tmp and config permission checks, symlink protections, capability-lowering, improved signal/shutdown handling, and safer proxy env persistence. * **Tests** * Added comprehensive tests covering sandbox init routines, permission enforcement, integrity checks, symlink hardening, capability behavior, and signal/cleanup semantics. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Add "save it now — will not be printed again" to the tokenized dashboard URL line in both onboard print paths (OpenClaw in onboard.ts, agent UI in agent-onboard.ts). Treat the URL as a one-shot credential (GitHub-PAT style) rather than exposing it through `nemoclaw status`, which would widen incidental leakage via CI logs and issue-paste output. Fixes NVIDIA#2167 <!-- markdownlint-disable MD041 --> ## Summary <!-- 1-3 sentences: what this PR does and why. --> ## Related Issue <!-- Fixes #NNN or Closes #NNN. Remove this section if none. --> ## Changes <!-- Bullet list of key changes. --> ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification <!-- Check each item you ran and confirmed. Leave unchecked items you skipped. --> - [x] `npx prek run --all-files` passes - [x] `npm test` passes - [x] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) ## AI Disclosure <!-- If an AI agent authored or co-authored this PR, check the box and name the tool. Remove this section for fully human-authored PRs. --> - [x] AI-assisted — tool: <!-- e.g., Claude Code, Cursor, GitHub Copilot --> --- <!-- DCO sign-off required by CI. Run: git config user.name && git config user.email --> Signed-off-by: Your Name <your-email@example.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Documentation** * Improved guidance in onboarding console messages regarding tokenized URLs. When users encounter the authentication token during the setup process, they are now explicitly instructed to save it immediately and clearly informed that the token will not be printed again in the future. This applies to both agent and gateway UI setup flows. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Paritosh Dixit <paritoshd@nvidia.com>
…DIA#380) ## Summary - Always show an "Install Ollama" option during onboard on Linux (not just macOS), so users have a local inference fallback when `build.nvidia.com` is overloaded or down - Use the official `curl -fsSL https://ollama.com/install.sh | sh` installer on Linux (Homebrew on macOS) - Add `install-ollama` as a valid `NEMOCLAW_PROVIDER` value for non-interactive/CI mode ## Problem When Ollama is not installed and the NVIDIA API server is unavailable, `nemoclaw onboard` presents only the cloud option on Linux. Users can't get an API key and onboarding fails with no fallback path (issue NVIDIA#301). ## Fix The `install-ollama` option was already implemented for macOS but gated behind `process.platform === "darwin"`. This PR extends it to Linux with the appropriate installer command. The change is minimal — no restructuring of the onboard flow. Fixes NVIDIA#301 ## Test plan - [x] New test: verifies `Install Ollama (Linux)` option appears when Ollama is not installed on Linux - [x] New test: verifies the curl installer (not Homebrew) is invoked on Linux - [x] Existing `onboard-selection.test.js` tests still pass - [x] All onboard/credentials/inference-config tests pass - [x] `npm test` shows no new failures (pre-existing failures in `runtime-shell.test.js` and `install-preflight.test.js` are unrelated) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added automatic Ollama installation option with platform-specific methods: `brew install` on macOS and curl-based installation on Linux * Enhanced provider selection with improved fallback behavior during non-interactive setup <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Josue Balandrano Coronel <josuebc@pm.me> --------- Signed-off-by: Josue Gomez <josue@guatulab.com> Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> Co-authored-by: futhgar <futhgar@users.noreply.github.com> Co-authored-by: Test User <test@example.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com> Co-authored-by: Aaron Erickson 🦞 <aerickson@nvidia.com>
…IA#2257) <!-- markdownlint-disable MD041 --> ## Summary Extends `test/e2e/test-token-rotation.sh` to cover Discord rotation alongside Telegram (with provider-isolation checks), and makes the test resilient to environmental install failures so corporate-VPN runs SKIP cleanly instead of exiting 1 mid-Phase 0. ## Related Issue Fixes NVIDIA#2247 Closes NVIDIA#2255 ## Changes **Test script (`test/e2e/test-token-rotation.sh`)** - Phase 0 now seeds both `TELEGRAM_BOT_TOKEN` and `DISCORD_BOT_TOKEN`; Phase 1 verifies both providers and both credential hashes are stored. - Add Phase 4 (Discord rotation) and Phase 5 (re-onboard with same tokens) mirroring the existing Telegram phases. - Phase 2 (Telegram) and Phase 4 (Discord) each get a Negative provider-isolation check — the rotation message must NOT name the provider whose token didn't change. - Add `SKIP` counter and `skip()` helper. When `install.sh` fails with `(Telegram|Discord) network reachability failure` in the install log (typical of VPN/proxy blocking `api.telegram.org`), record a SKIP, mark Phases 1–5 as skipped, and still print the Summary instead of exiting 1. - Per-phase onboard failures no longer hard-exit — Summary always runs. - Add Discord prereq guards (`DISCORD_BOT_TOKEN_A`/`_B` set, A ≠ B); SKIP cleanly if either is missing. **CI (`.github/workflows/nightly-e2e.yaml`)** - Wire `DISCORD_BOT_TOKEN_A` / `DISCORD_BOT_TOKEN_B` into the `token-rotation-e2e` job so the new prereq guards do not skip the test under nightly cron. - Refresh the job comment to mention the combined Telegram + Discord coverage. ## Type of Change - [x] Code change (feature, bug fix, or refactor) ## Verification - [ ] `npx prek run --all-files` passes - [ ] `npm test` passes - [ ] Tests added or updated for new or changed behavior - [ ] No secrets, API keys, or credentials committed --- <!-- DCO sign-off required by CI. Run: git config user.name && git config user.email --> Signed-off-by: Hung Le <hple@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Clarified test description to state per-provider (Telegram + Discord) fake tokens and cross-talk assertions. * **Tests** * Extended end-to-end token-rotation tests to include Discord alongside Telegram and added corresponding environment variables. * Added prereq gating, skip counting and summary reporting for missing tokens, install/network failures, or identical tokens. * Strengthened post-install verification for both provider bridges and credential registration. * Implemented provider-isolated rotation phases and reuse assertions for sandbox onboarding. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Bumps the pinned OpenShell version range from `0.0.29` → `0.0.32` so fresh NemoClaw installs pick up sandbox hardening and TLS improvements from the last three OpenShell releases. ## Notable upstream changes **0.0.30** ([NVIDIA/OpenShell@v0.0.29...v0.0.30](NVIDIA/OpenShell@v0.0.29...v0.0.30)) - Network policy deny rules ([OpenShell#822](NVIDIA/OpenShell#822)) - Preserve ownership on existing `read_write` paths ([OpenShell#827](NVIDIA/OpenShell#827)) - Disable child core dumps ([OpenShell#821](NVIDIA/OpenShell#821)) - Escape control characters in SSE error formatting ([OpenShell#842](NVIDIA/OpenShell#842)) - Fix silent truncation of large streaming inference responses ([OpenShell#834](NVIDIA/OpenShell#834)) **0.0.31** ([NVIDIA/OpenShell@v0.0.30...v0.0.31](NVIDIA/OpenShell@v0.0.30...v0.0.31)) - Inference routed-request header allowlist ([OpenShell#826](NVIDIA/OpenShell#826)) **0.0.32** ([NVIDIA/OpenShell@v0.0.31...v0.0.32](NVIDIA/OpenShell@v0.0.31...v0.0.32)) - **Load system CA certificates for upstream TLS connections** ([OpenShell#862](NVIDIA/OpenShell#862)) - Publish standalone `openshell-gateway` binaries ([OpenShell#853](NVIDIA/OpenShell#853)) ## Changes - `nemoclaw-blueprint/blueprint.yaml`: `min_openshell_version` and `max_openshell_version` → `0.0.32` - `scripts/install-openshell.sh`: `MIN_VERSION` and `MAX_VERSION` → `0.0.32` (`PIN_VERSION` follows `MAX`) - `scripts/brev-launchable-ci-cpu.sh`: default `OPENSHELL_VERSION` → `v0.0.32` - `src/lib/onboard.ts`: blueprint-fallback min version → `0.0.32` - `test/onboard.test.ts`, `test/install-openshell-version-check.test.ts`: fixtures updated; "above MAX" test case moved from `0.0.30` to `0.0.33` Historical `m-dev` comments referencing `0.0.29` left in place — they describe a self-report quirk the sidecar fallback still handles. ## Why not 0.0.33+? `0.0.34` introduced incremental sandbox policy updates and L7 request-target canonicalization — changes with larger surface area against how NemoClaw delivers policy via gRPC. Worth a follow-up PR rather than bundling here. `0.0.35` released hours before this PR was cut — too fresh. ## Type of Change - [x] Code change for a new feature, bug fix, or refactor. ## Testing - [x] `npx vitest run test/install-openshell-version-check.test.ts` — 9 passed - [x] pre-commit hooks (prek) clean: shellcheck, commitlint, gitleaks, YAML validator, CLI test suite - [ ] Nightly E2E on this branch — will be kicked off after PR opens ## Notes - No user-facing CLI behavior changes — just the pinned version range. - Two pre-existing failures in `test/onboard.test.ts` reproduce on clean `main` and are unrelated to this bump. Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated OpenShell version constraints and default pinned version to v0.0.32 across configuration, install, and onboarding flows. * **Tests** * Updated test fixtures and expectations to match the new OpenShell version (v0.0.32). <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary Add a maintainer skill for normalizing bracketed `NemoClaw` tags in issue and PR titles. The skill provides a dry-run workflow, a reusable TypeScript helper that matches tags case-insensitively anywhere in the title, and verification guidance so maintainers can apply the cleanup safely. ## Changes - Add `.agents/skills/nemoclaw-maintainer-normalize-title-tags/SKILL.md` with a dry-run-first workflow for previewing, applying, and verifying title tag cleanup - Add `.agents/skills/nemoclaw-maintainer-normalize-title-tags/scripts/normalize-title-tags.ts` to find and remove bracketed `nemoclaw` tags case-insensitively from GitHub issue and PR titles - Update `.agents/skills/nemoclaw-skills-guide/SKILL.md` to include the new maintainer skill in the catalog ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification - [x] `npx prek run --all-files` passes - [ ] `npm test` passes - [ ] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) ## AI Disclosure - [x] AI-assisted — tool: OpenAI Codex --- Signed-off-by: Carlos Villela <cvillela@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new maintainer skill to preview and bulk remove bracketed title tags containing "NemoClaw" from GitHub issues and pull requests, with dry-run preview and optional apply execution modes. * **Documentation** * Added comprehensive documentation for the new title-tag normalization skill with step-by-step usage instructions and behavioral guidelines. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Carlos Villela <cvillela@nvidia.com> Co-authored-by: Aaron Erickson 🦞 <aerickson@nvidia.com>
## Summary Catch up the user-facing docs for features and command renames merged since v0.0.22, and bump the doc-site version strings to 0.0.23. ## Related Issue <!-- Fixes #NNN or Closes #NNN. Remove this section if none. --> ## Changes - `docs/reference/commands.md` — Documented `snapshot create --name`, the new version-aware `snapshot list` table, and version/name/timestamp selectors for `snapshot restore` (from NVIDIA#2184). Renamed `nemoclaw start`/`stop` sections to `nemoclaw tunnel start`/`stop` with a deprecation note on the legacy aliases, and added new `channels start`/`channels stop` per-channel subsections (from NVIDIA#2103). - `docs/workspace/backup-restore.md` — Added `--name` and `v<N>` / name / timestamp selector examples for the snapshot commands. - `docs/deployment/set-up-telegram-bridge.md`, `docs/deployment/deploy-to-remote-gpu.md`, `docs/reference/troubleshooting.md` — Switched references from `nemoclaw start` to `nemoclaw tunnel start`; noted `channels stop/start` as the non-destructive way to pause a bridge. - `docs/project.json`, `docs/versions1.json` — Bumped preferred doc version to 0.0.23 and moved 0.0.22 into the version history list. - `.agents/skills/nemoclaw-user-*` — Regenerated via `scripts/docs-to-skills.py` so downstream skills match the doc sources. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [x] Doc only (includes code sample changes) ## Verification - [x] `npx prek run --all-files` passes - [ ] `npm test` passes - [ ] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [x] Docs updated for user-facing behavior changes - [x] `make docs` builds without warnings (doc changes only) - [x] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) Note on `npm test`: the CLI suite hit a pre-existing environmental timeout in `test/cli.test.ts:60` (`bare unknown name surfaces sandbox-not-found`) reaching a non-running local gateway. The plugin and skills YAML suites pass. This PR touches only Markdown + JSON under `docs/` and autogenerated `.agents/skills/` output, so the failing test is unrelated. ## AI Disclosure - [x] AI-assisted — tool: Claude Code --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added `channels stop/start` commands to pause and resume individual messaging bridges without destroying sandboxes * Introduced `--name` flag for creating labeled snapshots with improved restore selection (by version, name, or timestamp) * Added `--dangerously-skip-permissions` flag to `nemoclaw onboard` * Renamed host auxiliary commands to `nemoclaw tunnel start/stop` (legacy aliases retained for backward compatibility) * **Documentation** * Expanded quickstart guide with recovery, reconfiguration, and credential reset workflows * Updated all documentation to reflect new command structure and bridge lifecycle operations <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
When a Gemini onboard validates with an expired API key, the provider
returns HTTP 400 with `"API key expired. Please renew the API key."`.
The current classifier checks `httpStatus === 400` first and returns `{
kind: "model", retry: "model" }`, so the expired-key case never reaches
the credential-message regex. In the Gemini validation flow (no
`allowModelRetry`), `kind: "model"` falls through to `unknown`, and the
onboard wizard loops back to provider selection without offering to
re-enter the key.
## Related Issue
Closes NVIDIA#1942
## Changes
- `src/lib/validation.ts` — move the credential-bearing message check
**before** the `httpStatus === 400 → model` default. Extend the
credential regex to include `api key expired` and `api[_ ]key[_
]invalid` so Gemini's `API_KEY_INVALID` status classification also lands
as `credential`.
- Inline comment documents why the order matters and cites NVIDIA#1942.
- HTTP 400 without a credential-bearing message still classifies as
`model` — regression guard test added.
## Testing
- [x] `src/lib/validation.test.ts` — 41 tests pass (+3 new: expired key,
API_KEY_INVALID, regression guard)
- [x] `src/lib/validation-recovery.test.ts` — 5 tests pass
- [x] Build + typecheck clean
Executed:
- Targeted `npx vitest run src/lib/validation.test.ts
src/lib/validation-recovery.test.ts` in the `nemoclaw-test` Docker
environment
## Prior art
Prior fix attempt [NVIDIA#1944](NVIDIA#1944)
was closed by its author on 2026-04-18 to reduce PR volume — the issue
remained open. This PR replays the same core reorder with a slightly
broader credential regex (covering both `API key expired` and
`API_KEY_INVALID` forms Gemini uses) and preserves the existing test
style.
## Checklist
- [x] Follows [Conventional
Commits](https://www.conventionalcommits.org/)
- [x] Commits are signed (SSH)
- [x] DCO Signed-off-by trailer present
Signed-off-by: latenighthackathon
<latenighthackathon@users.noreply.github.com>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Error classification now prioritizes credential-related messages so
API key/credential failures (expired, invalid, unauthorized) are
reported as credential issues rather than being misclassified as model
errors, improving clarity and retry guidance.
* **Tests**
* Added tests covering credential-related 400 responses and a regression
case to ensure unrelated model errors remain classified correctly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
Co-authored-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
…1913) ## Problem The `setup-jetson.sh` script used `sed` to patch `/etc/docker/daemon.json` on JP6 devices. The sed command stripped the trailing comma from `"default-runtime": "nvidia",`: ``` s/"default-runtime": "nvidia",/"default-runtime": "nvidia"/ ``` This produced invalid JSON when `"runtimes"` was the next key: ```json { "default-runtime": "nvidia" ← missing comma here "runtimes": { "nvidia": { ... } } } ``` Docker rejects malformed JSON and fails to start, causing `Job for docker.service failed` errors. ## Fix Replace the sed one-liner with a Python3 snippet that parses the JSON properly, removes the `iptables` and `bridge` keys cleanly, and writes back valid JSON. Python3 is available on all supported Jetson/Ubuntu setups. Fixes NVIDIA#1875 Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Safer Jetson setup: Docker daemon configuration handling during installation is now more robust and less likely to corrupt existing files. * Improved validation and error handling: installers attempt to repair common formatting issues but will stop instead of overwriting unfixable malformed files. * Preserves original file permissions and uses atomic writes to ensure safer updates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com>
PR NVIDIA#2110's axios-only Module._load preload never fired at runtime: 1. nemoclaw-blueprint/scripts/ is excluded from the optimized sandbox build context (src/lib/sandbox-build-context.ts), so axios-proxy-fix.js was not baked into the sandbox image. 2. Adding scripts/ to the build context cache-busts the `COPY nemoclaw-blueprint/` Dockerfile layer and hangs npm ci in the k3s Docker-in-Docker build, so the delivery gap cannot be closed by expanding the context. 3. Even if the file had reached the image, intercepting require('axios') via Module._load cannot patch follow-redirects + proxy-from-env bundled as ESM in OpenClaw's dist/http-Bh-HtMAg.js — there are no require() calls to intercept. The Bot Connector reply path uses the bundled code. Replace with an http.request() wrapper — the lowest common denominator every HTTP library bottoms out at. Detect FORWARD-mode requests (hostname = proxy IP, path = full https:// URL) and rewrite them to https.request() against the real target, letting NODE_USE_ENV_PROXY handle the CONNECT tunnel correctly. Works for any HTTP client, including bundled ESM that makes no require() calls. Delivery: - nemoclaw-blueprint/scripts/http-proxy-fix.js — canonical source for review and tests. - scripts/nemoclaw-start.sh embeds the same JS inline via a heredoc, writes it to /tmp/nemoclaw-http-proxy-fix.js through emit_sandbox_sourced_file (root:root 444, symlink-safe), and loads it via NODE_OPTIONS=--require. No changes to sandbox-build-context. - test/http-proxy-fix-sync.test.ts enforces byte-for-byte equality between the heredoc and the canonical file, so future edits cannot silently diverge. - validate_tmp_permissions is invoked with the new path on both the root and non-root boot paths (the fix JS is a trust-boundary file — tampering would inject arbitrary code into every Node process via NODE_OPTIONS). Because the content ships inside nemoclaw-start.sh rather than as a separately-deployed file, the fix fires on the very first sandbox boot with no post-onboard deploy + restart dance required. Closes the NVIDIA#2109 regression class; removes the superseded axios-proxy-fix.js and updates the existing regression tests in service-env.test.ts to the new variable name (_PROXY_FIX_SCRIPT). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lcsmontiel
marked this pull request as ready for review
April 23, 2026 02:59
lcsmontiel
pushed a commit
that referenced
this pull request
May 19, 2026
…3456) (NVIDIA#3520) > **Draft for visibility.** Issue-autopilot Stages 4-5 of NVIDIA#3456. Will mark ready once batch self-review + CI complete. ## Summary Closes the two remaining output threads in NVIDIA#3456 after the core dead-loop fix already landed on `main` (via NVIDIA#3459, NVIDIA#3434, NVIDIA#3483). Full sub-bug mapping in the [NVIDIA#3456 status comment](NVIDIA#3456 (comment)). - **Sub-bug #3** — `nemoclaw <name> destroy --yes` recovery hint replaced with a registry-aware helper. - **Sub-bug NVIDIA#4** — `Destroyed gateway 'nemoclaw' skipped` self-contradictory wording replaced with `Gateway 'nemoclaw' already removed or unreachable`. ## Acceptance criteria mapping | Sub-bug | Resolution | Evidence | |---|---|---| | #1 dead loop | Already fixed on main (NVIDIA#3459) | out of scope | | #2 firewall diagnostic | Already fixed on main (NVIDIA#3459) | out of scope | | **#3** literal `<name>` placeholder | **This PR** | `src/lib/onboard/gpu-recovery.ts` + `onboard.ts:10387-10405` | | **NVIDIA#4** misleading "skipped" wording | **This PR** | `src/lib/actions/uninstall/run-plan.ts:210-228, 407-414` | | NVIDIA#5 uninstall residuals | Already fixed on main (NVIDIA#3483) | out of scope | ## Behavior matrix `gpuPassthroughRecoveryLines(names)`: | Input | Suggestion | |---|---| | `null` / `[]` | `nemoclaw uninstall && nemoclaw onboard --gpu` | | one sandbox | `nemoclaw <name> destroy --yes --cleanup-gateway && nemoclaw onboard --gpu` | | many sandboxes | each `destroy --yes`, only the last gets `--cleanup-gateway` | ## Test plan ``` npm run typecheck:cli npx vitest run src/lib/onboard/gpu-recovery.test.ts src/lib/actions/uninstall/run-plan.test.ts ``` 22 tests pass (6 new + 16 existing). ## Notes for reviewers - This is the work [NVIDIA#3464 attempted](NVIDIA#3464); that PR was closed without merging after CodeRabbit asked for the `<name>` placeholder to be forbidden in tests via negative assertion. This PR adopts that refinement. - `runOptional` extension is backwards-compatible — existing callers without `onSkip` get the original wording. Closes NVIDIA#3456 once merged. --------- Signed-off-by: Charan Jagwani <charjags100@gmail.com> Co-authored-by: Charan Jagwani <charjags100@gmail.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR NVIDIA#2110's
axios-proxy-fix.jsModule._load preload never fired in production:nemoclaw-blueprint/scripts/is excluded from the optimized sandbox build context (seesrc/lib/sandbox-build-context.ts), soaxios-proxy-fix.jsnever landed in the image.scripts/to the build context cache-busts theCOPY nemoclaw-blueprint/layer and hangsnpm ciin the k3s Docker-in-Docker build — the delivery gap can't be closed by expanding the context.require('axios')viaModule._loadcan't patchfollow-redirects+proxy-from-envbundled as ESM in OpenClaw'sdist/http-Bh-HtMAg.js— there are norequire()calls to intercept. The Bot Connector reply path uses the bundled code.This change replaces the preload with an
http.request()wrapper — the lowest common denominator every HTTP client bottoms out at. When a library configures an HTTP FORWARD-mode request (hostname == proxy,path == https://...), the wrapper rewrites it ashttps.request()against the real target, lettingNODE_USE_ENV_PROXYhandle the CONNECT tunnel correctly. Works for axios, follow-redirects, proxy-from-env, and any bundled ESM that makes norequire()calls.Delivery
nemoclaw-blueprint/scripts/http-proxy-fix.js— new canonical source for review and tests.scripts/nemoclaw-start.shembeds the same JS inline via a heredoc, writes it to/tmp/nemoclaw-http-proxy-fix.jsthroughemit_sandbox_sourced_file(root:root 444, symlink-safe), and loads it viaNODE_OPTIONS=--require. Nosandbox-build-context.tschange required. Fix fires on the first sandbox boot — no post-onboard deploy + restart dance.test/http-proxy-fix-sync.test.ts— new test that enforces byte-for-byte equality between the heredoc and the canonical file, so future edits can't silently diverge.validate_tmp_permissionsis invoked with the new path on both root and non-root boot paths — the fix JS is a trust-boundary file; tampering would inject arbitrary code into every Node process viaNODE_OPTIONS.nemoclaw-blueprint/scripts/axios-proxy-fix.jsis removed.test/service-env.test.tsaxios requests fail with ERR_BAD_RESPONSE inside NemoClaw sandbox — double proxy conflict with NODE_USE_ENV_PROXY NVIDIA/NemoClaw#2109 regression tests are updated for the new variable name (_PROXY_FIX_SCRIPT) and drop the file-existence check (the entrypoint writes the file unconditionally whenNODE_USE_ENV_PROXY=1). [All platforms] Discord channel fails with 400 — Node.js EnvHttpProxyAgent uses forward proxy instead of CONNECT tunnel NVIDIA/NemoClaw#1570 ws-fix tests keep passing.Reproduction (from original issue)
Inside a NemoClaw sandbox with
NODE_USE_ENV_PROXY=1, before the fix:```bash
FAIL — follow-redirects configures FORWARD, NODE_USE_ENV_PROXY double-processes
node -e "require('axios').get('https://clawhub.ai', {timeout:10000}).then(r => console.log('PASS', r.status)).catch(e => console.log('FAIL', e.code))"
```
After the fix, the same call returns `PASS 200`.
Test plan
Fixes NVIDIA#2109. Supersedes NVIDIA#2110.