Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions bin/lib/onboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ async function promptOrDefault(question, envVar, defaultValue) {

// ── Helpers ──────────────────────────────────────────────────────

/**
* Escapes a string for safe use in shell commands.
* Wraps in single quotes and handles embedded single quotes.
*/
function shellEscape(str) {
if (typeof str !== "string") {
throw new Error("shellEscape: expected string argument");
}
// Use single quotes and escape any embedded single quotes
// by ending the quote, adding an escaped quote, and starting a new quote
return "'" + str.replace(/'/g, "'\"'\"'") + "'";
}

/**
* Check if a sandbox is in Ready state from `openshell sandbox list` output.
* Strips ANSI codes and exact-matches the sandbox name in the first column.
Expand Down Expand Up @@ -438,7 +451,7 @@ async function createSandbox(gpu) {
}
}
// Destroy old sandbox
run(`openshell sandbox delete "${sandboxName}" 2>/dev/null || true`, { ignoreError: true });
run(`openshell sandbox delete ${shellEscape(sandboxName)} 2>/dev/null || true`, { ignoreError: true });
registry.removeSandbox(sandboxName);
}

Expand All @@ -457,7 +470,7 @@ async function createSandbox(gpu) {
const basePolicyPath = path.join(ROOT, "nemoclaw-blueprint", "policies", "openclaw-sandbox.yaml");
const createArgs = [
`--from "${buildCtx}/Dockerfile"`,
`--name "${sandboxName}"`,
`--name ${shellEscape(sandboxName)}`,
`--policy "${basePolicyPath}"`,
];
// --gpu is intentionally omitted. See comment in startGateway().
Expand Down Expand Up @@ -525,7 +538,7 @@ async function createSandbox(gpu) {
// which would silently prevent the new sandbox's dashboard from being reachable.
run(`openshell forward stop 18789 2>/dev/null || true`, { ignoreError: true });
// Forward dashboard port to the new sandbox
run(`openshell forward start --background 18789 "${sandboxName}"`, { ignoreError: true });
run(`openshell forward start --background 18789 ${shellEscape(sandboxName)}`, { ignoreError: true });

// Register only after confirmed ready — prevents phantom entries
registry.registerSandbox({
Expand Down