mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-28 05:55:17 -07:00
feat(ui): Put "Allow for all future sessions" behind a setting off by default. (#15322)
This commit is contained in:
@@ -731,6 +731,11 @@ their corresponding top-level category object in your `settings.json` file.
|
|||||||
- **Default:** `false`
|
- **Default:** `false`
|
||||||
- **Requires restart:** Yes
|
- **Requires restart:** Yes
|
||||||
|
|
||||||
|
- **`security.enablePermanentToolApproval`** (boolean):
|
||||||
|
- **Description:** Enable the "Allow for all future sessions" option in tool
|
||||||
|
confirmation dialogs.
|
||||||
|
- **Default:** `false`
|
||||||
|
|
||||||
- **`security.blockGitExtensions`** (boolean):
|
- **`security.blockGitExtensions`** (boolean):
|
||||||
- **Description:** Blocks installing and loading extensions from Git.
|
- **Description:** Blocks installing and loading extensions from Git.
|
||||||
- **Default:** `false`
|
- **Default:** `false`
|
||||||
|
|||||||
@@ -1164,6 +1164,16 @@ const SETTINGS_SCHEMA = {
|
|||||||
description: 'Disable YOLO mode, even if enabled by a flag.',
|
description: 'Disable YOLO mode, even if enabled by a flag.',
|
||||||
showInDialog: true,
|
showInDialog: true,
|
||||||
},
|
},
|
||||||
|
enablePermanentToolApproval: {
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Allow Permanent Tool Approval',
|
||||||
|
category: 'Security',
|
||||||
|
requiresRestart: false,
|
||||||
|
default: false,
|
||||||
|
description:
|
||||||
|
'Enable the "Allow for all future sessions" option in tool confirmation dialogs.',
|
||||||
|
showInDialog: true,
|
||||||
|
},
|
||||||
blockGitExtensions: {
|
blockGitExtensions: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
label: 'Blocks extensions from Git',
|
label: 'Blocks extensions from Git',
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import type {
|
|||||||
ToolCallConfirmationDetails,
|
ToolCallConfirmationDetails,
|
||||||
Config,
|
Config,
|
||||||
} from '@google/gemini-cli-core';
|
} from '@google/gemini-cli-core';
|
||||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
import {
|
||||||
|
renderWithProviders,
|
||||||
|
createMockSettings,
|
||||||
|
} from '../../../test-utils/render.js';
|
||||||
|
|
||||||
describe('ToolConfirmationMessage', () => {
|
describe('ToolConfirmationMessage', () => {
|
||||||
const mockConfig = {
|
const mockConfig = {
|
||||||
@@ -159,4 +162,63 @@ describe('ToolConfirmationMessage', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('enablePermanentToolApproval setting', () => {
|
||||||
|
const editConfirmationDetails: ToolCallConfirmationDetails = {
|
||||||
|
type: 'edit',
|
||||||
|
title: 'Confirm Edit',
|
||||||
|
fileName: 'test.txt',
|
||||||
|
filePath: '/test.txt',
|
||||||
|
fileDiff: '...diff...',
|
||||||
|
originalContent: 'a',
|
||||||
|
newContent: 'b',
|
||||||
|
onConfirm: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should NOT show "Allow for all future sessions" when setting is false (default)', () => {
|
||||||
|
const mockConfig = {
|
||||||
|
isTrustedFolder: () => true,
|
||||||
|
getIdeMode: () => false,
|
||||||
|
} as unknown as Config;
|
||||||
|
|
||||||
|
const { lastFrame } = renderWithProviders(
|
||||||
|
<ToolConfirmationMessage
|
||||||
|
confirmationDetails={editConfirmationDetails}
|
||||||
|
config={mockConfig}
|
||||||
|
availableTerminalHeight={30}
|
||||||
|
terminalWidth={80}
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
settings: createMockSettings({
|
||||||
|
security: { enablePermanentToolApproval: false },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(lastFrame()).not.toContain('Allow for all future sessions');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show "Allow for all future sessions" when setting is true', () => {
|
||||||
|
const mockConfig = {
|
||||||
|
isTrustedFolder: () => true,
|
||||||
|
getIdeMode: () => false,
|
||||||
|
} as unknown as Config;
|
||||||
|
|
||||||
|
const { lastFrame } = renderWithProviders(
|
||||||
|
<ToolConfirmationMessage
|
||||||
|
confirmationDetails={editConfirmationDetails}
|
||||||
|
config={mockConfig}
|
||||||
|
availableTerminalHeight={30}
|
||||||
|
terminalWidth={80}
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
settings: createMockSettings({
|
||||||
|
security: { enablePermanentToolApproval: true },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(lastFrame()).toContain('Allow for all future sessions');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { MaxSizedBox } from '../shared/MaxSizedBox.js';
|
|||||||
import { useKeypress } from '../../hooks/useKeypress.js';
|
import { useKeypress } from '../../hooks/useKeypress.js';
|
||||||
import { theme } from '../../semantic-colors.js';
|
import { theme } from '../../semantic-colors.js';
|
||||||
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
|
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
|
||||||
|
import { useSettings } from '../../contexts/SettingsContext.js';
|
||||||
|
|
||||||
export interface ToolConfirmationMessageProps {
|
export interface ToolConfirmationMessageProps {
|
||||||
confirmationDetails: ToolCallConfirmationDetails;
|
confirmationDetails: ToolCallConfirmationDetails;
|
||||||
@@ -41,6 +42,9 @@ export const ToolConfirmationMessage: React.FC<
|
|||||||
const { onConfirm } = confirmationDetails;
|
const { onConfirm } = confirmationDetails;
|
||||||
|
|
||||||
const isAlternateBuffer = useAlternateBuffer();
|
const isAlternateBuffer = useAlternateBuffer();
|
||||||
|
const settings = useSettings();
|
||||||
|
const allowPermanentApproval =
|
||||||
|
settings.merged.security?.enablePermanentToolApproval ?? false;
|
||||||
|
|
||||||
const [ideClient, setIdeClient] = useState<IdeClient | null>(null);
|
const [ideClient, setIdeClient] = useState<IdeClient | null>(null);
|
||||||
const [isDiffingEnabled, setIsDiffingEnabled] = useState(false);
|
const [isDiffingEnabled, setIsDiffingEnabled] = useState(false);
|
||||||
@@ -112,11 +116,13 @@ export const ToolConfirmationMessage: React.FC<
|
|||||||
value: ToolConfirmationOutcome.ProceedAlways,
|
value: ToolConfirmationOutcome.ProceedAlways,
|
||||||
key: 'Allow for this session',
|
key: 'Allow for this session',
|
||||||
});
|
});
|
||||||
options.push({
|
if (allowPermanentApproval) {
|
||||||
label: 'Allow for all future sessions',
|
options.push({
|
||||||
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
label: 'Allow for all future sessions',
|
||||||
key: 'Allow for all future sessions',
|
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
||||||
});
|
key: 'Allow for all future sessions',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!config.getIdeMode() || !isDiffingEnabled) {
|
if (!config.getIdeMode() || !isDiffingEnabled) {
|
||||||
options.push({
|
options.push({
|
||||||
@@ -147,11 +153,13 @@ export const ToolConfirmationMessage: React.FC<
|
|||||||
value: ToolConfirmationOutcome.ProceedAlways,
|
value: ToolConfirmationOutcome.ProceedAlways,
|
||||||
key: `Allow for this session`,
|
key: `Allow for this session`,
|
||||||
});
|
});
|
||||||
options.push({
|
if (allowPermanentApproval) {
|
||||||
label: `Allow for all future sessions`,
|
options.push({
|
||||||
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
label: `Allow for all future sessions`,
|
||||||
key: `Allow for all future sessions`,
|
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
||||||
});
|
key: `Allow for all future sessions`,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
label: 'No, suggest changes (esc)',
|
label: 'No, suggest changes (esc)',
|
||||||
@@ -171,11 +179,13 @@ export const ToolConfirmationMessage: React.FC<
|
|||||||
value: ToolConfirmationOutcome.ProceedAlways,
|
value: ToolConfirmationOutcome.ProceedAlways,
|
||||||
key: 'Allow for this session',
|
key: 'Allow for this session',
|
||||||
});
|
});
|
||||||
options.push({
|
if (allowPermanentApproval) {
|
||||||
label: 'Allow for all future sessions',
|
options.push({
|
||||||
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
label: 'Allow for all future sessions',
|
||||||
key: 'Allow for all future sessions',
|
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
||||||
});
|
key: 'Allow for all future sessions',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
label: 'No, suggest changes (esc)',
|
label: 'No, suggest changes (esc)',
|
||||||
@@ -202,11 +212,13 @@ export const ToolConfirmationMessage: React.FC<
|
|||||||
value: ToolConfirmationOutcome.ProceedAlwaysServer,
|
value: ToolConfirmationOutcome.ProceedAlwaysServer,
|
||||||
key: 'Allow all server tools for this session',
|
key: 'Allow all server tools for this session',
|
||||||
});
|
});
|
||||||
options.push({
|
if (allowPermanentApproval) {
|
||||||
label: 'Allow tool for all future sessions',
|
options.push({
|
||||||
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
label: 'Allow tool for all future sessions',
|
||||||
key: 'Allow tool for all future sessions',
|
value: ToolConfirmationOutcome.ProceedAlwaysAndSave,
|
||||||
});
|
key: 'Allow tool for all future sessions',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
label: 'No, suggest changes (esc)',
|
label: 'No, suggest changes (esc)',
|
||||||
@@ -327,6 +339,7 @@ export const ToolConfirmationMessage: React.FC<
|
|||||||
availableTerminalHeight,
|
availableTerminalHeight,
|
||||||
terminalWidth,
|
terminalWidth,
|
||||||
isAlternateBuffer,
|
isAlternateBuffer,
|
||||||
|
allowPermanentApproval,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (confirmationDetails.type === 'edit') {
|
if (confirmationDetails.type === 'edit') {
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
import {
|
||||||
|
renderWithProviders,
|
||||||
|
createMockSettings,
|
||||||
|
} from '../../../test-utils/render.js';
|
||||||
import { describe, it, expect, vi } from 'vitest';
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
import { ToolGroupMessage } from './ToolGroupMessage.js';
|
||||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||||
@@ -376,5 +379,57 @@ describe('<ToolGroupMessage />', () => {
|
|||||||
expect(lastFrame()).toMatchSnapshot();
|
expect(lastFrame()).toMatchSnapshot();
|
||||||
unmount();
|
unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders confirmation with permanent approval enabled', () => {
|
||||||
|
const toolCalls = [
|
||||||
|
createToolCall({
|
||||||
|
callId: 'tool-1',
|
||||||
|
name: 'confirm-tool',
|
||||||
|
status: ToolCallStatus.Confirming,
|
||||||
|
confirmationDetails: {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Confirm Tool',
|
||||||
|
prompt: 'Do you want to proceed?',
|
||||||
|
onConfirm: vi.fn(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const settings = createMockSettings({
|
||||||
|
security: { enablePermanentToolApproval: true },
|
||||||
|
});
|
||||||
|
const { lastFrame, unmount } = renderWithProviders(
|
||||||
|
<ToolGroupMessage {...baseProps} toolCalls={toolCalls} />,
|
||||||
|
{ settings },
|
||||||
|
);
|
||||||
|
expect(lastFrame()).toContain('Allow for all future sessions');
|
||||||
|
expect(lastFrame()).toMatchSnapshot();
|
||||||
|
unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders confirmation with permanent approval disabled', () => {
|
||||||
|
const toolCalls = [
|
||||||
|
createToolCall({
|
||||||
|
callId: 'tool-1',
|
||||||
|
name: 'confirm-tool',
|
||||||
|
status: ToolCallStatus.Confirming,
|
||||||
|
confirmationDetails: {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Confirm Tool',
|
||||||
|
prompt: 'Do you want to proceed?',
|
||||||
|
onConfirm: vi.fn(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const settings = createMockSettings({
|
||||||
|
security: { enablePermanentToolApproval: false },
|
||||||
|
});
|
||||||
|
const { lastFrame, unmount } = renderWithProviders(
|
||||||
|
<ToolGroupMessage {...baseProps} toolCalls={toolCalls} />,
|
||||||
|
{ settings },
|
||||||
|
);
|
||||||
|
expect(lastFrame()).not.toContain('Allow for all future sessions');
|
||||||
|
expect(lastFrame()).toMatchSnapshot();
|
||||||
|
unmount();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+7
-13
@@ -10,8 +10,7 @@ Do you want to proceed?
|
|||||||
|
|
||||||
● 1. Allow once
|
● 1. Allow once
|
||||||
2. Allow for this session
|
2. Allow for this session
|
||||||
3. Allow for all future sessions
|
3. No, suggest changes (esc)
|
||||||
4. No, suggest changes (esc)
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -22,8 +21,7 @@ Do you want to proceed?
|
|||||||
|
|
||||||
● 1. Allow once
|
● 1. Allow once
|
||||||
2. Allow for this session
|
2. Allow for this session
|
||||||
3. Allow for all future sessions
|
3. No, suggest changes (esc)
|
||||||
4. No, suggest changes (esc)
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -53,9 +51,8 @@ Apply this change?
|
|||||||
|
|
||||||
● 1. Allow once
|
● 1. Allow once
|
||||||
2. Allow for this session
|
2. Allow for this session
|
||||||
3. Allow for all future sessions
|
3. Modify with external editor
|
||||||
4. Modify with external editor
|
4. No, suggest changes (esc)
|
||||||
5. No, suggest changes (esc)
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -76,8 +73,7 @@ Allow execution of: 'echo'?
|
|||||||
|
|
||||||
● 1. Allow once
|
● 1. Allow once
|
||||||
2. Allow for this session
|
2. Allow for this session
|
||||||
3. Allow for all future sessions
|
3. No, suggest changes (esc)
|
||||||
4. No, suggest changes (esc)
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -98,8 +94,7 @@ Do you want to proceed?
|
|||||||
|
|
||||||
● 1. Allow once
|
● 1. Allow once
|
||||||
2. Allow for this session
|
2. Allow for this session
|
||||||
3. Allow for all future sessions
|
3. No, suggest changes (esc)
|
||||||
4. No, suggest changes (esc)
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -123,7 +118,6 @@ Allow execution of MCP tool "test-tool" from server "test-server"?
|
|||||||
● 1. Allow once
|
● 1. Allow once
|
||||||
2. Allow tool for this session
|
2. Allow tool for this session
|
||||||
3. Allow all server tools for this session
|
3. Allow all server tools for this session
|
||||||
4. Allow tool for all future sessions
|
4. No, suggest changes (esc)
|
||||||
5. No, suggest changes (esc)
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|||||||
+35
-4
@@ -28,6 +28,39 @@ exports[`<ToolGroupMessage /> > Border Color Logic > uses yellow border when too
|
|||||||
╰──────────────────────────────────────────────────────────────────────────────╯"
|
╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`<ToolGroupMessage /> > Confirmation Handling > renders confirmation with permanent approval disabled 1`] = `
|
||||||
|
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ ? confirm-tool A tool for testing ← │
|
||||||
|
│ │
|
||||||
|
│ Test result │
|
||||||
|
│ Do you want to proceed? │
|
||||||
|
│ │
|
||||||
|
│ Do you want to proceed? │
|
||||||
|
│ │
|
||||||
|
│ ● 1. Allow once │
|
||||||
|
│ 2. Allow for this session │
|
||||||
|
│ 3. No, suggest changes (esc) │
|
||||||
|
│ │
|
||||||
|
╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<ToolGroupMessage /> > Confirmation Handling > renders confirmation with permanent approval enabled 1`] = `
|
||||||
|
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ ? confirm-tool A tool for testing ← │
|
||||||
|
│ │
|
||||||
|
│ Test result │
|
||||||
|
│ Do you want to proceed? │
|
||||||
|
│ │
|
||||||
|
│ Do you want to proceed? │
|
||||||
|
│ │
|
||||||
|
│ ● 1. Allow once │
|
||||||
|
│ 2. Allow for this session │
|
||||||
|
│ 3. Allow for all future sessions │
|
||||||
|
│ 4. No, suggest changes (esc) │
|
||||||
|
│ │
|
||||||
|
╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`<ToolGroupMessage /> > Confirmation Handling > shows confirmation dialog for first confirming tool only 1`] = `
|
exports[`<ToolGroupMessage /> > Confirmation Handling > shows confirmation dialog for first confirming tool only 1`] = `
|
||||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||||
│ ? first-confirm A tool for testing ← │
|
│ ? first-confirm A tool for testing ← │
|
||||||
@@ -39,8 +72,7 @@ exports[`<ToolGroupMessage /> > Confirmation Handling > shows confirmation dialo
|
|||||||
│ │
|
│ │
|
||||||
│ ● 1. Allow once │
|
│ ● 1. Allow once │
|
||||||
│ 2. Allow for this session │
|
│ 2. Allow for this session │
|
||||||
│ 3. Allow for all future sessions │
|
│ 3. No, suggest changes (esc) │
|
||||||
│ 4. No, suggest changes (esc) │
|
|
||||||
│ │
|
│ │
|
||||||
│ │
|
│ │
|
||||||
│ ? second-confirm A tool for testing │
|
│ ? second-confirm A tool for testing │
|
||||||
@@ -123,8 +155,7 @@ exports[`<ToolGroupMessage /> > Golden Snapshots > renders tool call awaiting co
|
|||||||
│ │
|
│ │
|
||||||
│ ● 1. Allow once │
|
│ ● 1. Allow once │
|
||||||
│ 2. Allow for this session │
|
│ 2. Allow for this session │
|
||||||
│ 3. Allow for all future sessions │
|
│ 3. No, suggest changes (esc) │
|
||||||
│ 4. No, suggest changes (esc) │
|
|
||||||
│ │
|
│ │
|
||||||
╰──────────────────────────────────────────────────────────────────────────────╯"
|
╰──────────────────────────────────────────────────────────────────────────────╯"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1200,6 +1200,13 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"enablePermanentToolApproval": {
|
||||||
|
"title": "Allow Permanent Tool Approval",
|
||||||
|
"description": "Enable the \"Allow for all future sessions\" option in tool confirmation dialogs.",
|
||||||
|
"markdownDescription": "Enable the \"Allow for all future sessions\" option in tool confirmation dialogs.\n\n- Category: `Security`\n- Requires restart: `no`\n- Default: `false`",
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"blockGitExtensions": {
|
"blockGitExtensions": {
|
||||||
"title": "Blocks extensions from Git",
|
"title": "Blocks extensions from Git",
|
||||||
"description": "Blocks installing and loading extensions from Git.",
|
"description": "Blocks installing and loading extensions from Git.",
|
||||||
|
|||||||
Reference in New Issue
Block a user