Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/cli/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ they appear in the UI.
| Folder Trust | `security.folderTrust.enabled` | Setting to track whether Folder trust is enabled. | `true` |
| Enable Environment Variable Redaction | `security.environmentVariableRedaction.enabled` | Enable redaction of environment variables that may contain secrets. | `false` |
| Enable Context-Aware Security | `security.enableConseca` | Enable the context-aware security checker. This feature uses an LLM to dynamically generate and enforce security policies for tool use based on your prompt, providing an additional layer of protection against unintended actions. | `false` |
| Smart Policy Scoping | `security.enableSmartPolicyScoping` | Let Gemini suggest better-scoped policy rules when you approve tools. Displays the suggested scope in the approval question. | `false` |

### Advanced

Expand Down
9 changes: 9 additions & 0 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,15 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false`
- **Requires restart:** Yes

- **`security.enableSmartPolicyScoping`** (boolean):
- **Description:** Let Gemini suggest better-scoped policy rules when you
approve tools. When you select **Allow for this session** or **Allow for all
future sessions**, Gemini analyzes the tool invocation and suggests a
meaningful scope (for example, "read-only git commands") instead of the
default heuristic. The suggested scope appears in the approval question.
- **Default:** `false`
- **Requires restart:** No

#### `advanced`

- **`advanced.autoConfigureMemory`** (boolean):
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ export async function loadCliConfig(
};
},
enableConseca: settings.security?.enableConseca,
enableSmartPolicyScoping: settings.security?.enableSmartPolicyScoping,
});
}

Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1889,6 +1889,16 @@ const SETTINGS_SCHEMA = {
'Enable the context-aware security checker. This feature uses an LLM to dynamically generate and enforce security policies for tool use based on your prompt, providing an additional layer of protection against unintended actions.',
showInDialog: true,
},
enableSmartPolicyScoping: {
type: 'boolean',
label: 'Smart Policy Scoping',
category: 'Security',
requiresRestart: false,
default: false,
description:
'To suggest better-scoped policy rules, allow Gemini to analyze tool approvals. Displays a suggested scope description on approval options.',
showInDialog: true,
},
},
},

Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/ui/components/ToolConfirmationQueue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export const ToolConfirmationQueue: React.FC<ToolConfirmationQueueProps> = ({
<Box flexDirection="column">
<ToolConfirmationMessage
callId={tool.callId}
correlationId={tool.correlationId}
confirmationDetails={tool.confirmationDetails}
config={config}
getPreferredEditor={getPreferredEditor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
ApprovalMode,
hasRedirection,
debugLogger,
MessageBusType,
type PolicySuggestionMessage,
} from '@google/gemini-cli-core';
import { useToolActions } from '../../contexts/ToolActionsContext.js';
import {
Expand Down Expand Up @@ -49,6 +51,7 @@ import { isShellTool } from './ToolShared.js';

export interface ToolConfirmationMessageProps {
callId: string;
correlationId?: string;
confirmationDetails: SerializableConfirmationDetails;
config: Config;
getPreferredEditor: () => EditorType | undefined;
Expand All @@ -62,6 +65,7 @@ export const ToolConfirmationMessage: React.FC<
ToolConfirmationMessageProps
> = ({
callId,
correlationId,
confirmationDetails,
config,
getPreferredEditor,
Expand All @@ -72,6 +76,27 @@ export const ToolConfirmationMessage: React.FC<
}) => {
const keyMatchers = useKeyMatchers();
const { confirm, isDiffingEnabled } = useToolActions();
const smartScoping = config.enableSmartPolicyScoping && !!correlationId;
const [policySuggestion, setPolicySuggestion] = useState<
PolicySuggestionMessage['suggestion'] | null
>(null);

// Subscribe to LLM-generated policy suggestions for this confirmation
useEffect(() => {
if (!correlationId) return;

const messageBus = config.getMessageBus();
const handler = (msg: PolicySuggestionMessage) => {
if (msg.correlationId === correlationId && msg.suggestion?.description) {
setPolicySuggestion(msg.suggestion);
}
};
messageBus.on(MessageBusType.POLICY_SUGGESTION, handler);
return () => {
messageBus.off(MessageBusType.POLICY_SUGGESTION, handler);
};
}, [config, correlationId]);

const [mcpDetailsExpansionState, setMcpDetailsExpansionState] = useState<{
callId: string;
expanded: boolean;
Expand Down Expand Up @@ -738,15 +763,34 @@ export const ToolConfirmationMessage: React.FC<
),
).join(', ');

// When smart scoping is active, show the LLM-suggested scope in
// brackets with the description in parentheses. Otherwise fall back
// to the heuristic root command names.
let scopeDisplay = commandNames;
let scopeDescription = '';
if (smartScoping && policySuggestion) {
if (policySuggestion.commandPrefix) {
scopeDisplay = Array.isArray(policySuggestion.commandPrefix)
? policySuggestion.commandPrefix.join(', ')
: policySuggestion.commandPrefix;
} else if (policySuggestion.argsPattern) {
scopeDisplay = policySuggestion.argsPattern;
}
scopeDescription = policySuggestion.description;
}

const allowQuestion = (
<Text>
Allow execution of{' '}
<Text
color={isShell ? theme.status.warning : undefined}
bold={isShell}
>
[{sanitizeForDisplay(commandNames)}]
[{sanitizeForDisplay(scopeDisplay)}]
</Text>
{scopeDescription ? (
<Text color={theme.text.secondary}> ({scopeDescription})</Text>
) : null}
{'?'}
</Text>
);
Expand Down Expand Up @@ -834,7 +878,15 @@ export const ToolConfirmationMessage: React.FC<
);
} else if (confirmationDetails.type === 'mcp') {
const mcpProps = confirmationDetails;
question = `Allow execution of MCP tool "${sanitizeForDisplay(mcpProps.toolName)}" from server "${sanitizeForDisplay(mcpProps.serverName)}"?`;
const mcpToolDisplay =
smartScoping && policySuggestion?.toolName
? policySuggestion.toolName
: mcpProps.toolName;
const mcpDescription =
smartScoping && policySuggestion?.description
? ` (${policySuggestion.description})`
: '';
question = `Allow execution of MCP tool "${sanitizeForDisplay(mcpToolDisplay)}" from server "${sanitizeForDisplay(mcpProps.serverName)}"${mcpDescription}?`;

bodyContent = (
<Box flexDirection="column">
Expand Down Expand Up @@ -906,6 +958,8 @@ export const ToolConfirmationMessage: React.FC<
activeTheme,
config,
toolName,
smartScoping,
policySuggestion,
]);

const bodyOverflowDirection: 'top' | 'bottom' =
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ export interface ConfigParameters {
agents?: AgentSettings;
}>;
enableConseca?: boolean;
enableSmartPolicyScoping?: boolean;
billing?: {
overageStrategy?: OverageStrategy;
};
Expand Down Expand Up @@ -759,6 +760,7 @@ export class Config implements McpContext, AgentLoopContext {
private readonly question: string | undefined;
private readonly worktreeSettings: WorktreeSettings | undefined;
readonly enableConseca: boolean;
readonly enableSmartPolicyScoping: boolean;

private readonly coreTools: string[] | undefined;
private readonly mainAgentTools: string[] | undefined;
Expand Down Expand Up @@ -1273,6 +1275,7 @@ export class Config implements McpContext, AgentLoopContext {
this.fileExclusions = new FileExclusions(this);
this.eventEmitter = params.eventEmitter;
this.enableConseca = params.enableConseca ?? false;
this.enableSmartPolicyScoping = params.enableSmartPolicyScoping ?? false;

// Initialize Safety Infrastructure
const contextBuilder = new ContextBuilder(this);
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/confirmation-bus/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
import type { ToolCall } from '../scheduler/types.js';
import type { SandboxPermissions } from '../services/sandboxManager.js';
import type { SubagentActivityItem } from '../agents/types.js';
import type { PolicySuggestion } from '../policy/suggestion-generator.js';

export enum MessageBusType {
TOOL_CONFIRMATION_REQUEST = 'tool-confirmation-request',
Expand All @@ -26,6 +27,7 @@ export enum MessageBusType {
ASK_USER_REQUEST = 'ask-user-request',
ASK_USER_RESPONSE = 'ask-user-response',
SUBAGENT_ACTIVITY = 'subagent-activity',
POLICY_SUGGESTION = 'policy-suggestion',
}

export interface ToolCallsUpdateMessage {
Expand Down Expand Up @@ -154,6 +156,12 @@ export interface UpdatePolicy {
modes?: ApprovalMode[];
}

export interface PolicySuggestionMessage {
type: MessageBusType.POLICY_SUGGESTION;
correlationId: string;
suggestion: PolicySuggestion;
}

export interface ToolPolicyRejection {
type: MessageBusType.TOOL_POLICY_REJECTION;
toolCall: FunctionCall;
Expand Down Expand Up @@ -224,6 +232,7 @@ export type Message =
| ToolExecutionSuccess
| ToolExecutionFailure
| UpdatePolicy
| PolicySuggestionMessage
| AskUserRequest
| AskUserResponse
| ToolCallsUpdateMessage
Expand Down
Loading