diff --git a/packages/cli/src/gemini.ts b/packages/cli/src/gemini.ts index 2cecbedb..29d2b1b7 100644 --- a/packages/cli/src/gemini.ts +++ b/packages/cli/src/gemini.ts @@ -101,10 +101,10 @@ async function start_sandbox(sandbox: string) { const args = ['run', '-it', '--rm', '--init', '--workdir', workdir]; // mount current directory as ${workdir} inside container - args.push('-v', `${process.cwd()}:${workdir}`); + args.push('--volume', `${process.cwd()}:${workdir}`); // mount os.tmpdir() as /tmp inside container - args.push('-v', `${os.tmpdir()}:/tmp`); + args.push('--volume', `${os.tmpdir()}:/tmp`); // mount paths listed in SANDBOX_MOUNTS if (process.env.SANDBOX_MOUNTS) { @@ -130,7 +130,7 @@ async function start_sandbox(sandbox: string) { process.exit(1); } console.log(`SANDBOX_MOUNTS: ${from} -> ${to} (${opts})`); - args.push('-v', mount); + args.push('--volume', mount); } } } @@ -200,29 +200,38 @@ async function start_sandbox(sandbox: string) { const nodeArgs = []; const debugPort = process.env.DEBUG_PORT || '9229'; if (process.env.DEBUG) { - args.push('-p', `${debugPort}:${debugPort}`); + args.push('--publish', `${debugPort}:${debugPort}`); nodeArgs.push(`--inspect-brk=0.0.0.0:${debugPort}`); } // 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 = ''; + let bashCmd = ''; if (process.env.SANDBOX_PORTS) { for (let port of process.env.SANDBOX_PORTS.split(',')) { if ((port = port.trim())) { console.log(`SANDBOX_PORTS: ${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 & `; + args.push('--publish', `${port}:${port}`); + bashCmd += `socat TCP4-LISTEN:${port},bind=$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:${port} 2> /dev/null & `; } } } + // specify --user as "$(id -u):$(id -g)" if SANDBOX_SET_UID_GID is 1|true + // only necessary if user mapping is not handled by sandboxing setup on host + // (e.g. rootful docker on linux w/o userns-remap configured) + if (['1', 'true'].includes(process.env.SANDBOX_SET_UID_GID ?? '')) { + const uid = execSync('id -u').toString().trim(); + const gid = execSync('id -g').toString().trim(); + args.push('--user', `${uid}:${gid}`); + } + // append remaining args (image, bash -c "node node_args... cli path cli_args...") // 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); + bashCmd += `node ${quotedNodeArgs.join(' ')} ${quote([cliPath])} ${quotedCliArgs.join(' ')}`; + args.push(image, 'bash', '-c', bashCmd); // spawn child and let it inherit stdio const child = spawn(sandbox, args, { diff --git a/scripts/sandbox_command.sh b/scripts/sandbox_command.sh index 03163458..fab94b52 100755 --- a/scripts/sandbox_command.sh +++ b/scripts/sandbox_command.sh @@ -22,15 +22,15 @@ set -euo pipefail QUIET=false while getopts ":q" opt; do case ${opt} in - q ) QUIET=true ;; - \? ) echo "Usage: $0 [-q]" - exit 1 - ;; + q) QUIET=true ;; + \?) + echo "Usage: $0 [-q]" + exit 1 + ;; esac done shift $((OPTIND - 1)) - # if GEMINI_CODE_SANDBOX is not set, try to source .env in case set there # allow .env to be in any ancestor directory (same as findEnvFile in config.ts) if [ -z "${GEMINI_CODE_SANDBOX:-}" ]; then @@ -57,10 +57,10 @@ fi # if GEMINI_CODE_SANDBOX is set to 1 or true, then try to use docker or podman if [[ "${GEMINI_CODE_SANDBOX:-}" =~ ^(1|true)$ ]]; then - if command -v docker &> /dev/null; then + if command -v docker &>/dev/null; then if [ "$QUIET" = false ]; then echo "docker"; fi exit 0 - elif command -v podman &> /dev/null; then + elif command -v podman &>/dev/null; then if [ "$QUIET" = false ]; then echo "podman"; fi exit 0 else @@ -69,7 +69,7 @@ if [[ "${GEMINI_CODE_SANDBOX:-}" =~ ^(1|true)$ ]]; then fi fi -if ! command -v "$GEMINI_CODE_SANDBOX" &> /dev/null; then +if ! command -v "$GEMINI_CODE_SANDBOX" &>/dev/null; then echo "ERROR: missing sandbox command '$GEMINI_CODE_SANDBOX' (from GEMINI_CODE_SANDBOX)" >&2 exit 1 fi diff --git a/scripts/start.sh b/scripts/start.sh index b6b94085..c979205e 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -30,4 +30,4 @@ else else CLI_VERSION='development' DEV=true node ./packages/cli "$@" fi -fi \ No newline at end of file +fi diff --git a/scripts/start_sandbox.sh b/scripts/start_sandbox.sh index 444efbd3..b857d496 100755 --- a/scripts/start_sandbox.sh +++ b/scripts/start_sandbox.sh @@ -44,10 +44,10 @@ fi run_args=(-it --rm --init --workdir "$WORKDIR") # mount current directory as $WORKDIR inside container -run_args+=(-v "$PWD:$WORKDIR") +run_args+=(--volume "$PWD:$WORKDIR") # mount $TMPDIR as /tmp inside container -run_args+=(-v "${TMPDIR:-/tmp/}:/tmp") +run_args+=(--volume "${TMPDIR:-/tmp/}:/tmp") # if .env exists, source it before checking/parsing environment variables below # allow .env to be in any ancestor directory (same as findEnvFile in config.ts) @@ -81,7 +81,7 @@ if [ -n "${SANDBOX_MOUNTS:-}" ]; then exit 1 fi echo "SANDBOX_MOUNTS: $from -> $to ($opts)" - run_args+=(-v "$mount") + run_args+=(--volume "$mount") fi done fi @@ -130,7 +130,7 @@ run_args+=(--env "SANDBOX=$IMAGE-$INDEX") node_args=() if [ -n "${DEBUG:-}" ]; then node_args+=(--inspect-brk="0.0.0.0:$DEBUG_PORT") - run_args+=(-p "$DEBUG_PORT:$DEBUG_PORT") + run_args+=(--publish "$DEBUG_PORT:$DEBUG_PORT") fi node_args+=("$CLI_PATH" "$@") @@ -142,13 +142,20 @@ if [ -n "${SANDBOX_PORTS:-}" ]; then for port in $ports; do if [ -n "$port" ]; then echo "SANDBOX_PORTS: $port" - run_args+=(-p "$port:$port") + run_args+=(--publish "$port:$port") bash_cmd+="socat TCP4-LISTEN:$port,bind=\$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:$port 2> /dev/null& " fi done fi bash_cmd+="node $(printf '%q ' "${node_args[@]}")" # printf fixes quoting within args +# specify --user as "$(id -u):$(id -g)" if SANDBOX_SET_UID_GID is 1|true +# only necessary if user mapping is not handled by sandboxing setup on host +# (e.g. rootful docker on linux w/o userns-remap configured) +if [[ "${SANDBOX_SET_UID_GID:-}" =~ ^(1|true)$ ]]; then + run_args+=(--user "$(id -u):$(id -g)") +fi + # run gemini-code in sandbox container if [[ "$CMD" == "podman" ]]; then # use empty --authfile to skip unnecessary auth refresh overhead