mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-25 12:34:38 -07:00
fix(cli): allow restricted .env loading in untrusted sandboxed folders (#17806)
This commit is contained in:
@@ -4,10 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
renderWithProviders,
|
||||
createMockSettings,
|
||||
} from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { CliSpinner } from './CliSpinner.js';
|
||||
import { debugState } from '../debug.js';
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from '../contexts/UIActionsContext.js';
|
||||
import { ConfigContext } from '../contexts/ConfigContext.js';
|
||||
import { SettingsContext } from '../contexts/SettingsContext.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
// Mock VimModeContext hook
|
||||
vi.mock('../contexts/VimModeContext.js', () => ({
|
||||
useVimMode: vi.fn(() => ({
|
||||
@@ -24,7 +25,6 @@ vi.mock('../contexts/VimModeContext.js', () => ({
|
||||
}));
|
||||
import { ApprovalMode } from '@google/gemini-cli-core';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { mergeSettings } from '../../config/settings.js';
|
||||
|
||||
// Mock child components
|
||||
vi.mock('./LoadingIndicator.js', () => ({
|
||||
@@ -168,21 +168,6 @@ const createMockConfig = (overrides = {}) => ({
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const createMockSettings = (merged = {}) => {
|
||||
const defaultMergedSettings = mergeSettings({}, {}, {}, {}, true);
|
||||
return {
|
||||
merged: {
|
||||
...defaultMergedSettings,
|
||||
ui: {
|
||||
...defaultMergedSettings.ui,
|
||||
hideFooter: false,
|
||||
showMemoryUsage: false,
|
||||
...merged,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const renderComposer = (
|
||||
uiState: UIState,
|
||||
@@ -207,7 +192,7 @@ describe('Composer', () => {
|
||||
describe('Footer Display Settings', () => {
|
||||
it('renders Footer by default when hideFooter is false', () => {
|
||||
const uiState = createMockUIState();
|
||||
const settings = createMockSettings({ hideFooter: false });
|
||||
const settings = createMockSettings({ ui: { hideFooter: false } });
|
||||
|
||||
const { lastFrame } = renderComposer(uiState, settings);
|
||||
|
||||
@@ -216,7 +201,7 @@ describe('Composer', () => {
|
||||
|
||||
it('does NOT render Footer when hideFooter is true', () => {
|
||||
const uiState = createMockUIState();
|
||||
const settings = createMockSettings({ hideFooter: true });
|
||||
const settings = createMockSettings({ ui: { hideFooter: true } });
|
||||
|
||||
const { lastFrame } = renderComposer(uiState, settings);
|
||||
|
||||
@@ -245,8 +230,10 @@ describe('Composer', () => {
|
||||
getDebugMode: vi.fn(() => true),
|
||||
});
|
||||
const settings = createMockSettings({
|
||||
hideFooter: false,
|
||||
showMemoryUsage: true,
|
||||
ui: {
|
||||
hideFooter: false,
|
||||
showMemoryUsage: true,
|
||||
},
|
||||
});
|
||||
// Mock vim mode for this test
|
||||
const { useVimMode } = await import('../contexts/VimModeContext.js');
|
||||
|
||||
@@ -101,9 +101,7 @@ describe('FolderTrustDialog', () => {
|
||||
);
|
||||
|
||||
// Unmount immediately (before 250ms)
|
||||
act(() => {
|
||||
unmount();
|
||||
});
|
||||
unmount();
|
||||
|
||||
await vi.advanceTimersByTimeAsync(250);
|
||||
expect(relaunchApp).not.toHaveBeenCalled();
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import {
|
||||
renderWithProviders,
|
||||
createMockSettings,
|
||||
} from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { Footer } from './Footer.js';
|
||||
import { tildeifyPath, ToolCallDecision } from '@google/gemini-cli-core';
|
||||
import type { SessionStatsState } from '../contexts/SessionContext.js';
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
renderWithProviders,
|
||||
createMockSettings,
|
||||
} from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { act, useState } from 'react';
|
||||
import type { InputPromptProps } from './InputPrompt.js';
|
||||
|
||||
@@ -26,6 +26,7 @@ import { waitFor } from '../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { SettingsDialog } from './SettingsDialog.js';
|
||||
import { LoadedSettings, SettingScope } from '../../config/settings.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { VimModeProvider } from '../contexts/VimModeContext.js';
|
||||
import { KeypressProvider } from '../contexts/KeypressContext.js';
|
||||
import { act } from 'react';
|
||||
@@ -58,56 +59,6 @@ enum TerminalKeys {
|
||||
BACKSPACE = '\u0008',
|
||||
}
|
||||
|
||||
const createMockSettings = (
|
||||
userSettings = {},
|
||||
systemSettings = {},
|
||||
workspaceSettings = {},
|
||||
) =>
|
||||
new LoadedSettings(
|
||||
{
|
||||
settings: { ui: { customThemes: {} }, mcpServers: {}, ...systemSettings },
|
||||
originalSettings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...systemSettings,
|
||||
},
|
||||
path: '/system/settings.json',
|
||||
},
|
||||
{
|
||||
settings: {},
|
||||
originalSettings: {},
|
||||
path: '/system/system-defaults.json',
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...userSettings,
|
||||
},
|
||||
originalSettings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...userSettings,
|
||||
},
|
||||
path: '/user/settings.json',
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...workspaceSettings,
|
||||
},
|
||||
originalSettings: {
|
||||
ui: { customThemes: {} },
|
||||
mcpServers: {},
|
||||
...workspaceSettings,
|
||||
},
|
||||
path: '/workspace/settings.json',
|
||||
},
|
||||
true,
|
||||
[],
|
||||
);
|
||||
|
||||
vi.mock('../../config/settingsSchema.js', async (importOriginal) => {
|
||||
const original =
|
||||
await importOriginal<typeof import('../../config/settingsSchema.js')>();
|
||||
@@ -639,11 +590,23 @@ describe('SettingsDialog', () => {
|
||||
});
|
||||
|
||||
it('should show different values for different scopes', () => {
|
||||
const settings = createMockSettings(
|
||||
{ vimMode: true }, // User settings
|
||||
{ vimMode: false }, // System settings
|
||||
{ autoUpdate: false }, // Workspace settings
|
||||
);
|
||||
const settings = createMockSettings({
|
||||
user: {
|
||||
settings: { vimMode: true },
|
||||
originalSettings: { vimMode: true },
|
||||
path: '',
|
||||
},
|
||||
system: {
|
||||
settings: { vimMode: false },
|
||||
originalSettings: { vimMode: false },
|
||||
path: '',
|
||||
},
|
||||
workspace: {
|
||||
settings: { autoUpdate: false },
|
||||
originalSettings: { autoUpdate: false },
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { lastFrame } = renderDialog(settings, onSelect);
|
||||
@@ -733,11 +696,23 @@ describe('SettingsDialog', () => {
|
||||
|
||||
describe('Specific Settings Behavior', () => {
|
||||
it('should show correct display values for settings with different states', () => {
|
||||
const settings = createMockSettings(
|
||||
{ vimMode: true, hideTips: false }, // User settings
|
||||
{ hideWindowTitle: true }, // System settings
|
||||
{ ideMode: false }, // Workspace settings
|
||||
);
|
||||
const settings = createMockSettings({
|
||||
user: {
|
||||
settings: { vimMode: true, hideTips: false },
|
||||
originalSettings: { vimMode: true, hideTips: false },
|
||||
path: '',
|
||||
},
|
||||
system: {
|
||||
settings: { hideWindowTitle: true },
|
||||
originalSettings: { hideWindowTitle: true },
|
||||
path: '',
|
||||
},
|
||||
workspace: {
|
||||
settings: { ideMode: false },
|
||||
originalSettings: { ideMode: false },
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { lastFrame } = renderDialog(settings, onSelect);
|
||||
@@ -794,11 +769,13 @@ describe('SettingsDialog', () => {
|
||||
|
||||
describe('Settings Display Values', () => {
|
||||
it('should show correct values for inherited settings', () => {
|
||||
const settings = createMockSettings(
|
||||
{},
|
||||
{ vimMode: true, hideWindowTitle: false }, // System settings
|
||||
{},
|
||||
);
|
||||
const settings = createMockSettings({
|
||||
system: {
|
||||
settings: { vimMode: true, hideWindowTitle: false },
|
||||
originalSettings: { vimMode: true, hideWindowTitle: false },
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { lastFrame } = renderDialog(settings, onSelect);
|
||||
@@ -809,11 +786,18 @@ describe('SettingsDialog', () => {
|
||||
});
|
||||
|
||||
it('should show override indicator for overridden settings', () => {
|
||||
const settings = createMockSettings(
|
||||
{ vimMode: false }, // User overrides
|
||||
{ vimMode: true }, // System default
|
||||
{},
|
||||
);
|
||||
const settings = createMockSettings({
|
||||
user: {
|
||||
settings: { vimMode: false },
|
||||
originalSettings: { vimMode: false },
|
||||
path: '',
|
||||
},
|
||||
system: {
|
||||
settings: { vimMode: true },
|
||||
originalSettings: { vimMode: true },
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { lastFrame } = renderDialog(settings, onSelect);
|
||||
@@ -983,11 +967,13 @@ describe('SettingsDialog', () => {
|
||||
describe('Error Recovery', () => {
|
||||
it('should handle malformed settings gracefully', () => {
|
||||
// Create settings with potentially problematic values
|
||||
const settings = createMockSettings(
|
||||
{ vimMode: null as unknown as boolean }, // Invalid value
|
||||
{},
|
||||
{},
|
||||
);
|
||||
const settings = createMockSettings({
|
||||
user: {
|
||||
settings: { vimMode: null as unknown as boolean },
|
||||
originalSettings: { vimMode: null as unknown as boolean },
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { lastFrame } = renderDialog(settings, onSelect);
|
||||
@@ -1198,11 +1184,13 @@ describe('SettingsDialog', () => {
|
||||
stdin.write('\r'); // Commit
|
||||
});
|
||||
|
||||
settings = createMockSettings(
|
||||
{ 'a.string.setting': 'new value' },
|
||||
{},
|
||||
{},
|
||||
);
|
||||
settings = createMockSettings({
|
||||
user: {
|
||||
settings: { 'a.string.setting': 'new value' },
|
||||
originalSettings: { 'a.string.setting': 'new value' },
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
rerender(
|
||||
<KeypressProvider>
|
||||
<SettingsDialog settings={settings} onSelect={onSelect} />
|
||||
@@ -1550,11 +1538,23 @@ describe('SettingsDialog', () => {
|
||||
])(
|
||||
'should render $name correctly',
|
||||
({ userSettings, systemSettings, workspaceSettings, stdinActions }) => {
|
||||
const settings = createMockSettings(
|
||||
userSettings,
|
||||
systemSettings,
|
||||
workspaceSettings,
|
||||
);
|
||||
const settings = createMockSettings({
|
||||
user: {
|
||||
settings: userSettings,
|
||||
originalSettings: userSettings,
|
||||
path: '',
|
||||
},
|
||||
system: {
|
||||
settings: systemSettings,
|
||||
originalSettings: systemSettings,
|
||||
path: '',
|
||||
},
|
||||
workspace: {
|
||||
settings: workspaceSettings,
|
||||
originalSettings: workspaceSettings,
|
||||
path: '',
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
||||
const { lastFrame, stdin } = renderDialog(settings, onSelect);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { StatusDisplay } from './StatusDisplay.js';
|
||||
import { UIStateContext, type UIState } from '../contexts/UIStateContext.js';
|
||||
import { ConfigContext } from '../contexts/ConfigContext.js';
|
||||
import { SettingsContext } from '../contexts/SettingsContext.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import type { TextBuffer } from './shared/text-buffer.js';
|
||||
|
||||
// Mock child components to simplify testing
|
||||
@@ -65,14 +66,6 @@ const createMockConfig = (overrides = {}) => ({
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const createMockSettings = (merged = {}) => ({
|
||||
merged: {
|
||||
hooksConfig: { notifications: true },
|
||||
ui: { hideContextSummary: false },
|
||||
...merged,
|
||||
},
|
||||
});
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const renderStatusDisplay = (
|
||||
props: { hideContextSummary: boolean } = { hideContextSummary: false },
|
||||
|
||||
@@ -8,52 +8,10 @@ import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { ThemeDialog } from './ThemeDialog.js';
|
||||
import { LoadedSettings } from '../../config/settings.js';
|
||||
import { createMockSettings } from '../../test-utils/settings.js';
|
||||
import { DEFAULT_THEME, themeManager } from '../themes/theme-manager.js';
|
||||
import { act } from 'react';
|
||||
|
||||
const createMockSettings = (
|
||||
userSettings = {},
|
||||
workspaceSettings = {},
|
||||
systemSettings = {},
|
||||
): LoadedSettings =>
|
||||
new LoadedSettings(
|
||||
{
|
||||
settings: { ui: { customThemes: {} }, ...systemSettings },
|
||||
originalSettings: { ui: { customThemes: {} }, ...systemSettings },
|
||||
path: '/system/settings.json',
|
||||
},
|
||||
{
|
||||
settings: {},
|
||||
originalSettings: {},
|
||||
path: '/system/system-defaults.json',
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
...userSettings,
|
||||
},
|
||||
originalSettings: {
|
||||
ui: { customThemes: {} },
|
||||
...userSettings,
|
||||
},
|
||||
path: '/user/settings.json',
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
ui: { customThemes: {} },
|
||||
...workspaceSettings,
|
||||
},
|
||||
originalSettings: {
|
||||
ui: { customThemes: {} },
|
||||
...workspaceSettings,
|
||||
},
|
||||
path: '/workspace/settings.json',
|
||||
},
|
||||
true,
|
||||
[],
|
||||
);
|
||||
|
||||
describe('ThemeDialog Snapshots', () => {
|
||||
const baseProps = {
|
||||
onSelect: vi.fn(),
|
||||
|
||||
@@ -10,10 +10,8 @@ import type {
|
||||
ToolCallConfirmationDetails,
|
||||
Config,
|
||||
} from '@google/gemini-cli-core';
|
||||
import {
|
||||
renderWithProviders,
|
||||
createMockSettings,
|
||||
} from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { useToolActions } from '../../contexts/ToolActionsContext.js';
|
||||
|
||||
vi.mock('../../contexts/ToolActionsContext.js', async (importOriginal) => {
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
renderWithProviders,
|
||||
createMockSettings,
|
||||
} from '../../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { createMockSettings } from '../../../test-utils/settings.js';
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
|
||||
Reference in New Issue
Block a user