enable servers in sandbox to listen on localhost (127.0.0.1) instead of 0.0.0.0, ensuring servers can be container/host-agnostic (#207)

* enable servers in sandbox to listen on localhost (127.0.0.1) instead of 0.0.0.0, ensuring servers can be container/host-agnostic

* Merge remote-tracking branch 'origin/main' into sandbox_localhost_works
This commit is contained in:
Olcan 2025-04-28 18:40:24 -07:00 committed by GitHub
parent 3073c67861
commit 0d849bf58e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 29 additions and 5 deletions

View File

@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
procps \ procps \
psmisc \ psmisc \
lsof \ lsof \
socat \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*

View File

@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
procps \ procps \
psmisc \ psmisc \
lsof \ lsof \
socat \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*

10
package-lock.json generated
View File

@ -1149,6 +1149,13 @@
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/@types/shell-quote": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/@types/shell-quote/-/shell-quote-1.7.5.tgz",
"integrity": "sha512-+UE8GAGRPbJVQDdxi16dgadcBfQ+KG2vgZhV1+3A1XmHbmwcdwhCUwIdy+d3pAGrbvgRoVSjeI9vOWyq376Yzw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/tinycolor2": { "node_modules/@types/tinycolor2": {
"version": "1.4.6", "version": "1.4.6",
"resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz", "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz",
@ -5534,7 +5541,6 @@
"version": "1.8.2", "version": "1.8.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
"integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
"devOptional": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -6850,6 +6856,7 @@
"lowlight": "^3.3.0", "lowlight": "^3.3.0",
"react": "^18.3.1", "react": "^18.3.1",
"read-package-up": "^11.0.0", "read-package-up": "^11.0.0",
"shell-quote": "^1.8.2",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"bin": { "bin": {
@ -6861,6 +6868,7 @@
"@types/dotenv": "^6.1.1", "@types/dotenv": "^6.1.1",
"@types/node": "^20.11.24", "@types/node": "^20.11.24",
"@types/react": "^19.1.0", "@types/react": "^19.1.0",
"@types/shell-quote": "^1.7.5",
"@types/yargs": "^17.0.32", "@types/yargs": "^17.0.32",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vitest": "^3.1.1" "vitest": "^3.1.1"

View File

@ -42,6 +42,7 @@
"lowlight": "^3.3.0", "lowlight": "^3.3.0",
"react": "^18.3.1", "react": "^18.3.1",
"read-package-up": "^11.0.0", "read-package-up": "^11.0.0",
"shell-quote": "^1.8.2",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"devDependencies": { "devDependencies": {
@ -49,6 +50,7 @@
"@types/dotenv": "^6.1.1", "@types/dotenv": "^6.1.1",
"@types/node": "^20.11.24", "@types/node": "^20.11.24",
"@types/react": "^19.1.0", "@types/react": "^19.1.0",
"@types/shell-quote": "^1.7.5",
"@types/yargs": "^17.0.32", "@types/yargs": "^17.0.32",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vitest": "^3.1.1" "vitest": "^3.1.1"

View File

@ -8,6 +8,7 @@ import os from 'os';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import React from 'react'; import React from 'react';
import { quote } from 'shell-quote';
import { render } from 'ink'; import { render } from 'ink';
import { App } from './ui/App.js'; import { App } from './ui/App.js';
import { loadCliConfig } from './config/config.js'; import { loadCliConfig } from './config/config.js';
@ -204,17 +205,24 @@ async function start_sandbox(sandbox: string) {
} }
// open additional ports if SANDBOX_PORTS is set // open additional ports if SANDBOX_PORTS is set
// also set up redirects (via socat) so servers can listen on localhost instead of 0.0.0.0
let bash_cmd = '';
if (process.env.SANDBOX_PORTS) { if (process.env.SANDBOX_PORTS) {
for (let port of process.env.SANDBOX_PORTS.split(',')) { for (let port of process.env.SANDBOX_PORTS.split(',')) {
if ((port = port.trim())) { if ((port = port.trim())) {
console.log(`SANDBOX_PORTS: ${port}`); console.log(`SANDBOX_PORTS: ${port}`);
args.push('-p', `${port}:${port}`); args.push('-p', `${port}:${port}`);
bash_cmd += `socat TCP4-LISTEN:${port},bind=$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:${port} 2> /dev/null & `;
} }
} }
} }
// append remaining args (image, node, node args, cli path, cli args) // append remaining args (image, bash -c "node node_args... cli path cli_args...")
args.push(image, 'node', ...nodeArgs, cliPath, ...process.argv.slice(2)); // node_args and cli_args need to be quoted before being inserted into bash_cmd
const quotedNodeArgs = nodeArgs.map((arg) => quote([arg]));
const quotedCliArgs = process.argv.slice(2).map((arg) => quote([arg]));
bash_cmd += `node ${quotedNodeArgs.join(' ')} ${quote([cliPath])} ${quotedCliArgs.join(' ')}`;
args.push(image, 'bash', '-c', bash_cmd);
// spawn child and let it inherit stdio // spawn child and let it inherit stdio
const child = spawn(sandbox, args, { const child = spawn(sandbox, args, {

View File

@ -135,20 +135,24 @@ fi
node_args+=("$CLI_PATH" "$@") node_args+=("$CLI_PATH" "$@")
# open additional ports if SANDBOX_PORTS is set # open additional ports if SANDBOX_PORTS is set
# also set up redirects (via socat) so servers can listen on localhost instead of 0.0.0.0
bash_cmd=""
if [ -n "${SANDBOX_PORTS:-}" ]; then if [ -n "${SANDBOX_PORTS:-}" ]; then
ports=$(echo "$SANDBOX_PORTS" | tr ',' '\n') ports=$(echo "$SANDBOX_PORTS" | tr ',' '\n')
for port in $ports; do for port in $ports; do
if [ -n "$port" ]; then if [ -n "$port" ]; then
echo "SANDBOX_PORTS: $port" echo "SANDBOX_PORTS: $port"
run_args+=(-p "$port:$port") run_args+=(-p "$port:$port")
bash_cmd+="socat TCP4-LISTEN:$port,bind=\$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:$port 2> /dev/null& "
fi fi
done done
fi fi
bash_cmd+="node $(printf '%q ' "${node_args[@]}")" # printf fixes quoting within args
# run gemini-code in sandbox container # run gemini-code in sandbox container
if [[ "$CMD" == "podman" ]]; then if [[ "$CMD" == "podman" ]]; then
# use empty --authfile to skip unnecessary auth refresh overhead # use empty --authfile to skip unnecessary auth refresh overhead
$CMD run "${run_args[@]}" --authfile <(echo '{}') "$IMAGE" node "${node_args[@]}" $CMD run "${run_args[@]}" --authfile <(echo '{}') "$IMAGE" bash -c "$bash_cmd"
else else
$CMD run "${run_args[@]}" "$IMAGE" node "${node_args[@]}" $CMD run "${run_args[@]}" "$IMAGE" bash -c "$bash_cmd"
fi fi