mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
Introduce GEMINI_CLI_HOME for strict test isolation (#15907)
This commit is contained in:
@@ -24,6 +24,15 @@ vi.mock('os', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: mockHomedir,
|
||||
};
|
||||
});
|
||||
|
||||
describe('ExtensionManager skills validation', () => {
|
||||
let tempHomeDir: string;
|
||||
let tempWorkspaceDir: string;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import { stat } from 'node:fs/promises';
|
||||
import chalk from 'chalk';
|
||||
import { ExtensionEnablementManager } from './extensions/extensionEnablement.js';
|
||||
@@ -39,6 +38,7 @@ import {
|
||||
logExtensionUninstall,
|
||||
logExtensionUpdateEvent,
|
||||
loadSkillsFromDir,
|
||||
homedir,
|
||||
type ExtensionEvents,
|
||||
type MCPServerConfig,
|
||||
type ExtensionInstallMetadata,
|
||||
@@ -692,7 +692,7 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
toOutputString(extension: GeminiCLIExtension): string {
|
||||
const userEnabled = this.extensionEnablementManager.isEnabled(
|
||||
extension.name,
|
||||
os.homedir(),
|
||||
homedir(),
|
||||
);
|
||||
const workspaceEnabled = this.extensionEnablementManager.isEnabled(
|
||||
extension.name,
|
||||
@@ -766,7 +766,7 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
|
||||
if (scope !== SettingScope.Session) {
|
||||
const scopePath =
|
||||
scope === SettingScope.Workspace ? this.workspaceDir : os.homedir();
|
||||
scope === SettingScope.Workspace ? this.workspaceDir : homedir();
|
||||
this.extensionEnablementManager.disable(name, true, scopePath);
|
||||
}
|
||||
await logExtensionDisable(
|
||||
@@ -801,7 +801,7 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
|
||||
if (scope !== SettingScope.Session) {
|
||||
const scopePath =
|
||||
scope === SettingScope.Workspace ? this.workspaceDir : os.homedir();
|
||||
scope === SettingScope.Workspace ? this.workspaceDir : homedir();
|
||||
this.extensionEnablementManager.enable(name, true, scopePath);
|
||||
}
|
||||
await logExtensionEnable(
|
||||
|
||||
@@ -105,6 +105,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
logExtensionUninstall: mockLogExtensionUninstall,
|
||||
logExtensionUpdateEvent: mockLogExtensionUpdateEvent,
|
||||
logExtensionDisable: mockLogExtensionDisable,
|
||||
homedir: mockHomedir,
|
||||
ExtensionEnableEvent: vi.fn(),
|
||||
ExtensionInstallEvent: vi.fn(),
|
||||
ExtensionUninstallEvent: vi.fn(),
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
EXTENSION_SETTINGS_FILENAME,
|
||||
EXTENSIONS_CONFIG_FILENAME,
|
||||
} from './variables.js';
|
||||
import { Storage } from '@google/gemini-cli-core';
|
||||
import { Storage, homedir } from '@google/gemini-cli-core';
|
||||
|
||||
export class ExtensionStorage {
|
||||
private readonly extensionName: string;
|
||||
@@ -36,7 +36,7 @@ export class ExtensionStorage {
|
||||
}
|
||||
|
||||
static getUserExtensionsDir(): string {
|
||||
return new Storage(os.homedir()).getExtensionsDir();
|
||||
return new Storage(homedir()).getExtensionsDir();
|
||||
}
|
||||
|
||||
static async createTmpDir(): Promise<string> {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { homedir, platform } from 'node:os';
|
||||
import { platform } from 'node:os';
|
||||
import * as dotenv from 'dotenv';
|
||||
import process from 'node:process';
|
||||
import {
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
getErrorMessage,
|
||||
Storage,
|
||||
coreEvents,
|
||||
homedir,
|
||||
} from '@google/gemini-cli-core';
|
||||
import stripJsonComments from 'strip-json-comments';
|
||||
import { DefaultLight } from '../ui/themes/default-light.js';
|
||||
|
||||
@@ -27,6 +27,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
return {
|
||||
...actual,
|
||||
coreEvents: mockCoreEvents,
|
||||
homedir: () => '/mock/home/user',
|
||||
Storage: class extends actual.Storage {
|
||||
static override getGlobalSettingsPath = () =>
|
||||
'/mock/home/user/.gemini/settings.json';
|
||||
@@ -52,11 +53,15 @@ vi.mock('./trustedFolders.js', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('os', () => ({
|
||||
homedir: () => '/mock/home/user',
|
||||
platform: () => 'linux',
|
||||
totalmem: () => 16 * 1024 * 1024 * 1024,
|
||||
}));
|
||||
vi.mock('os', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('node:os')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: () => '/mock/home/user',
|
||||
platform: () => 'linux',
|
||||
totalmem: () => 16 * 1024 * 1024 * 1024,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('fs', async (importOriginal) => {
|
||||
const actualFs = await importOriginal<typeof fs>();
|
||||
|
||||
@@ -36,6 +36,15 @@ vi.mock('os', async (importOriginal) => {
|
||||
platform: vi.fn(() => 'linux'),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: () => '/mock/home/user',
|
||||
};
|
||||
});
|
||||
vi.mock('fs', async (importOriginal) => {
|
||||
const actualFs = await importOriginal<typeof fs>();
|
||||
return {
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { homedir } from 'node:os';
|
||||
import {
|
||||
FatalConfigError,
|
||||
getErrorMessage,
|
||||
isWithinRoot,
|
||||
ideContextStore,
|
||||
GEMINI_DIR,
|
||||
homedir,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Settings } from './settings.js';
|
||||
import stripJsonComments from 'strip-json-comments';
|
||||
|
||||
@@ -48,6 +48,7 @@ vi.mock('node:path', async () => {
|
||||
|
||||
vi.mock('@google/gemini-cli-core', () => ({
|
||||
GEMINI_DIR: '.gemini',
|
||||
homedir: () => '/mock/home',
|
||||
Storage: {
|
||||
getGlobalTempDir: () => '/mock/temp',
|
||||
},
|
||||
|
||||
@@ -12,13 +12,17 @@ import { theme } from '../semantic-colors.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { UpdateNotification } from './UpdateNotification.js';
|
||||
|
||||
import { GEMINI_DIR, Storage, debugLogger } from '@google/gemini-cli-core';
|
||||
import {
|
||||
GEMINI_DIR,
|
||||
Storage,
|
||||
debugLogger,
|
||||
homedir,
|
||||
} from '@google/gemini-cli-core';
|
||||
|
||||
import * as fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
const settingsPath = path.join(os.homedir(), GEMINI_DIR, 'settings.json');
|
||||
const settingsPath = path.join(homedir(), GEMINI_DIR, 'settings.json');
|
||||
|
||||
const screenReaderNudgeFilePath = path.join(
|
||||
Storage.getGlobalTempDir(),
|
||||
|
||||
@@ -74,6 +74,7 @@ vi.mock('node:process', () => {
|
||||
exit: mockProcessExit,
|
||||
platform: 'sunos',
|
||||
cwd: () => '/fake/dir',
|
||||
env: {},
|
||||
} as unknown as NodeJS.Process;
|
||||
return {
|
||||
...mockProcess,
|
||||
|
||||
@@ -30,6 +30,15 @@ vi.mock('os', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: () => os.homedir(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../config/extensions/update.js', () => ({
|
||||
checkForAllExtensionUpdates: vi.fn(),
|
||||
updateExtension: vi.fn(),
|
||||
|
||||
@@ -28,9 +28,16 @@ const mockedIsWorkspaceTrusted = vi.hoisted(() => vi.fn());
|
||||
const mockedUseSettings = vi.hoisted(() => vi.fn());
|
||||
|
||||
// Mock modules
|
||||
vi.mock('node:process', () => ({
|
||||
cwd: mockedCwd,
|
||||
}));
|
||||
vi.mock('node:process', () => {
|
||||
const mockProcess = {
|
||||
cwd: mockedCwd,
|
||||
env: {},
|
||||
};
|
||||
return {
|
||||
...mockProcess,
|
||||
default: mockProcess,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('node:path', async (importOriginal) => {
|
||||
const actual = await importOriginal();
|
||||
|
||||
@@ -27,6 +27,15 @@ vi.mock('node:os', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: () => os.homedir(),
|
||||
};
|
||||
});
|
||||
|
||||
const validCustomTheme: CustomTheme = {
|
||||
type: 'custom',
|
||||
name: 'MyCustomTheme',
|
||||
|
||||
@@ -18,7 +18,6 @@ import { ShadesOfPurple } from './shades-of-purple.js';
|
||||
import { XCode } from './xcode.js';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import type { Theme, ThemeType, CustomTheme } from './theme.js';
|
||||
import { createCustomTheme, validateCustomTheme } from './theme.js';
|
||||
import type { SemanticColors } from './semantic-tokens.js';
|
||||
@@ -26,7 +25,7 @@ import { ANSI } from './ansi.js';
|
||||
import { ANSILight } from './ansi-light.js';
|
||||
import { NoColorTheme } from './no-color.js';
|
||||
import process from 'node:process';
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
import { debugLogger, homedir } from '@google/gemini-cli-core';
|
||||
|
||||
export interface ThemeDisplay {
|
||||
name: string;
|
||||
@@ -255,7 +254,7 @@ class ThemeManager {
|
||||
}
|
||||
|
||||
// 2. Perform security check.
|
||||
const homeDir = path.resolve(os.homedir());
|
||||
const homeDir = path.resolve(homedir());
|
||||
if (!canonicalPath.startsWith(homeDir)) {
|
||||
debugLogger.warn(
|
||||
`Theme file at "${themePath}" is outside your home directory. ` +
|
||||
|
||||
@@ -16,6 +16,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...original,
|
||||
homedir: () => mockHomeDir,
|
||||
loadServerHierarchicalMemory: vi.fn().mockResolvedValue({
|
||||
memoryContent: 'mock memory',
|
||||
fileCount: 10,
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import * as fs from 'node:fs';
|
||||
import { opendir } from 'node:fs/promises';
|
||||
import { homedir } from '@google/gemini-cli-core';
|
||||
|
||||
const MAX_SUGGESTIONS = 50;
|
||||
const MATCH_BUFFER_MULTIPLIER = 3;
|
||||
@@ -18,9 +18,9 @@ export function expandHomeDir(p: string): string {
|
||||
}
|
||||
let expandedPath = p;
|
||||
if (p.toLowerCase().startsWith('%userprofile%')) {
|
||||
expandedPath = os.homedir() + p.substring('%userprofile%'.length);
|
||||
expandedPath = homedir() + p.substring('%userprofile%'.length);
|
||||
} else if (p === '~' || p.startsWith('~/')) {
|
||||
expandedPath = os.homedir() + p.substring(1);
|
||||
expandedPath = homedir() + p.substring(1);
|
||||
}
|
||||
return path.normalize(expandedPath);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ function parsePartialPath(partialPath: string): ParsedPath {
|
||||
!partialPath.includes('/') &&
|
||||
!partialPath.includes(path.sep)
|
||||
) {
|
||||
searchDir = os.homedir();
|
||||
searchDir = homedir();
|
||||
filter = partialPath.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,15 @@ vi.mock('node:os', () => ({
|
||||
platform: mocks.platform,
|
||||
}));
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: mocks.homedir,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('./terminalCapabilityManager.js', () => ({
|
||||
terminalCapabilityManager: {
|
||||
isKittyProtocolEnabled: vi.fn().mockReturnValue(false),
|
||||
|
||||
@@ -30,7 +30,7 @@ import { exec } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
import { terminalCapabilityManager } from './terminalCapabilityManager.js';
|
||||
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
import { debugLogger, homedir } from '@google/gemini-cli-core';
|
||||
|
||||
export const VSCODE_SHIFT_ENTER_SEQUENCE = '\\\r\n';
|
||||
|
||||
@@ -124,7 +124,7 @@ function getVSCodeStyleConfigDir(appName: string): string | null {
|
||||
|
||||
if (platform === 'darwin') {
|
||||
return path.join(
|
||||
os.homedir(),
|
||||
homedir(),
|
||||
'Library',
|
||||
'Application Support',
|
||||
appName,
|
||||
@@ -136,7 +136,7 @@ function getVSCodeStyleConfigDir(appName: string): string | null {
|
||||
}
|
||||
return path.join(process.env['APPDATA'], appName, 'User');
|
||||
} else {
|
||||
return path.join(os.homedir(), '.config', appName, 'User');
|
||||
return path.join(homedir(), '.config', appName, 'User');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ vi.mock('node:os', () => ({
|
||||
homedir: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@google/gemini-cli-core', () => ({
|
||||
homedir: () => os.homedir(),
|
||||
}));
|
||||
|
||||
describe('resolvePath', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(os.homedir).mockReturnValue('/home/user');
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { homedir } from '@google/gemini-cli-core';
|
||||
|
||||
export function resolvePath(p: string): string {
|
||||
if (!p) {
|
||||
@@ -13,9 +13,9 @@ export function resolvePath(p: string): string {
|
||||
}
|
||||
let expandedPath = p;
|
||||
if (p.toLowerCase().startsWith('%userprofile%')) {
|
||||
expandedPath = os.homedir() + p.substring('%userprofile%'.length);
|
||||
expandedPath = homedir() + p.substring('%userprofile%'.length);
|
||||
} else if (p === '~' || p.startsWith('~/')) {
|
||||
expandedPath = os.homedir() + p.substring(1);
|
||||
expandedPath = homedir() + p.substring(1);
|
||||
}
|
||||
return path.normalize(expandedPath);
|
||||
}
|
||||
|
||||
@@ -12,9 +12,19 @@ import { start_sandbox } from './sandbox.js';
|
||||
import { FatalSandboxError, type SandboxConfig } from '@google/gemini-cli-core';
|
||||
import { EventEmitter } from 'node:events';
|
||||
|
||||
vi.mock('../config/settings.js', () => ({
|
||||
USER_SETTINGS_DIR: '/home/user/.gemini',
|
||||
const { mockedHomedir, mockedGetContainerPath } = vi.hoisted(() => ({
|
||||
mockedHomedir: vi.fn().mockReturnValue('/home/user'),
|
||||
mockedGetContainerPath: vi.fn().mockImplementation((p: string) => p),
|
||||
}));
|
||||
|
||||
vi.mock('./sandboxUtils.js', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('./sandboxUtils.js')>();
|
||||
return {
|
||||
...actual,
|
||||
getContainerPath: mockedGetContainerPath,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('node:child_process');
|
||||
vi.mock('node:os');
|
||||
vi.mock('node:fs');
|
||||
@@ -44,6 +54,7 @@ vi.mock('node:util', async (importOriginal) => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
@@ -64,7 +75,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
}
|
||||
},
|
||||
GEMINI_DIR: '.gemini',
|
||||
USER_SETTINGS_DIR: '/home/user/.gemini',
|
||||
homedir: mockedHomedir,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -341,13 +352,23 @@ describe('sandbox', () => {
|
||||
|
||||
await start_sandbox(config);
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
// The first call is 'docker images -q ...'
|
||||
expect(spawn).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'docker',
|
||||
expect.arrayContaining(['images', '-q']),
|
||||
);
|
||||
|
||||
// The second call is 'docker run ...'
|
||||
expect(spawn).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'docker',
|
||||
expect.arrayContaining([
|
||||
'run',
|
||||
'--volume',
|
||||
'/host/path:/container/path:ro',
|
||||
'--volume',
|
||||
expect.stringContaining('/home/user/.gemini'),
|
||||
expect.stringMatching(/[\\/]home[\\/]user[\\/]\.gemini/),
|
||||
]),
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
*/
|
||||
|
||||
import { exec, execSync, spawn, type ChildProcess } from 'node:child_process';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { quote, parse } from 'shell-quote';
|
||||
import { USER_SETTINGS_DIR } from '../config/settings.js';
|
||||
import { promisify } from 'node:util';
|
||||
import type { Config, SandboxConfig } from '@google/gemini-cli-core';
|
||||
import {
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
debugLogger,
|
||||
FatalSandboxError,
|
||||
GEMINI_DIR,
|
||||
homedir,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { ConsolePatcher } from '../ui/utils/ConsolePatcher.js';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
@@ -82,7 +82,7 @@ export async function start_sandbox(
|
||||
'-D',
|
||||
`TMP_DIR=${fs.realpathSync(os.tmpdir())}`,
|
||||
'-D',
|
||||
`HOME_DIR=${fs.realpathSync(os.homedir())}`,
|
||||
`HOME_DIR=${fs.realpathSync(homedir())}`,
|
||||
'-D',
|
||||
`CACHE_DIR=${fs.realpathSync((await execAsync('getconf DARWIN_USER_CACHE_DIR')).stdout.trim())}`,
|
||||
];
|
||||
@@ -288,18 +288,23 @@ export async function start_sandbox(
|
||||
|
||||
// mount user settings directory inside container, after creating if missing
|
||||
// note user/home changes inside sandbox and we mount at BOTH paths for consistency
|
||||
const userSettingsDirOnHost = USER_SETTINGS_DIR;
|
||||
const userHomeDirOnHost = homedir();
|
||||
const userSettingsDirInSandbox = getContainerPath(
|
||||
`/home/node/${GEMINI_DIR}`,
|
||||
);
|
||||
if (!fs.existsSync(userSettingsDirOnHost)) {
|
||||
fs.mkdirSync(userSettingsDirOnHost);
|
||||
if (!fs.existsSync(userHomeDirOnHost)) {
|
||||
fs.mkdirSync(userHomeDirOnHost, { recursive: true });
|
||||
}
|
||||
const userSettingsDirOnHost = path.join(userHomeDirOnHost, GEMINI_DIR);
|
||||
if (!fs.existsSync(userSettingsDirOnHost)) {
|
||||
fs.mkdirSync(userSettingsDirOnHost, { recursive: true });
|
||||
}
|
||||
|
||||
args.push(
|
||||
'--volume',
|
||||
`${userSettingsDirOnHost}:${userSettingsDirInSandbox}`,
|
||||
);
|
||||
if (userSettingsDirInSandbox !== userSettingsDirOnHost) {
|
||||
if (userSettingsDirInSandbox !== getContainerPath(userSettingsDirOnHost)) {
|
||||
args.push(
|
||||
'--volume',
|
||||
`${userSettingsDirOnHost}:${getContainerPath(userSettingsDirOnHost)}`,
|
||||
@@ -309,8 +314,16 @@ export async function start_sandbox(
|
||||
// mount os.tmpdir() as os.tmpdir() inside container
|
||||
args.push('--volume', `${os.tmpdir()}:${getContainerPath(os.tmpdir())}`);
|
||||
|
||||
// mount homedir() as homedir() inside container
|
||||
if (userHomeDirOnHost !== os.homedir()) {
|
||||
args.push(
|
||||
'--volume',
|
||||
`${userHomeDirOnHost}:${getContainerPath(userHomeDirOnHost)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// mount gcloud config directory if it exists
|
||||
const gcloudConfigDir = path.join(os.homedir(), '.config', 'gcloud');
|
||||
const gcloudConfigDir = path.join(homedir(), '.config', 'gcloud');
|
||||
if (fs.existsSync(gcloudConfigDir)) {
|
||||
args.push(
|
||||
'--volume',
|
||||
@@ -585,7 +598,7 @@ export async function start_sandbox(
|
||||
// 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 homeDir = getContainerPath(homedir());
|
||||
|
||||
const setupUserCommands = [
|
||||
// Use -f with groupadd to avoid errors if the group already exists.
|
||||
@@ -606,7 +619,7 @@ export async function start_sandbox(
|
||||
// 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.
|
||||
args.push('--env', `HOME=${os.homedir()}`);
|
||||
args.push('--env', `HOME=${homedir()}`);
|
||||
}
|
||||
|
||||
// push container image name
|
||||
|
||||
@@ -19,6 +19,15 @@ vi.mock('os', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
return {
|
||||
...actual,
|
||||
homedir: () => os.homedir(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('getUserStartupWarnings', () => {
|
||||
let testRootDir: string;
|
||||
let homeDir: string;
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
*/
|
||||
|
||||
import fs from 'node:fs/promises';
|
||||
import * as os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { homedir } from '@google/gemini-cli-core';
|
||||
|
||||
type WarningCheck = {
|
||||
id: string;
|
||||
@@ -20,7 +21,7 @@ const homeDirectoryCheck: WarningCheck = {
|
||||
try {
|
||||
const [workspaceRealPath, homeRealPath] = await Promise.all([
|
||||
fs.realpath(workspaceRoot),
|
||||
fs.realpath(os.homedir()),
|
||||
fs.realpath(homedir()),
|
||||
]);
|
||||
|
||||
if (workspaceRealPath === homeRealPath) {
|
||||
|
||||
Reference in New Issue
Block a user