feat(policy): map --yolo to allowedTools wildcard policy

This PR maps the `--yolo` flag natively into a wildcard policy array
(`allowedTools: ["*"]`) and removes the concept of `ApprovalMode.YOLO` as a
distinct state in the application, fulfilling issue #11303.

This removes the hardcoded `ApprovalMode.YOLO` state and its associated
UI/bypasses. The `PolicyEngine` now evaluates YOLO purely via data-driven rules.

- Removes `ApprovalMode.YOLO`
- Removes UI toggle (`Ctrl+Y`) and indicators for YOLO
- Removes `yolo.toml`
- Updates A2A server and CLI config logic to translate YOLO into a wildcard tool
- Rewrites policy engine tests to evaluate the wildcard
- Enforces enterprise `disableYoloMode` and `secureModeEnabled` controls
  by actively preventing manual `--allowed-tools=*` bypasses.

Fixes #11303
This commit is contained in:
Spencer
2026-03-19 02:43:14 +00:00
parent 1f5d7014c6
commit 4fde6c014c
86 changed files with 1125 additions and 2387 deletions

View File

@@ -29,12 +29,13 @@ To create your first policy:
```toml
[[rule]]
toolName = "run_shell_command"
commandPrefix = "rm -rf"
decision = "deny"
commandPrefix = "git status"
decision = "allow"
priority = 100
```
3. **Run a command** that triggers the policy (e.g., ask Gemini CLI to
`rm -rf /`). The tool will now be blocked automatically.
`git status`). The tool will now execute automatically without prompting for
confirmation.
## Core concepts
@@ -112,9 +113,7 @@ There are three possible decisions a rule can enforce:
- `ask_user`: The user is prompted to approve or deny the tool call. (In
non-interactive mode, this is treated as `deny`.)
<!-- prettier-ignore -->
> [!NOTE]
> The `deny` decision is the recommended way to exclude tools. The
> **Note:** The `deny` decision is the recommended way to exclude tools. The
> legacy `tools.exclude` setting in `settings.json` is deprecated in favor of
> policy rules with a `deny` decision.
@@ -142,26 +141,25 @@ engine transforms this into a final priority using the following formula:
This system guarantees that:
- Admin policies always override User, Workspace, and Default policies (defined
in policy TOML files).
- Admin policies always override User, Workspace, and Default policies.
- User policies override Workspace and Default policies.
- Workspace policies override Default policies.
- You can still order rules within a single tier with fine-grained control.
For example:
- A `priority: 50` rule in a Default policy TOML becomes `1.050`.
- A `priority: 10` rule in a Workspace policy TOML becomes `2.010`.
- A `priority: 100` rule in a User policy TOML becomes `3.100`.
- A `priority: 20` rule in an Admin policy TOML becomes `4.020`.
- A `priority: 50` rule in a Default policy file becomes `1.050`.
- A `priority: 10` rule in a Workspace policy policy file becomes `2.010`.
- A `priority: 100` rule in a User policy file becomes `3.100`.
- A `priority: 20` rule in an Admin policy file becomes `4.020`.
### Approval modes
Approval modes allow the policy engine to apply different sets of rules based on
the CLI's operational mode. A rule in a TOML policy file can be associated with
one or more modes (e.g., `yolo`, `autoEdit`, `plan`). The rule will only be
active if the CLI is running in one of its specified modes. If a rule has no
modes specified, it is always active.
the CLI's operational mode. A rule can be associated with one or more modes
(e.g., `autoEdit`, `plan`). The rule will only be active if the CLI is running
in one of its specified modes. If a rule has no modes specified, it is always
active.
- `default`: The standard interactive mode where most write tools require
confirmation.
@@ -169,25 +167,6 @@ modes specified, it is always active.
auto-approved.
- `plan`: A strict, read-only mode for research and design. See
[Customizing Plan Mode Policies](../cli/plan-mode.md#customizing-policies).
- `yolo`: A mode where all tools are auto-approved (use with extreme caution).
To maintain the integrity of Plan Mode as a safe research environment,
persistent tool approvals are context-aware. When you select **"Allow for all
future sessions"**, the policy engine explicitly includes the current mode and
all more permissive modes in the hierarchy (`plan` < `default` < `autoEdit` <
`yolo`).
- **Approvals in `plan` mode**: These represent an intentional choice to trust a
tool globally. The resulting rule explicitly includes all modes (`plan`,
`default`, `autoEdit`, and `yolo`).
- **Approvals in other modes**: These only apply to the current mode and those
more permissive. For example:
- An approval granted in **`default`** mode applies to `default`, `autoEdit`,
and `yolo`.
- An approval granted in **`autoEdit`** mode applies to `autoEdit` and `yolo`.
- An approval granted in **`yolo`** mode applies only to `yolo`. This ensures
that trust flows correctly to more permissive environments while maintaining
the safety of more restricted modes like `plan`.
## Rule matching
@@ -197,8 +176,8 @@ outcome.
A rule matches a tool call if all of its conditions are met:
1. **Tool name**: The `toolName` in the TOML rule must match the name of the
tool being called.
1. **Tool name**: The `toolName` in the rule must match the name of the tool
being called.
- **Wildcards**: You can use wildcards like `*`, `mcp_server_*`, or
`mcp_*_toolName` to match multiple tools. See [Tool Name](#tool-name) for
details.
@@ -259,17 +238,15 @@ directory are **ignored**.
- **Linux / macOS:** Must be owned by `root` (UID 0) and NOT writable by group
or others (e.g., `chmod 755`).
- **Windows:** Must be in `C:\ProgramData`. Standard users (`Users`, `Everyone`)
must NOT have `Write`, `Modify`, or `Full Control` permissions. If you see a
security warning, use the folder properties to remove write permissions for
non-admin groups. You may need to "Disable inheritance" in Advanced Security
Settings.
must NOT have `Write`, `Modify`, or `Full Control` permissions. _Tip: If you
see a security warning, use the folder properties to remove write permissions
for non-admin groups. You may need to "Disable inheritance" in Advanced
Security Settings._
<!-- prettier-ignore -->
> [!NOTE]
> Supplemental admin policies (provided via `--admin-policy` or
> `adminPolicyPaths` settings) are **NOT** subject to these strict ownership
> checks, as they are explicitly provided by the user or administrator in their
> current execution context.
**Note:** Supplemental admin policies (provided via `--admin-policy` or
`adminPolicyPaths` settings) are **NOT** subject to these strict ownership
checks, as they are explicitly provided by the user or administrator in their
current execution context.
### TOML rule schema
@@ -280,9 +257,9 @@ Here is a breakdown of the fields available in a TOML policy rule:
# A unique name for the tool, or an array of names.
toolName = "run_shell_command"
# (Optional) The name of a subagent. If provided, the rule only applies to tool
# calls made by this specific subagent.
subagent = "codebase_investigator"
# (Optional) The name of a subagent. If provided, the rule only applies to tool calls
# made by this specific subagent.
subagent = "generalist"
# (Optional) The name of an MCP server. Can be combined with toolName
# to form a composite FQN internally like "mcp_mcpName_toolName".
@@ -296,17 +273,14 @@ toolAnnotations = { readOnlyHint = true }
argsPattern = '"command":"(git|npm)'
# (Optional) A string or array of strings that a shell command must start with.
# This is syntactic sugar for `toolName = "run_shell_command"` and an
# `argsPattern`.
# This is syntactic sugar for `toolName = "run_shell_command"` and an `argsPattern`.
commandPrefix = "git"
# (Optional) A regex to match against the entire shell command.
# This is also syntactic sugar for `toolName = "run_shell_command"`.
# Note: This pattern is tested against the JSON representation of the arguments
# (e.g., `{"command":"<your_command>"}`). Because it prepends `"command":"`,
# it effectively matches from the start of the command.
# Anchors like `^` or `$` apply to the full JSON string,
# so `^` should usually be avoided here.
# Note: This pattern is tested against the JSON representation of the arguments (e.g., `{"command":"<your_command>"}`).
# Because it prepends `"command":"`, it effectively matches from the start of the command.
# Anchors like `^` or `$` apply to the full JSON string, so `^` should usually be avoided here.
# You cannot use commandPrefix and commandRegex in the same rule.
commandRegex = "git (commit|push)"
@@ -316,27 +290,16 @@ decision = "ask_user"
# The priority of the rule, from 0 to 999.
priority = 10
# (Optional) A custom message to display when a tool call is denied by this
# rule. This message is returned to the model and user,
# useful for explaining *why* it was denied.
denyMessage = "Deletion is permanent"
# (Optional) A custom message to display when a tool call is denied by this rule.
# This message is returned to the model and user, useful for explaining *why* it was denied.
deny_message = "Deletion is permanent"
# (Optional) An array of approval modes where this rule is active.
# If omitted or empty, the rule applies to all modes.
modes = ["default", "autoEdit", "yolo"]
modes = ["autoEdit"]
# (Optional) A boolean to restrict the rule to interactive (true) or
# non-interactive (false) environments.
# (Optional) A boolean to restrict the rule to interactive (true) or non-interactive (false) environments.
# If omitted, the rule applies to both.
interactive = true
# (Optional) If true, lets shell commands use redirection operators
# (>, >>, <, <<, <<<). By default, the policy engine asks for confirmation
# when redirection is detected, even if a rule matches the command.
# This permission is granular; it only applies to the specific rule it's
# defined in. In chained commands (e.g., cmd1 > file && cmd2), each
# individual command rule must permit redirection if it's used.
allowRedirection = true
```
### Using arrays (lists)
@@ -384,9 +347,7 @@ using the `mcpName` field. **This is the recommended approach** for defining MCP
policies, as it is much more robust than manually writing Fully Qualified Names
(FQNs) or string wildcards.
<!-- prettier-ignore -->
> [!WARNING]
> Do not use underscores (`_`) in your MCP server names (e.g., use
> **Warning:** Do not use underscores (`_`) in your MCP server names (e.g., use
> `my-server` rather than `my_server`). The policy parser splits Fully Qualified
> Names (`mcp_server_tool`) on the _first_ underscore following the `mcp_`
> prefix. If your server name contains an underscore, the parser will
@@ -421,7 +382,7 @@ server.
mcpName = "untrusted-server"
decision = "deny"
priority = 500
denyMessage = "This server is not trusted by the admin."
deny_message = "This server is not trusted by the admin."
```
**3. Targeting all MCP servers**
@@ -432,12 +393,25 @@ registered MCP server. This is useful for setting category-wide defaults.
```toml
# Ask user for any tool call from any MCP server
[[rule]]
toolName = "*"
mcpName = "*"
decision = "ask_user"
priority = 10
```
**4. Targeting a tool name across all servers**
Use `mcpName = "*"` with a specific `toolName` to target that operation
regardless of which server provides it.
```toml
# Allow the `search` tool across all connected MCP servers
[[rule]]
mcpName = "*"
toolName = "search"
decision = "allow"
priority = 50
```
## Default policies
The Gemini CLI ships with a set of default policies to provide a safe
@@ -449,6 +423,5 @@ out-of-the-box experience.
checked individually.
- **Write tools** (like `write_file`, `run_shell_command`) default to
**`ask_user`**.
- In **`yolo`** mode, a high-priority rule allows all tools.
- In **`autoEdit`** mode, rules allow certain write operations to happen without
prompting.