Skip to content
Merged
Changes from all commits
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
44 changes: 40 additions & 4 deletions src/lib/onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,26 @@ async function configureWebSearch(

// getSandboxInferenceConfig — moved to onboard-providers.ts

// Shared validators for NEMOCLAW_PROXY_HOST / NEMOCLAW_PROXY_PORT.
// Both `patchStagedDockerfile()` (build-time Dockerfile ARG override) and
// `createSandbox()` (runtime sandbox env whitelist) must reject the same
// inputs, otherwise the build and runtime paths can diverge — e.g. a
// build-time-accepted value silently no-ops at runtime, leaving the
// container running with the default proxy. Hostname regex deliberately
// excludes `:` so raw IPv6 literals are rejected: the runtime
// `http://${HOST}:${PORT}` template does not bracket them and would
// produce a malformed URL. Port is range-checked because a 5-digit
// length filter alone would accept out-of-range values like 70000.
const PROXY_HOST_RE = /^[A-Za-z0-9._-]+$/;
function isValidProxyHost(value: string): boolean {
return PROXY_HOST_RE.test(value);
}
function isValidProxyPort(value: string): boolean {
if (!/^[0-9]{1,5}$/.test(value)) return false;
const port = Number(value);
return port >= 1 && port <= 65535;
}

function patchStagedDockerfile(
dockerfilePath: string,
model: string,
Expand Down Expand Up @@ -1381,17 +1401,15 @@ function patchStagedDockerfile(
// shell so the sandbox-side nemoclaw-start.sh sees them via $ENV at runtime.
// Without this, the host export is silently dropped at image build time and
// the sandbox falls back to the default 10.200.0.1:3128 proxy. See #1409.
const PROXY_HOST_RE = /^[A-Za-z0-9._:-]+$/;
const PROXY_PORT_RE = /^[0-9]{1,5}$/;
const proxyHostEnv = process.env.NEMOCLAW_PROXY_HOST;
if (proxyHostEnv && PROXY_HOST_RE.test(proxyHostEnv)) {
if (proxyHostEnv && isValidProxyHost(proxyHostEnv)) {
dockerfile = dockerfile.replace(
/^ARG NEMOCLAW_PROXY_HOST=.*$/m,
`ARG NEMOCLAW_PROXY_HOST=${proxyHostEnv}`,
);
}
const proxyPortEnv = process.env.NEMOCLAW_PROXY_PORT;
if (proxyPortEnv && PROXY_PORT_RE.test(proxyPortEnv)) {
if (proxyPortEnv && isValidProxyPort(proxyPortEnv)) {
dockerfile = dockerfile.replace(
/^ARG NEMOCLAW_PROXY_PORT=.*$/m,
`ARG NEMOCLAW_PROXY_PORT=${proxyPortEnv}`,
Expand Down Expand Up @@ -3588,6 +3606,24 @@ async function createSandbox(
// 18789 and the gateway listens on the wrong port. (#2267, #1925)
const effectiveDashboardPort = getDashboardForwardPort(chatUiUrl);
envArgs.push(formatEnvAssignment("NEMOCLAW_DASHBOARD_PORT", effectiveDashboardPort));
// Propagate NEMOCLAW_PROXY_HOST / NEMOCLAW_PROXY_PORT to the runtime
// sandbox container. patchStagedDockerfile() already substitutes them
// into the build-time Dockerfile ARG/ENV, but `openshell sandbox create
// -- env … nemoclaw-start` only forwards the explicitly listed env vars
// — image-baked ENV does not propagate into the running pod. Without
// this, nemoclaw-start.sh:898 falls back to the default 10.200.0.1:3128
// and `HTTPS_PROXY` inside the sandbox ignores the host override. The
// build-time substitution and runtime env stay in sync as a result.
// Fixes #2424. Uses the shared isValidProxyHost / isValidProxyPort
// helpers so build-time and runtime validation stay aligned.
const sandboxProxyHost = process.env.NEMOCLAW_PROXY_HOST;
if (sandboxProxyHost && isValidProxyHost(sandboxProxyHost)) {
envArgs.push(formatEnvAssignment("NEMOCLAW_PROXY_HOST", sandboxProxyHost));
}
const sandboxProxyPort = process.env.NEMOCLAW_PROXY_PORT;
if (sandboxProxyPort && isValidProxyPort(sandboxProxyPort)) {
envArgs.push(formatEnvAssignment("NEMOCLAW_PROXY_PORT", sandboxProxyPort));
}
if (webSearchConfig?.fetchEnabled) {
const braveKey =
getCredential(webSearch.BRAVE_API_KEY_ENV) || process.env[webSearch.BRAVE_API_KEY_ENV];
Expand Down
Loading