fix(proxy): inject NO_PROXY=localhost,127.0.0.1 when HTTP_PROXY is set (#2616)#2662
Conversation
NVIDIA#2616) On hosts with a system HTTP proxy (e.g. Privoxy, corporate CONNECT proxy), subprocesses inherit HTTP_PROXY but no NO_PROXY, so loopback requests to the Ollama daemon (:11434) and the auth proxy (:11435) are tunnelled through the proxy and fail with "HTTP 500 — Privoxy could not connect to 127.0.0.1". Three changes: 1. subprocess-env.ts (CLI + plugin mirror): add withLocalNoProxy() that appends localhost and 127.0.0.1 to NO_PROXY/no_proxy whenever any HTTP proxy var is present. buildSubprocessEnv() calls it automatically, so all subprocess spawns via that helper are fixed. 2. onboard-ollama-proxy.ts: switch spawnOllamaAuthProxy() from { ...process.env } to buildSubprocessEnv() — fixes the proxy daemon env and removes the secret-leakage risk identified in NVIDIA#1874. 3. onboard-ollama-proxy.ts: switch pullOllamaModel() from { ...process.env } to buildSubprocessEnv() — fixes model pulls while keeping HTTP_PROXY active for the outbound ollama.ai registry fetch. Fixes NVIDIA#2616 Signed-off-by: Dongni Yang <dongniy@nvidia.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis change adds a Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Review rate limit: 9/10 reviews remaining, refill in 6 minutes. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/lib/subprocess-env.test.ts (1)
28-33: Optional: add a lowercasehttps_proxytest case for full branch coverage.
withLocalNoProxychecks lowercasehttps_proxyon Line 59 insrc/lib/subprocess-env.ts, but this suite currently validates lowercasehttp_proxyonly.➕ Suggested test addition
it("adds localhost and 127.0.0.1 when lowercase http_proxy is set", () => { const env: Record<string, string> = { http_proxy: "http://proxy:8888" }; withLocalNoProxy(env); expect(env.NO_PROXY).toBe("localhost,127.0.0.1"); expect(env.no_proxy).toBe("localhost,127.0.0.1"); }); + + it("adds localhost and 127.0.0.1 when lowercase https_proxy is set", () => { + const env: Record<string, string> = { https_proxy: "http://proxy:8888" }; + withLocalNoProxy(env); + expect(env.NO_PROXY).toBe("localhost,127.0.0.1"); + expect(env.no_proxy).toBe("localhost,127.0.0.1"); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/subprocess-env.test.ts` around lines 28 - 33, Add a parallel test that mirrors the existing "adds localhost and 127.0.0.1 when lowercase http_proxy is set" case but uses a lowercase https_proxy environment variable instead; call withLocalNoProxy(env) and assert that both env.NO_PROXY and env.no_proxy equal "localhost,127.0.0.1". This ensures the branch in withLocalNoProxy that checks for lowercase https_proxy is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/lib/subprocess-env.test.ts`:
- Around line 28-33: Add a parallel test that mirrors the existing "adds
localhost and 127.0.0.1 when lowercase http_proxy is set" case but uses a
lowercase https_proxy environment variable instead; call withLocalNoProxy(env)
and assert that both env.NO_PROXY and env.no_proxy equal "localhost,127.0.0.1".
This ensures the branch in withLocalNoProxy that checks for lowercase
https_proxy is covered.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: e90ef77b-d766-4d41-99ac-7948bbaa2349
📒 Files selected for processing (4)
nemoclaw/src/lib/subprocess-env.tssrc/lib/onboard-ollama-proxy.tssrc/lib/subprocess-env.test.tssrc/lib/subprocess-env.ts
|
Local macOS Verification — #2616 Validated the fix end-to-end on Apple Silicon macOS (Darwin 25.0.0) after merge. Setup
Bug confirmed on 7c5174e (pre-fix) With HTTP_PROXY=http://127.0.0.1:8118 set and NO_PROXY unset, the subprocess spawned with { ...process.env } routed the loopback probe through the proxy: Fix verified on 659d2d7 After switching to buildSubprocessEnv() (which calls withLocalNoProxy() automatically), the fake Privoxy terminal stayed completely silent — curl connected directly to Buggy build hits proxy? YES ✗ Repro result: PASS — bug reproduced and fix verified. |
## Summary Refreshes the daily docs from NemoClaw commits merged in the past 24 hours and advances the docs metadata from 0.0.29 to 0.0.31, the next version after tag v0.0.30. The updates cover documented behavior gaps found in the merged PRs listed below. ## Related Issue None. ## Changes - `docs/versions1.json` and `docs/project.json`: bump the preferred docs version to `0.0.31` for daily release preparation after latest tag `v0.0.30`. - `docs/reference/commands.md`: document non-interactive Brave Search validation fallback from #2511 / 9bfe30b, missing `--from <Dockerfile>` path validation from #2597 / 7186834, and `logs` reading OpenShell audit events from #2590 / e225dfb. - `docs/inference/use-local-inference.md`: document local inference reachability retry and host-side fallback from #2453 / 9dbe855, plus compatible-endpoint timeout coverage from #2583 / b4ef3db. - `docs/reference/troubleshooting.md`: document source-install shim fallback from #2520 / 01a177c, TLS gateway trust recovery from #1936 / 24725d2, compatible-endpoint timeout coverage from #2583 / b4ef3db, local reachability diagnostics from #2453 / 9dbe855, and host proxy `NO_PROXY` injection from #2662 / b4df07e. ## 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 - [ ] `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) Additional verification: - `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run` passed. - `git diff --check` passed. - Pre-push hooks passed through markdownlint, docs-to-skills, JSON checks, gitleaks, and version sync before `Test (skills YAML)` failed because this fresh worktree lacked `vitest/config`. - `npx prek run --all-files` could not run from the fresh worktree because `npx prek` resolved to a missing `prek@*` package; downloading `@j178/prek` was not approved. - `npm test` could not complete from the fresh worktree because dependencies and compiled `dist/lib/*` artifacts were absent. ## AI Disclosure - [x] AI-assisted — tool: OpenAI Codex --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Version updated to 0.0.31 * Local inference onboarding now includes retry logic for container reachability checks * Web search setup failure handling clarified with fallback guidance * Dockerfile path validation timing documented * Logging behavior clarified for concurrent stream reading * New TLS/certificate troubleshooting section added * Install path and proxy configuration troubleshooting updated <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>
NVIDIA#2616) (NVIDIA#2662) ## Summary On hosts with a system HTTP proxy (Privoxy, corporate CONNECT proxy, Cursor's bundled proxy), NemoClaw spawned the Ollama daemon and its `:11435` auth proxy with `HTTP_PROXY` inherited from the shell but no `NO_PROXY` set. Loopback requests — the auth-proxy health probe, `ollama pull`, and macOS curl's token validation — were tunnelled through the proxy and failed with: ``` HTTP 500 — Internal Privoxy Error Privoxy could not connect to the host: 127.0.0.1:11435 ``` The root cause is two call sites that used `{ ...process.env }` directly instead of the shared `buildSubprocessEnv()` allowlist, combined with `buildSubprocessEnv()` not guarding against a proxy-without-NO_PROXY environment. ## Related Issue Fixes NVIDIA#2616 ## How the fix works | Call site | Before | After | |---|---|---| | `spawnOllamaAuthProxy()` | `{ ...process.env, token, ports }` — full env including secrets | `buildSubprocessEnv({ token, ports })` — allowlisted env + NO_PROXY injected | | `pullOllamaModel()` | `{ ...process.env }` — full env | `buildSubprocessEnv()` — allowlisted env + NO_PROXY injected | | `buildSubprocessEnv()` | forwards `HTTP_PROXY` with no `NO_PROXY` guard | calls `withLocalNoProxy()` which appends `localhost,127.0.0.1` to both `NO_PROXY` and `no_proxy` when any proxy var is present | `withLocalNoProxy()` is additive: it appends only the missing entries so an existing `NO_PROXY=corp.internal` becomes `corp.internal,localhost,127.0.0.1`, preserving outbound proxy functionality for external registries like `registry.ollama.ai`. ## Changes - **`src/lib/subprocess-env.ts`**: add exported `withLocalNoProxy(env)` helper; call it at the end of `buildSubprocessEnv()`. When `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy`, or `https_proxy` is present, appends `localhost` and `127.0.0.1` to both `NO_PROXY` and `no_proxy` if either entry is missing. - **`nemoclaw/src/lib/subprocess-env.ts`**: mirror of above (kept in sync per existing policy). - **`src/lib/onboard-ollama-proxy.ts`**: add `require("./subprocess-env")` import; switch `spawnOllamaAuthProxy()` from `{ ...process.env, ... }` to `buildSubprocessEnv({ ... })` (also fixes the NVIDIA#1874 secret-leakage risk for this spawn); switch `pullOllamaModel()` from `{ ...process.env }` to `buildSubprocessEnv()`. - **`src/lib/subprocess-env.test.ts`** (new): 11 unit tests covering `withLocalNoProxy` (no proxy → no-op, HTTP_PROXY/HTTPS_PROXY/http_proxy each trigger injection, partial NO_PROXY is extended, full NO_PROXY is unchanged) and `buildSubprocessEnv` integration (injection on proxy set, augmentation of existing NO_PROXY, no injection when no proxy, extra vars preserved). ## 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 - [ ] `npx prek run --all-files` passes - [x] `npm test` passes (subprocess-env: 11/11 new tests pass; full suite clean) - [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 --- Signed-off-by: Dongni Yang <dongniy@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed HTTP proxy configuration to ensure localhost and loopback traffic properly bypass proxy routing when proxy environment variables are configured. * **Tests** * Added comprehensive test coverage for proxy bypass functionality in subprocess environment setup. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Dongni Yang <dongniy@nvidia.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary Refreshes the daily docs from NemoClaw commits merged in the past 24 hours and advances the docs metadata from 0.0.29 to 0.0.31, the next version after tag v0.0.30. The updates cover documented behavior gaps found in the merged PRs listed below. ## Related Issue None. ## Changes - `docs/versions1.json` and `docs/project.json`: bump the preferred docs version to `0.0.31` for daily release preparation after latest tag `v0.0.30`. - `docs/reference/commands.md`: document non-interactive Brave Search validation fallback from NVIDIA#2511 / 9bfe30b, missing `--from <Dockerfile>` path validation from NVIDIA#2597 / 7186834, and `logs` reading OpenShell audit events from NVIDIA#2590 / e225dfb. - `docs/inference/use-local-inference.md`: document local inference reachability retry and host-side fallback from NVIDIA#2453 / 9dbe855, plus compatible-endpoint timeout coverage from NVIDIA#2583 / b4ef3db. - `docs/reference/troubleshooting.md`: document source-install shim fallback from NVIDIA#2520 / 01a177c, TLS gateway trust recovery from NVIDIA#1936 / 24725d2, compatible-endpoint timeout coverage from NVIDIA#2583 / b4ef3db, local reachability diagnostics from NVIDIA#2453 / 9dbe855, and host proxy `NO_PROXY` injection from NVIDIA#2662 / b4df07e. ## 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 - [ ] `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) Additional verification: - `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run` passed. - `git diff --check` passed. - Pre-push hooks passed through markdownlint, docs-to-skills, JSON checks, gitleaks, and version sync before `Test (skills YAML)` failed because this fresh worktree lacked `vitest/config`. - `npx prek run --all-files` could not run from the fresh worktree because `npx prek` resolved to a missing `prek@*` package; downloading `@j178/prek` was not approved. - `npm test` could not complete from the fresh worktree because dependencies and compiled `dist/lib/*` artifacts were absent. ## AI Disclosure - [x] AI-assisted — tool: OpenAI Codex --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Version updated to 0.0.31 * Local inference onboarding now includes retry logic for container reachability checks * Web search setup failure handling clarified with fallback guidance * Dockerfile path validation timing documented * Logging behavior clarified for concurrent stream reading * New TLS/certificate troubleshooting section added * Install path and proxy configuration troubleshooting updated <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>
Summary
On hosts with a system HTTP proxy (Privoxy, corporate CONNECT proxy, Cursor's bundled proxy), NemoClaw spawned the Ollama daemon and its
:11435auth proxy withHTTP_PROXYinherited from the shell but noNO_PROXYset. Loopback requests — the auth-proxy health probe,ollama pull, and macOS curl's token validation — were tunnelled through the proxy and failed with:The root cause is two call sites that used
{ ...process.env }directly instead of the sharedbuildSubprocessEnv()allowlist, combined withbuildSubprocessEnv()not guarding against a proxy-without-NO_PROXY environment.Related Issue
Fixes #2616
How the fix works
spawnOllamaAuthProxy(){ ...process.env, token, ports }— full env including secretsbuildSubprocessEnv({ token, ports })— allowlisted env + NO_PROXY injectedpullOllamaModel(){ ...process.env }— full envbuildSubprocessEnv()— allowlisted env + NO_PROXY injectedbuildSubprocessEnv()HTTP_PROXYwith noNO_PROXYguardwithLocalNoProxy()which appendslocalhost,127.0.0.1to bothNO_PROXYandno_proxywhen any proxy var is presentwithLocalNoProxy()is additive: it appends only the missing entries so an existingNO_PROXY=corp.internalbecomescorp.internal,localhost,127.0.0.1, preserving outbound proxy functionality for external registries likeregistry.ollama.ai.Changes
src/lib/subprocess-env.ts: add exportedwithLocalNoProxy(env)helper; call it at the end ofbuildSubprocessEnv(). WhenHTTP_PROXY,HTTPS_PROXY,http_proxy, orhttps_proxyis present, appendslocalhostand127.0.0.1to bothNO_PROXYandno_proxyif either entry is missing.nemoclaw/src/lib/subprocess-env.ts: mirror of above (kept in sync per existing policy).src/lib/onboard-ollama-proxy.ts: addrequire("./subprocess-env")import; switchspawnOllamaAuthProxy()from{ ...process.env, ... }tobuildSubprocessEnv({ ... })(also fixes the fix(security): replace process.env spread with allowlist in blueprint runner #1874 secret-leakage risk for this spawn); switchpullOllamaModel()from{ ...process.env }tobuildSubprocessEnv().src/lib/subprocess-env.test.ts(new): 11 unit tests coveringwithLocalNoProxy(no proxy → no-op, HTTP_PROXY/HTTPS_PROXY/http_proxy each trigger injection, partial NO_PROXY is extended, full NO_PROXY is unchanged) andbuildSubprocessEnvintegration (injection on proxy set, augmentation of existing NO_PROXY, no injection when no proxy, extra vars preserved).Type of Change
Verification
npx prek run --all-filespassesnpm testpasses (subprocess-env: 11/11 new tests pass; full suite clean)make docsbuilds without warnings (doc changes only)AI Disclosure
Signed-off-by: Dongni Yang dongniy@nvidia.com
Summary by CodeRabbit
Bug Fixes
Tests