SANDBOX_SET_UID_GID option for systems where this is necessary (should be only rootful docker on linux w/o userns-remap configured) (#210)
* SANDBOX_SET_UID_GID option for systems where this is necessary (should be only rootful docker on linux w/o userns-remap configured) * Merge remote-tracking branch 'origin/main' into sandbox_uid_gid
This commit is contained in:
parent
e0de69f384
commit
825cecc089
|
@ -101,10 +101,10 @@ async function start_sandbox(sandbox: string) {
|
||||||
const args = ['run', '-it', '--rm', '--init', '--workdir', workdir];
|
const args = ['run', '-it', '--rm', '--init', '--workdir', workdir];
|
||||||
|
|
||||||
// mount current directory as ${workdir} inside container
|
// 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
|
// 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
|
// mount paths listed in SANDBOX_MOUNTS
|
||||||
if (process.env.SANDBOX_MOUNTS) {
|
if (process.env.SANDBOX_MOUNTS) {
|
||||||
|
@ -130,7 +130,7 @@ async function start_sandbox(sandbox: string) {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
console.log(`SANDBOX_MOUNTS: ${from} -> ${to} (${opts})`);
|
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 nodeArgs = [];
|
||||||
const debugPort = process.env.DEBUG_PORT || '9229';
|
const debugPort = process.env.DEBUG_PORT || '9229';
|
||||||
if (process.env.DEBUG) {
|
if (process.env.DEBUG) {
|
||||||
args.push('-p', `${debugPort}:${debugPort}`);
|
args.push('--publish', `${debugPort}:${debugPort}`);
|
||||||
nodeArgs.push(`--inspect-brk=0.0.0.0:${debugPort}`);
|
nodeArgs.push(`--inspect-brk=0.0.0.0:${debugPort}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// 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) {
|
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('--publish', `${port}:${port}`);
|
||||||
bash_cmd += `socat TCP4-LISTEN:${port},bind=$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:${port} 2> /dev/null & `;
|
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...")
|
// 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
|
// node_args and cli_args need to be quoted before being inserted into bash_cmd
|
||||||
const quotedNodeArgs = nodeArgs.map((arg) => quote([arg]));
|
const quotedNodeArgs = nodeArgs.map((arg) => quote([arg]));
|
||||||
const quotedCliArgs = process.argv.slice(2).map((arg) => quote([arg]));
|
const quotedCliArgs = process.argv.slice(2).map((arg) => quote([arg]));
|
||||||
bash_cmd += `node ${quotedNodeArgs.join(' ')} ${quote([cliPath])} ${quotedCliArgs.join(' ')}`;
|
bashCmd += `node ${quotedNodeArgs.join(' ')} ${quote([cliPath])} ${quotedCliArgs.join(' ')}`;
|
||||||
args.push(image, 'bash', '-c', bash_cmd);
|
args.push(image, 'bash', '-c', bashCmd);
|
||||||
|
|
||||||
// spawn child and let it inherit stdio
|
// spawn child and let it inherit stdio
|
||||||
const child = spawn(sandbox, args, {
|
const child = spawn(sandbox, args, {
|
||||||
|
|
|
@ -22,15 +22,15 @@ set -euo pipefail
|
||||||
QUIET=false
|
QUIET=false
|
||||||
while getopts ":q" opt; do
|
while getopts ":q" opt; do
|
||||||
case ${opt} in
|
case ${opt} in
|
||||||
q ) QUIET=true ;;
|
q) QUIET=true ;;
|
||||||
\? ) echo "Usage: $0 [-q]"
|
\?)
|
||||||
exit 1
|
echo "Usage: $0 [-q]"
|
||||||
;;
|
exit 1
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
shift $((OPTIND - 1))
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
|
||||||
# if GEMINI_CODE_SANDBOX is not set, try to source .env in case set there
|
# 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)
|
# allow .env to be in any ancestor directory (same as findEnvFile in config.ts)
|
||||||
if [ -z "${GEMINI_CODE_SANDBOX:-}" ]; then
|
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 is set to 1 or true, then try to use docker or podman
|
||||||
if [[ "${GEMINI_CODE_SANDBOX:-}" =~ ^(1|true)$ ]]; then
|
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
|
if [ "$QUIET" = false ]; then echo "docker"; fi
|
||||||
exit 0
|
exit 0
|
||||||
elif command -v podman &> /dev/null; then
|
elif command -v podman &>/dev/null; then
|
||||||
if [ "$QUIET" = false ]; then echo "podman"; fi
|
if [ "$QUIET" = false ]; then echo "podman"; fi
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
|
@ -69,7 +69,7 @@ if [[ "${GEMINI_CODE_SANDBOX:-}" =~ ^(1|true)$ ]]; then
|
||||||
fi
|
fi
|
||||||
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
|
echo "ERROR: missing sandbox command '$GEMINI_CODE_SANDBOX' (from GEMINI_CODE_SANDBOX)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -30,4 +30,4 @@ else
|
||||||
else
|
else
|
||||||
CLI_VERSION='development' DEV=true node ./packages/cli "$@"
|
CLI_VERSION='development' DEV=true node ./packages/cli "$@"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -44,10 +44,10 @@ fi
|
||||||
run_args=(-it --rm --init --workdir "$WORKDIR")
|
run_args=(-it --rm --init --workdir "$WORKDIR")
|
||||||
|
|
||||||
# mount current directory as $WORKDIR inside container
|
# mount current directory as $WORKDIR inside container
|
||||||
run_args+=(-v "$PWD:$WORKDIR")
|
run_args+=(--volume "$PWD:$WORKDIR")
|
||||||
|
|
||||||
# mount $TMPDIR as /tmp inside container
|
# 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
|
# 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)
|
# 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
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "SANDBOX_MOUNTS: $from -> $to ($opts)"
|
echo "SANDBOX_MOUNTS: $from -> $to ($opts)"
|
||||||
run_args+=(-v "$mount")
|
run_args+=(--volume "$mount")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
@ -130,7 +130,7 @@ run_args+=(--env "SANDBOX=$IMAGE-$INDEX")
|
||||||
node_args=()
|
node_args=()
|
||||||
if [ -n "${DEBUG:-}" ]; then
|
if [ -n "${DEBUG:-}" ]; then
|
||||||
node_args+=(--inspect-brk="0.0.0.0:$DEBUG_PORT")
|
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
|
fi
|
||||||
node_args+=("$CLI_PATH" "$@")
|
node_args+=("$CLI_PATH" "$@")
|
||||||
|
|
||||||
|
@ -142,13 +142,20 @@ if [ -n "${SANDBOX_PORTS:-}" ]; then
|
||||||
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+=(--publish "$port:$port")
|
||||||
bash_cmd+="socat TCP4-LISTEN:$port,bind=\$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:$port 2> /dev/null& "
|
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
|
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
|
# 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
|
||||||
|
|
Loading…
Reference in New Issue