diff options
| author | Eddie Santos <[email protected]> | 2025-06-19 14:40:10 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-06-19 21:40:10 +0000 |
| commit | c1486c47eeedcea065d69ced1f6b454e86ff3191 (patch) | |
| tree | 41f305ed7b3e8ff0a7df6e6545a3028095a61fe3 /packages/cli/src | |
| parent | 619da700709560828c5f6ef112e48994f3238cdc (diff) | |
fix: auto-update sandbox regression (#1221)
Diffstat (limited to 'packages/cli/src')
| -rw-r--r-- | packages/cli/src/config/sandboxConfig.ts | 5 | ||||
| -rw-r--r-- | packages/cli/src/utils/sandbox.ts | 37 |
2 files changed, 39 insertions, 3 deletions
diff --git a/packages/cli/src/config/sandboxConfig.ts b/packages/cli/src/config/sandboxConfig.ts index e0adf0ac..59e19a49 100644 --- a/packages/cli/src/config/sandboxConfig.ts +++ b/packages/cli/src/config/sandboxConfig.ts @@ -30,6 +30,11 @@ function isSandboxCommand(value: string): value is SandboxConfig['command'] { function getSandboxCommand( sandbox?: boolean | string, ): SandboxConfig['command'] | '' { + // If the SANDBOX env var is set, we're already inside the sandbox. + if (process.env.SANDBOX) { + return ''; + } + // note environment variable takes precedence over argument (from command line or settings) sandbox = process.env.GEMINI_SANDBOX?.toLowerCase().trim() ?? sandbox; if (sandbox === '1' || sandbox === 'true') sandbox = true; diff --git a/packages/cli/src/utils/sandbox.ts b/packages/cli/src/utils/sandbox.ts index 48386357..6a08edef 100644 --- a/packages/cli/src/utils/sandbox.ts +++ b/packages/cli/src/utils/sandbox.ts @@ -605,15 +605,46 @@ export async function start_sandbox(config: SandboxConfig) { // Determine if the current user's UID/GID should be passed to the sandbox. // See shouldUseCurrentUserInSandbox for more details. let userFlag = ''; + const finalEntrypoint = entrypoint(workdir); + if (process.env.GEMINI_CLI_INTEGRATION_TEST === 'true') { args.push('--user', 'root'); userFlag = '--user root'; } else if (await shouldUseCurrentUserInSandbox()) { + // For the user-creation logic to work, the container must start as root. + // The entrypoint script then handles dropping privileges to the correct user. + args.push('--user', 'root'); + const uid = execSync('id -u').toString().trim(); const gid = execSync('id -g').toString().trim(); - args.push('--user', `${uid}:${gid}`); + + // Instead of passing --user to the main sandbox container, we let it + // start as root, then create a user with the host's UID/GID, and + // finally switch to that user to run the gemini process. This is + // necessary on Linux to ensure the user exists within the + // container's /etc/passwd file, which is required by os.userInfo(). + const username = 'gemini'; + const homeDir = getContainerPath(os.homedir()); + + const setupUserCommands = [ + // Use -f with groupadd to avoid errors if the group already exists. + `groupadd -f -g ${gid} ${username}`, + // Create user only if it doesn't exist. Use -o for non-unique UID. + `id -u ${username} &>/dev/null || useradd -o -u ${uid} -g ${gid} -d ${homeDir} -s /bin/bash ${username}`, + ].join(' && '); + + const originalCommand = finalEntrypoint[2]; + const escapedOriginalCommand = originalCommand.replace(/'/g, "'\\''"); + + // Use `su -p` to preserve the environment. + const suCommand = `su -p ${username} -c '${escapedOriginalCommand}'`; + + // The entrypoint is always `['bash', '-c', '<command>']`, so we modify the command part. + finalEntrypoint[2] = `${setupUserCommands} && ${suCommand}`; + + // We still need userFlag for the simpler proxy container, which does not have this issue. userFlag = `--user ${uid}:${gid}`; - // when forcing a UID in the sandbox, $HOME can be reset to '/', so we copy $HOME as well + // When forcing a UID in the sandbox, $HOME can be reset to '/', so we copy $HOME as well. args.push('--env', `HOME=${os.homedir()}`); } @@ -621,7 +652,7 @@ export async function start_sandbox(config: SandboxConfig) { args.push(image); // push container entrypoint (including args) - args.push(...entrypoint(workdir)); + args.push(...finalEntrypoint); // start and set up proxy if GEMINI_SANDBOX_PROXY_COMMAND is set let proxyProcess: ChildProcess | undefined = undefined; |
