Skip to content

Fix #166: Quote sandbox names in shell commands#335

Open
hkc5 wants to merge 2 commits intoNVIDIA:mainfrom
hkc5:fix-sandbox-name-quoting
Open

Fix #166: Quote sandbox names in shell commands#335
hkc5 wants to merge 2 commits intoNVIDIA:mainfrom
hkc5:fix-sandbox-name-quoting

Conversation

@hkc5
Copy link

@hkc5 hkc5 commented Mar 18, 2026

Summary

  • Add shellEscape() helper function that wraps strings in single quotes and safely handles embedded single quotes (replacing the previous "${sandboxName}" double-quote interpolation)
  • Apply shellEscape() to all three shell commands that use sandboxName:
    • openshell sandbox delete
    • openshell sandbox create --name
    • openshell forward start

This is a re-submission of the quoting fix originally in PR #211, which was accidentally opened with main as both the head and base branch. Only the quoting/escaping changes are included here — the lowercase normalization changes are tracked separately in PR #212.

Test plan

  • Onboard with a normal sandbox name (e.g. my-assistant) — should work as before
  • Verify shellEscape() correctly handles names containing single quotes (e.g. it's) — should produce 'it'"'"'s'
  • Verify the three shell invocations (sandbox delete, sandbox create --name, forward start) all use the escaped name

Summary by CodeRabbit

  • Bug Fixes
    • Improved safety of sandbox operations (creation, deletion, and port forwarding) so sandbox names containing special or shell-sensitive characters no longer cause command failures.
    • Increased reliability of sandbox lifecycle actions without changing public interfaces or behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 04f5163d-0741-440a-8431-fabc2e6f3be2

📥 Commits

Reviewing files that changed from the base of the PR and between fd3b4a3 and 09afb41.

📒 Files selected for processing (1)
  • bin/lib/onboard.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • bin/lib/onboard.js

📝 Walkthrough

Walkthrough

The command constructions in createSandbox() were modified to shell-escape sandboxName when passed to openshell CLI commands by wrapping it with shellQuote(...) for deletion, creation (--name), and dashboard port-forwarding.

Changes

Cohort / File(s) Summary
Shell quoting in CLI invocations
bin/lib/onboard.js
Replaced direct double-quoted interpolation of sandboxName with shellQuote(sandboxName) for openshell sandbox delete, sandbox creation (--name), and openshell forward start --background commands.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hop through scripts with a careful quote,
Nestling names safe so they stay afloat.
Sandboxes guarded from shells that pry,
One snug quote keeps mischief shy. 🥕

🚥 Pre-merge checks | ✅ 3
✅ 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 directly and accurately reflects the main change: implementing proper shell quoting for sandbox names in three shell commands to fix issue #166.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Tip

CodeRabbit can approve the review once all CodeRabbit's comments are resolved.

Enable the reviews.request_changes_workflow setting to automatically approve the review once all CodeRabbit's comments are resolved.

Fixes NVIDIA#166

- Add shellEscape() function to properly escape sandbox names in shell
  commands by wrapping in single quotes and handling embedded single
  quotes correctly
- Apply shell escaping to all shell commands that use sandboxName:
  - openshell sandbox delete
  - openshell sandbox create --name
  - openshell forward start

This replaces the previous double-quoted interpolation ("${sandboxName}")
with shellEscape(), which is more robust and prevents shell injection when
sandbox names contain special characters.
@hkc5 hkc5 force-pushed the fix-sandbox-name-quoting branch from bf84ea6 to fd3b4a3 Compare March 20, 2026 08:45
Copy link
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.

🧹 Nitpick comments (2)
bin/lib/onboard.js (2)

60-71: Duplicate shell-escaping helper exists.

A similar function shellQuote() already exists at lines 101-103 using the '\'' escape pattern. Both patterns are valid POSIX techniques, but having two functions for the same purpose violates DRY. Consider consolidating into a single helper.

♻️ Suggested consolidation

Either rename and reuse the existing shellQuote() for all shell-escaping needs, or replace it with this new shellEscape():

-function shellQuote(value) {
-  return `'${String(value).replace(/'/g, `'\\''`)}'`;
-}
+// Reuse shellEscape for all shell quoting needs
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/lib/onboard.js` around lines 60 - 71, There are two duplicate helpers
(shellEscape and shellQuote); remove the duplication by consolidating to a
single helper and updating call sites: choose one name (prefer keep shellQuote
or rename shellEscape) and delete the other function, then replace all
references to the removed function with the retained function (ensure the
retained implementation uses a POSIX-safe pattern such as replacing ' with '\''
or equivalent used in shellQuote/shellEscape). Update any module exports or
imports in this file to reference only the chosen function (shellEscape or
shellQuote) so all usages call the single consolidated helper.

454-454: Shell escaping applied correctly to these call sites.

The use of shellEscape(sandboxName) at sandbox delete (line 454), create --name (line 473), and forward start (line 541) is consistent with the PR objectives.

However, other sandboxName usages in this file still use double-quoted interpolation without escaping:

  • Line 237: openshell sandbox get "${sandboxName}"
  • Line 523: openshell sandbox delete "${sandboxName}"
  • Line 816: openshell sandbox connect "${sandboxName}"

While the sandbox name validation at line 429 restricts input to [a-z0-9-] (making injection impossible), the inconsistent escaping pattern is a code smell. Consider applying shellEscape() uniformly for maintainability and defense-in-depth.

♻️ Apply shellEscape consistently
-    const exists = runCapture(`openshell sandbox get "${sandboxName}" 2>/dev/null`, { ignoreError: true });
+    const exists = runCapture(`openshell sandbox get ${shellEscape(sandboxName)} 2>/dev/null`, { ignoreError: true });
-    const delResult = run(`openshell sandbox delete "${sandboxName}" 2>/dev/null || true`, { ignoreError: true });
+    const delResult = run(`openshell sandbox delete ${shellEscape(sandboxName)} 2>/dev/null || true`, { ignoreError: true });
-    run(`cat <<'EOF_NEMOCLAW_SYNC' | openshell sandbox connect "${sandboxName}"
+    run(`cat <<'EOF_NEMOCLAW_SYNC' | openshell sandbox connect ${shellEscape(sandboxName)}

Also applies to: 473-473, 541-541

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

In `@bin/lib/onboard.js` at line 454, Replace the remaining double-quoted
interpolations of sandboxName with shellEscape(sandboxName) to make escaping
consistent and defense-in-depth; specifically update any calls that build shell
commands with sandboxName (e.g., run("openshell sandbox get
\"${sandboxName}\""), run("openshell sandbox delete \"${sandboxName}\""), and
run("openshell sandbox connect \"${sandboxName}\"")) to use
shellEscape(sandboxName) instead, keeping the same command text (openshell
sandbox get/delete/connect and the --name option) and reusing the existing
shellEscape helper and run function so all run(...) invocations embed the
escaped sandboxName variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bin/lib/onboard.js`:
- Around line 60-71: There are two duplicate helpers (shellEscape and
shellQuote); remove the duplication by consolidating to a single helper and
updating call sites: choose one name (prefer keep shellQuote or rename
shellEscape) and delete the other function, then replace all references to the
removed function with the retained function (ensure the retained implementation
uses a POSIX-safe pattern such as replacing ' with '\'' or equivalent used in
shellQuote/shellEscape). Update any module exports or imports in this file to
reference only the chosen function (shellEscape or shellQuote) so all usages
call the single consolidated helper.
- Line 454: Replace the remaining double-quoted interpolations of sandboxName
with shellEscape(sandboxName) to make escaping consistent and defense-in-depth;
specifically update any calls that build shell commands with sandboxName (e.g.,
run("openshell sandbox get \"${sandboxName}\""), run("openshell sandbox delete
\"${sandboxName}\""), and run("openshell sandbox connect \"${sandboxName}\""))
to use shellEscape(sandboxName) instead, keeping the same command text
(openshell sandbox get/delete/connect and the --name option) and reusing the
existing shellEscape helper and run function so all run(...) invocations embed
the escaped sandboxName variable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9453f3e3-9d85-4b90-bccc-de3a8f1279b2

📥 Commits

Reviewing files that changed from the base of the PR and between bf84ea6 and fd3b4a3.

📒 Files selected for processing (1)
  • bin/lib/onboard.js

Removes the newly added shellEscape() function which duplicated the
pre-existing shellQuote() helper. All call sites updated to use shellQuote().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants