mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 09:17:53 +00:00
feat: consolidate sandbox configurations into a single object (#1154)
This commit is contained in:
@@ -28,6 +28,7 @@ import * as dotenv from 'dotenv';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import { loadSandboxConfig } from './sandboxConfig.js';
|
||||
|
||||
// Simple console logger for now - replace with actual logger if available
|
||||
const logger = {
|
||||
@@ -42,6 +43,7 @@ const logger = {
|
||||
interface CliArgs {
|
||||
model: string | undefined;
|
||||
sandbox: boolean | string | undefined;
|
||||
'sandbox-image': string | undefined;
|
||||
debug: boolean | undefined;
|
||||
prompt: string | undefined;
|
||||
all_files: boolean | undefined;
|
||||
@@ -72,6 +74,10 @@ async function parseArguments(): Promise<CliArgs> {
|
||||
type: 'boolean',
|
||||
description: 'Run in sandbox?',
|
||||
})
|
||||
.option('sandbox-image', {
|
||||
type: 'string',
|
||||
description: 'Sandbox image URI.',
|
||||
})
|
||||
.option('debug', {
|
||||
alias: 'd',
|
||||
type: 'boolean',
|
||||
@@ -192,11 +198,13 @@ export async function loadCliConfig(
|
||||
|
||||
const mcpServers = mergeMcpServers(settings, extensions);
|
||||
|
||||
const sandboxConfig = await loadSandboxConfig(settings, argv);
|
||||
|
||||
return new Config({
|
||||
sessionId,
|
||||
contentGeneratorConfig,
|
||||
embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
|
||||
sandbox: argv.sandbox ?? settings.sandbox,
|
||||
sandbox: sandboxConfig,
|
||||
targetDir: process.cwd(),
|
||||
debugMode,
|
||||
question: argv.prompt || '',
|
||||
|
||||
102
packages/cli/src/config/sandboxConfig.ts
Normal file
102
packages/cli/src/config/sandboxConfig.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { SandboxConfig } from '@gemini-cli/core';
|
||||
import commandExists from 'command-exists';
|
||||
import * as os from 'node:os';
|
||||
import { getPackageJson } from '../utils/package.js';
|
||||
import { Settings } from './settings.js';
|
||||
|
||||
// This is a stripped-down version of the CliArgs interface from config.ts
|
||||
// to avoid circular dependencies.
|
||||
interface SandboxCliArgs {
|
||||
sandbox?: boolean | string;
|
||||
'sandbox-image'?: string;
|
||||
}
|
||||
|
||||
const VALID_SANDBOX_COMMANDS: ReadonlyArray<SandboxConfig['command']> = [
|
||||
'docker',
|
||||
'podman',
|
||||
'sandbox-exec',
|
||||
];
|
||||
|
||||
function isSandboxCommand(value: string): value is SandboxConfig['command'] {
|
||||
return (VALID_SANDBOX_COMMANDS as readonly string[]).includes(value);
|
||||
}
|
||||
|
||||
function getSandboxCommand(
|
||||
sandbox?: boolean | string,
|
||||
): SandboxConfig['command'] | '' {
|
||||
// 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;
|
||||
else if (sandbox === '0' || sandbox === 'false') sandbox = false;
|
||||
|
||||
if (sandbox === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (typeof sandbox === 'string' && sandbox !== '') {
|
||||
if (!isSandboxCommand(sandbox)) {
|
||||
console.error(
|
||||
`ERROR: invalid sandbox command '${sandbox}'. Must be one of ${VALID_SANDBOX_COMMANDS.join(
|
||||
', ',
|
||||
)}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
// confirm that specfied command exists
|
||||
if (commandExists.sync(sandbox)) {
|
||||
return sandbox;
|
||||
}
|
||||
console.error(
|
||||
`ERROR: missing sandbox command '${sandbox}' (from GEMINI_SANDBOX)`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// look for seatbelt, docker, or podman, in that order
|
||||
// for container-based sandboxing, require sandbox to be enabled explicitly
|
||||
if (os.platform() === 'darwin' && commandExists.sync('sandbox-exec')) {
|
||||
return 'sandbox-exec';
|
||||
} else if (commandExists.sync('docker') && sandbox === true) {
|
||||
return 'docker';
|
||||
} else if (commandExists.sync('podman') && sandbox === true) {
|
||||
return 'podman';
|
||||
}
|
||||
|
||||
// throw an error if user requested sandbox but no command was found
|
||||
if (sandbox === true) {
|
||||
console.error(
|
||||
'ERROR: GEMINI_SANDBOX is true but failed to determine command for sandbox; ' +
|
||||
'install docker or podman or specify command in GEMINI_SANDBOX',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export async function loadSandboxConfig(
|
||||
settings: Settings,
|
||||
argv: SandboxCliArgs,
|
||||
): Promise<SandboxConfig | undefined> {
|
||||
const sandboxOption = argv.sandbox ?? settings.sandbox;
|
||||
const sandboxCommand = getSandboxCommand(sandboxOption);
|
||||
if (!sandboxCommand) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const packageJson = await getPackageJson();
|
||||
return {
|
||||
command: sandboxCommand,
|
||||
image:
|
||||
argv['sandbox-image'] ??
|
||||
process.env.GEMINI_SANDBOX_IMAGE ??
|
||||
packageJson?.config?.sandboxImageUri ??
|
||||
'gemini-cli-sandbox',
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user