Skip to content

fix(cli): add local-inference policy preset for Ollama/vLLM host access (#693)#1469

Open
cv wants to merge 6 commits intomainfrom
fix/local-inference-preset-781
Open

fix(cli): add local-inference policy preset for Ollama/vLLM host access (#693)#1469
cv wants to merge 6 commits intomainfrom
fix/local-inference-preset-781

Conversation

@cv
Copy link
Copy Markdown
Contributor

@cv cv commented Apr 4, 2026

Summary

  • Add local-inference network policy preset allowing sandbox egress to host.openshell.internal on ports 11434 (Ollama) and 8000 (vLLM)
  • Auto-suggest the preset during onboarding when provider is ollama-local or vllm-local
  • Fix API key exposure in setupSpark, telegram-bridge.js, and walkthrough.sh by passing credentials via environment instead of command arguments
  • Conditional sudo for npm link in installer when global prefix is not writable

Supersedes #781. Closes #693.

Test plan

  • All pre-commit hooks pass (prettier, eslint, shellcheck, gitleaks, commitlint)
  • All pre-push hooks pass (TypeScript type-check, tests)
  • test/policies.test.js updated: preset count 9→10, new local-inference preset tests
  • test/runner.test.js updated: walkthrough credential exposure guard allows safe tmux -e pattern
  • Manual: nemoclaw onboard with ollama-local provider suggests local-inference preset at step 7
  • Manual: verify scripts/telegram-bridge.js passes API key via SendEnv (not in cmd args)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added local inference preset enabling integration with Ollama and vLLM providers via host gateway
    • Auto-detection of local inference providers with automatic policy suggestions during onboarding
  • Bug Fixes

    • Fixed npm installation to intelligently handle permission requirements
    • Corrected API key environment variable propagation in agent execution
  • Tests

    • Updated test coverage for local inference preset and environment variable handling

…ss (#693)

Add a local-inference network policy preset that allows sandbox egress
to host.openshell.internal on ports 11434 (Ollama) and 8000 (vLLM).
Auto-suggest the preset during onboarding when provider is ollama-local
or vllm-local.

Also fixes API key exposure in setupSpark, telegram-bridge, and
walkthrough by passing credentials via environment instead of command
arguments.

Supersedes #781.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 4, 2026

📝 Walkthrough

Walkthrough

This PR introduces local inference support by adding a local-inference policy preset and auto-detection logic in the onboarding wizard. When users select local providers (ollama-local or vllm-local) during onboarding Step 7, the system automatically suggests the new preset, which permits network access to Ollama (port 11434) and vLLM (port 8000) via host.openshell.internal. Additional changes refine npm linking with conditional sudo and propagate the NVIDIA_API_KEY environment variable through tmux.

Changes

Cohort / File(s) Summary
Onboarding logic
bin/lib/onboard.js
Updated _setupPolicies and setupPoliciesWithSelection to accept an optional provider parameter. Auto-detects when provider is ollama-local or vllm-local and conditionally adds local-inference preset to policy suggestions with console logging. Updated Step 7 call site to pass provider info.
Local inference policy preset
nemoclaw-blueprint/policies/presets/local-inference.yaml
New preset configuration defining network policies for local inference access. Specifies REST endpoints for Ollama (host.openshell.internal:11434) and vLLM (host.openshell.internal:8000) with enforcement enabled, allowing GET/POST requests. Includes permitted binaries (/usr/local/bin/openclaw, /usr/local/bin/claude).
Installation script
scripts/install.sh
Conditionally applies sudo to npm link based on npm global prefix writability. Queries npm config, checks if prefix path is writable and user is non-root, only using sudo when necessary.
Walkthrough script
scripts/walkthrough.sh
Added explicit environment variable forwarding for NVIDIA_API_KEY into the agent pane via tmux's -e flag, ensuring the API key is available in the sandbox environment.
Policy tests
test/policies.test.js
Updated preset count expectation from 10 to 11. Added comprehensive test suite for local-inference preset validating endpoint hosts, ports (11434, 8000), binaries section, and preset entry extraction.
Runner tests
test/runner.test.js
Updated credential exposure guard for walkthrough.sh to conditionally permit NVIDIA_API_KEY occurrences when formatted as proper tmux environment passing (tmux -e "NVIDIA_API_KEY=..."), preventing false positives on legitimate environment injection.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Onboarding as Onboarding Wizard
    participant Setup as setupPoliciesWithSelection
    participant Registry as Registry/Sandbox
    participant Policies as Policy System

    User->>Onboarding: Complete Step 7, select provider<br/>(e.g., ollama-local)
    Onboarding->>Setup: Call with { provider, ... }
    Setup->>Registry: provider argument provided?<br/>Resolve effective provider
    Registry-->>Setup: Return provider: ollama-local
    Setup->>Setup: Check if provider matches<br/>ollama-local OR vllm-local
    alt Provider is local inference
        Setup->>Policies: Auto-detect: load<br/>local-inference preset
        Policies-->>Setup: Preset loaded
        Setup->>Setup: Add local-inference to<br/>policy suggestions
        Note over Setup: Log auto-detection
    end
    Setup-->>Onboarding: Return suggestions list<br/>(includes local-inference)
    Onboarding-->>User: Present policy suggestions
    User->>User: Review & accept
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Whiskers twitch with local glee,
Ollama routes through proxy's decree,
Host gateway opens, eleven presets gleam,
Auto-detection fulfills the coding dream!
Sudo checks and tmux keys align,
Local inference—at last—is thine!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes to scripts/install.sh (conditional sudo for npm link) and scripts/walkthrough.sh (NVIDIA_API_KEY credential handling) appear unrelated to the core objective of adding local-inference policy preset support. Remove or justify in a separate PR the changes to install.sh and walkthrough.sh that address npm link sudo handling and API key credential passing, as these are distinct from the local-inference policy preset objective.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(cli): add local-inference policy preset for Ollama/vLLM host access' clearly and concisely summarizes the primary change: adding a policy preset for local inference access.
Linked Issues check ✅ Passed The PR successfully addresses issue #693 by providing a supported path for local Ollama/vLLM inference via the new local-inference policy preset and auto-suggestion during onboarding.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/local-inference-preset-781

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/nemoclaw.js`:
- Around line 650-653: Remove the unnecessary credential prompting and secret
export around the Spark setup: delete the call to ensureApiKey() and stop
injecting NVIDIA_API_KEY into the sudo run of setup-spark.sh; update the run
invocation that calls `run(\`sudo -E bash "\${SCRIPTS}/setup-spark.sh"\`, { env:
{ NVIDIA_API_KEY: process.env.NVIDIA_API_KEY } })` to a plain invocation without
the env property (or with only required non-secret env vars), so
`setup-spark.sh` is executed without prompting for or passing the NVIDIA_API_KEY
secret; target the ensureApiKey() call and the run(...) invocation in
bin/nemoclaw.js that reference SCRIPTS, setup-spark.sh, and NVIDIA_API_KEY.

In `@scripts/walkthrough.sh`:
- Around line 87-90: The tmux usage in scripts/walkthrough.sh currently expands
the secret into the shell argv via -e "NVIDIA_API_KEY=$NVIDIA_API_KEY", which
can leak via process inspection; instead, set the secret into the tmux
server/session environment (use tmux set-environment -t "$SESSION"
NVIDIA_API_KEY "$NVIDIA_API_KEY") and then call tmux split-window with -e
NVIDIA_API_KEY (no shell expansion) so the value is supplied by tmux internally;
after the split, remove the secret from the tmux environment (unset-environment)
to avoid lingering secrets. Ensure you update the tmux command that creates the
right pane (the split-window invocation) and add the set-environment and
unset-environment steps around it.

In `@test/runner.test.js`:
- Around line 511-514: The test's guard currently allows argv-based secret
exposure by accepting patterns like tmux -e "NVIDIA_API_KEY=..." — change the
credential-exposure checks in test/runner.test.js to reject environment
assignments passed as command-line arguments (e.g., any argv token matching
/[A-Z0-9_]+=.+/ or the specific pattern tmux -e "<KEY>=<VALUE>") rather than
whitelisting them; update the validation logic used in the credential-exposure
test (the block that comments about `tmux -e "NVIDIA_API_KEY=..."`) so it treats
such -e "KEY=..." usages as failures and add the same check for the other
occurrence mentioned (around lines 524-527).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eb151673-5688-47b7-a3ae-a4c3b0c4314b

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4d6fe and ea6b1bc.

📒 Files selected for processing (8)
  • bin/lib/onboard.js
  • bin/nemoclaw.js
  • nemoclaw-blueprint/policies/presets/local-inference.yaml
  • scripts/install.sh
  • scripts/telegram-bridge.js
  • scripts/walkthrough.sh
  • test/policies.test.js
  • test/runner.test.js

Comment on lines +87 to 90
# Split right pane for the agent — pass NVIDIA_API_KEY via tmux -e so it
# reaches the sandbox environment without being embedded in the command string.
tmux split-window -h -t "$SESSION" -e "NVIDIA_API_KEY=$NVIDIA_API_KEY" \
"openshell sandbox connect nemoclaw -- bash -c 'nemoclaw-start openclaw agent --agent main --local --session-id live'"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid placing NVIDIA_API_KEY in tmux command arguments.

Line 89 expands the secret into argv (KEY=value), which can leak via process inspection.

Proposed fix
-# Split right pane for the agent — pass NVIDIA_API_KEY via tmux -e so it
-# reaches the sandbox environment without being embedded in the command string.
-tmux split-window -h -t "$SESSION" -e "NVIDIA_API_KEY=$NVIDIA_API_KEY" \
+# Split right pane for the agent. Inherit NVIDIA_API_KEY from the script
+# environment instead of embedding KEY=value in argv.
+tmux split-window -h -t "$SESSION" \
   "openshell sandbox connect nemoclaw -- bash -c 'nemoclaw-start openclaw agent --agent main --local --session-id live'"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/walkthrough.sh` around lines 87 - 90, The tmux usage in
scripts/walkthrough.sh currently expands the secret into the shell argv via -e
"NVIDIA_API_KEY=$NVIDIA_API_KEY", which can leak via process inspection;
instead, set the secret into the tmux server/session environment (use tmux
set-environment -t "$SESSION" NVIDIA_API_KEY "$NVIDIA_API_KEY") and then call
tmux split-window with -e NVIDIA_API_KEY (no shell expansion) so the value is
supplied by tmux internally; after the split, remove the secret from the tmux
environment (unset-environment) to avoid lingering secrets. Ensure you update
the tmux command that creates the right pane (the split-window invocation) and
add the set-environment and unset-environment steps around it.

Comment on lines +511 to +514
// Check only executable lines (tmux spawn, openshell connect) — not comments/docs.
// The safe `tmux -e "NVIDIA_API_KEY=..."` pattern is allowed because it
// passes the key through the environment rather than embedding it in the
// shell command that runs inside the sandbox.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

This guard now whitelists argv-based secret exposure.

Allowing -e "NVIDIA_API_KEY=..." weakens the credential-exposure test by permitting the raw key in executable command arguments.

Proposed fix
-      // Check only executable lines (tmux spawn, openshell connect) — not comments/docs.
-      // The safe `tmux -e "NVIDIA_API_KEY=..."` pattern is allowed because it
-      // passes the key through the environment rather than embedding it in the
-      // shell command that runs inside the sandbox.
+      // Check only executable lines (tmux spawn, openshell connect) — not comments/docs.
+      // NVIDIA_API_KEY must not appear in executable command text.
       const cmdLines = src
         .split("\n")
         .filter(
@@
       for (const line of cmdLines) {
-        if (line.includes("NVIDIA_API_KEY")) {
-          // Only the tmux -e env-passing pattern is acceptable
-          expect(line).toMatch(/-e\s+"NVIDIA_API_KEY=/);
-        }
+        expect(line.includes("NVIDIA_API_KEY")).toBe(false);
       }

Also applies to: 524-527

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/runner.test.js` around lines 511 - 514, The test's guard currently
allows argv-based secret exposure by accepting patterns like tmux -e
"NVIDIA_API_KEY=..." — change the credential-exposure checks in
test/runner.test.js to reject environment assignments passed as command-line
arguments (e.g., any argv token matching /[A-Z0-9_]+=.+/ or the specific pattern
tmux -e "<KEY>=<VALUE>") rather than whitelisting them; update the validation
logic used in the credential-exposure test (the block that comments about `tmux
-e "NVIDIA_API_KEY=..."`) so it treats such -e "KEY=..." usages as failures and
add the same check for the other occurrence mentioned (around lines 524-527).

cv and others added 2 commits April 3, 2026 21:08
Keep both provider (ours) and webSearchConfig (main) options in
setupPoliciesWithSelection. Update preset count 10→11 to account
for the brave preset added on main.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wscurran wscurran added security Something isn't secure Local Models Running NemoClaw with local models priority: high Important issue that should be resolved in the next release NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. fix labels Apr 4, 2026
cv and others added 2 commits April 4, 2026 10:19
- onboard.js: keep provider param for local-inference, use main's step count
- nemoclaw.js: take main's deprecated setupSpark (addresses CodeRabbit finding)
- telegram-bridge.js: accept deletion from main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
test/runner.test.js (1)

498-514: ⚠️ Potential issue | 🟠 Major

Credential-exposure guard still whitelists argv secret leakage

Line 511–Line 514 allow tmux -e "NVIDIA_API_KEY=...", which still places the secret in executable command arguments and weakens this regression guard.

Proposed fix
-      // Check only executable lines (tmux spawn, openshell connect) — not comments/docs.
-      // The safe `tmux -e "NVIDIA_API_KEY=..."` pattern is allowed because it
-      // passes the key through the environment rather than embedding it in the
-      // shell command that runs inside the sandbox.
+      // Check only executable lines (tmux spawn, openshell connect) — not comments/docs.
+      // NVIDIA_API_KEY must not appear in executable command text.
       const cmdLines = src
         .split("\n")
         .filter(
@@
       for (const line of cmdLines) {
-        if (line.includes("NVIDIA_API_KEY")) {
-          // Only the tmux -e env-passing pattern is acceptable
-          expect(line).toMatch(/-e\s+"NVIDIA_API_KEY=/);
-        }
+        expect(line.includes("NVIDIA_API_KEY")).toBe(false);
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/runner.test.js` around lines 498 - 514, The current test whitelists tmux
-e "NVIDIA_API_KEY=..." which still exposes secrets via command argv; update the
check in the cmdLines loop so any appearance of "NVIDIA_API_KEY" in an
executable line fails instead of being allowed — e.g. replace the permissive
expect(/-e\s+"NVIDIA_API_KEY=/) with an assertion that the line does not contain
the literal "NVIDIA_API_KEY" (use expect(line).not.toMatch(/NVIDIA_API_KEY/)) so
cmdLines and the src filtering logic reject any command-line embedding of the
key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@test/runner.test.js`:
- Around line 498-514: The current test whitelists tmux -e "NVIDIA_API_KEY=..."
which still exposes secrets via command argv; update the check in the cmdLines
loop so any appearance of "NVIDIA_API_KEY" in an executable line fails instead
of being allowed — e.g. replace the permissive expect(/-e\s+"NVIDIA_API_KEY=/)
with an assertion that the line does not contain the literal "NVIDIA_API_KEY"
(use expect(line).not.toMatch(/NVIDIA_API_KEY/)) so cmdLines and the src
filtering logic reject any command-line embedding of the key.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 398c99ec-00c0-4a0d-a1c8-92269015429b

📥 Commits

Reviewing files that changed from the base of the PR and between 944a4fc and b2d5292.

📒 Files selected for processing (4)
  • bin/lib/onboard.js
  • scripts/install.sh
  • test/policies.test.js
  • test/runner.test.js
✅ Files skipped from review due to trivial changes (2)
  • test/policies.test.js
  • bin/lib/onboard.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/install.sh

@cv cv requested a review from ericksoa April 9, 2026 00:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. fix Local Models Running NemoClaw with local models NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). priority: high Important issue that should be resolved in the next release security Something isn't secure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local Ollama inference blocked by OpenShell egress proxy — RFC1918 addresses return 403 regardless of policy

3 participants