mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-20 08:42:39 -07:00
address comments
This commit is contained in:
@@ -136,8 +136,6 @@ The manifest file defines the extension's behavior and configuration.
|
||||
also be an array of strings to load multiple context files.
|
||||
- `excludeTools`: An array of tools to block from the model. You can restrict
|
||||
specific arguments, such as `run_shell_command(rm -rf)`.
|
||||
- `policies`: An optional path to a policy TOML file relative to the extension
|
||||
root. See [Policy Engine](#policy-engine) for more information.
|
||||
- `themes`: An optional list of themes provided by the extension. See
|
||||
[Themes](../cli/themes.md) for more information.
|
||||
|
||||
@@ -209,22 +207,16 @@ agent definition files (`.md`) to an `agents/` directory in your extension root.
|
||||
### <a id="policy-engine"></a>Policy Engine
|
||||
|
||||
Extensions can contribute policy rules and safety checkers to the Gemini CLI
|
||||
[Policy Engine](../reference/policy-engine.md). These rules are defined in a
|
||||
TOML file and take effect when the extension is activated.
|
||||
[Policy Engine](../admin/policy-engine.md). These rules are defined in `.toml`
|
||||
files and take effect when the extension is activated.
|
||||
|
||||
To add policies, specify the file path in your `gemini-extension.json`:
|
||||
To add policies, create a `policies/` directory in your extension's root and
|
||||
place your `.toml` policy files inside it. Gemini CLI automatically loads all
|
||||
`.toml` files from this directory.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-secure-extension",
|
||||
"version": "1.0.0",
|
||||
"policies": "policies.toml"
|
||||
}
|
||||
```
|
||||
|
||||
Rules contributed by extensions run in the **User Tier** (Tier 3), alongside
|
||||
user-defined policies. This tier has higher priority than the default or
|
||||
workspace-specific rules but lower priority than admin policies.
|
||||
Rules contributed by extensions run in the **Workspace Tier** (Tier 2),
|
||||
alongside workspace-defined policies. This tier has higher priority than the
|
||||
default rules but lower priority than user or admin policies.
|
||||
|
||||
> **Warning:** For security, Gemini CLI ignores any `allow` decisions or `yolo`
|
||||
> mode configurations in extension policies. This ensures that an extension
|
||||
|
||||
@@ -728,7 +728,7 @@ export class Task {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const errorEvent = event as ServerGeminiErrorEvent; // Type assertion
|
||||
const errorMessage =
|
||||
errorEvent.value?.error.message ?? 'Unknown error from LLM stream';
|
||||
errorEvent.value?.error?.message ?? 'Unknown error from LLM stream';
|
||||
logger.error(
|
||||
'[Task] Received error event from LLM stream:',
|
||||
errorMessage,
|
||||
|
||||
@@ -5,7 +5,7 @@ to the Gemini CLI Policy Engine.
|
||||
|
||||
## Description
|
||||
|
||||
The extension uses a `policies.toml` file to define:
|
||||
The extension uses a `policies/` directory containing `.toml` files to define:
|
||||
|
||||
- A rule that requires user confirmation for `rm -rf` commands.
|
||||
- A rule that denies searching for sensitive files (like `.env`) using `grep`.
|
||||
@@ -13,8 +13,8 @@ The extension uses a `policies.toml` file to define:
|
||||
|
||||
## Structure
|
||||
|
||||
- `gemini-extension.json`: The manifest file that points to the policy file.
|
||||
- `policies.toml`: Contains the policy rules and safety checkers.
|
||||
- `gemini-extension.json`: The manifest file.
|
||||
- `policies/`: Contains the `.toml` policy files.
|
||||
|
||||
## How to use
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"name": "policy-example",
|
||||
"version": "1.0.0",
|
||||
"description": "An example extension demonstrating Policy Engine support.",
|
||||
"policies": "policies.toml"
|
||||
"description": "An example extension demonstrating Policy Engine support."
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import {
|
||||
applyAdminAllowlist,
|
||||
getAdminBlockedMcpServersMessage,
|
||||
CoreToolCallStatus,
|
||||
EXTENSION_POLICY_TIER,
|
||||
WORKSPACE_POLICY_TIER,
|
||||
loadPoliciesFromToml,
|
||||
PolicyDecision,
|
||||
ApprovalMode,
|
||||
@@ -761,74 +761,61 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
let rules: PolicyRule[] | undefined;
|
||||
let checkers: SafetyCheckerRule[] | undefined;
|
||||
|
||||
if (config.policies) {
|
||||
const policyPath = path.join(effectiveExtensionPath, config.policies);
|
||||
const resolvedPolicyPath = path.resolve(policyPath);
|
||||
const resolvedExtensionPath = path.resolve(effectiveExtensionPath);
|
||||
const policyDir = path.join(effectiveExtensionPath, 'policies');
|
||||
if (fs.existsSync(policyDir)) {
|
||||
const result = await loadPoliciesFromToml(
|
||||
[policyDir],
|
||||
() => WORKSPACE_POLICY_TIER,
|
||||
);
|
||||
rules = result.rules;
|
||||
checkers = result.checkers;
|
||||
|
||||
if (!resolvedPolicyPath.startsWith(resolvedExtensionPath)) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute a policy file outside its directory: "${config.policies}". Ignoring for security.`,
|
||||
);
|
||||
} else if (fs.existsSync(policyPath)) {
|
||||
const result = await loadPoliciesFromToml(
|
||||
[policyPath],
|
||||
() => EXTENSION_POLICY_TIER,
|
||||
);
|
||||
rules = result.rules;
|
||||
checkers = result.checkers;
|
||||
|
||||
// Prefix source with extension name to avoid collisions
|
||||
if (rules) {
|
||||
rules = rules.filter((rule) => {
|
||||
// Security: Extensions are not allowed to automatically approve tool calls.
|
||||
// We ignore any rule that is ALLOW.
|
||||
if (rule.decision === PolicyDecision.ALLOW) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute an ALLOW rule for tool "${rule.toolName}". Ignoring this rule for security.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Security: Extensions are not allowed to contribute YOLO mode rules.
|
||||
if (rule.modes?.includes(ApprovalMode.YOLO)) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute a rule for YOLO mode. Ignoring this rule for security.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
rule.source = `Extension (${config.name}): ${rule.source}`;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (checkers) {
|
||||
checkers = checkers.filter((checker) => {
|
||||
// Security: Extensions are not allowed to contribute YOLO mode checkers.
|
||||
if (checker.modes?.includes(ApprovalMode.YOLO)) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute a safety checker for YOLO mode. Ignoring this checker for security.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
checker.source = `Extension (${config.name}): ${checker.source}`;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (result.errors.length > 0) {
|
||||
for (const error of result.errors) {
|
||||
// Prefix source with extension name to avoid collisions
|
||||
if (rules) {
|
||||
rules = rules.filter((rule) => {
|
||||
// Security: Extensions are not allowed to automatically approve tool calls.
|
||||
// We ignore any rule that is ALLOW.
|
||||
if (rule.decision === PolicyDecision.ALLOW) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Error loading policies from ${config.name}: ${error.message}`,
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute an ALLOW rule for tool "${rule.toolName}". Ignoring this rule for security.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Security: Extensions are not allowed to contribute YOLO mode rules.
|
||||
if (rule.modes?.includes(ApprovalMode.YOLO)) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute a rule for YOLO mode. Ignoring this rule for security.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
rule.source = `Extension (${config.name}): ${rule.source}`;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (checkers) {
|
||||
checkers = checkers.filter((checker) => {
|
||||
// Security: Extensions are not allowed to contribute YOLO mode checkers.
|
||||
if (checker.modes?.includes(ApprovalMode.YOLO)) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Extension "${config.name}" attempted to contribute a safety checker for YOLO mode. Ignoring this checker for security.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
checker.source = `Extension (${config.name}): ${checker.source}`;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (result.errors.length > 0) {
|
||||
for (const error of result.errors) {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Error loading policies from ${config.name}: ${error.message}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
debugLogger.warn(
|
||||
`[ExtensionManager] Policy file not found for ${config.name}: ${policyPath}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,6 @@ export interface ExtensionConfig {
|
||||
* These themes will be registered when the extension is activated.
|
||||
*/
|
||||
themes?: CustomTheme[];
|
||||
/**
|
||||
* Path to a policy TOML file relative to the extension root.
|
||||
*/
|
||||
policies?: string;
|
||||
}
|
||||
|
||||
export interface ExtensionUpdateInfo {
|
||||
|
||||
@@ -41,7 +41,7 @@ export const DEFAULT_CORE_POLICIES_DIR = path.join(__dirname, 'policies');
|
||||
export const DEFAULT_POLICY_TIER = 1;
|
||||
export const WORKSPACE_POLICY_TIER = 2;
|
||||
export const USER_POLICY_TIER = 3;
|
||||
export const EXTENSION_POLICY_TIER = 3;
|
||||
export const EXTENSION_POLICY_TIER = WORKSPACE_POLICY_TIER;
|
||||
export const ADMIN_POLICY_TIER = 4;
|
||||
|
||||
// Specific priority offsets and derived priorities for dynamic/settings rules.
|
||||
|
||||
Reference in New Issue
Block a user