Addressing feedback and fixing policy issues

This commit is contained in:
Keith Schaab
2026-04-06 23:17:36 +00:00
parent 605b19af1b
commit ee4a3e129f
8 changed files with 36 additions and 17 deletions
@@ -409,11 +409,13 @@ describe('extension tests', () => {
toolName = "deny_tool"
decision = "deny"
priority = 500
modes = ["plan", "default", "autoEdit"]
[[rule]]
toolName = "ask_tool"
decision = "ask_user"
priority = 100
modes = ["plan", "default", "autoEdit"]
`;
fs.writeFileSync(
path.join(policiesDir, 'policies.toml'),
@@ -454,6 +456,7 @@ priority = 100
toolName = "allow_tool"
decision = "allow"
priority = 100
modes = ["plan", "default", "autoEdit"]
[[rule]]
toolName = "yolo_tool"
@@ -7,6 +7,7 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import {
ApprovalMode,
MODES_BY_PERMISSIVENESS,
PolicyDecision,
PolicyEngine,
} from '@google/gemini-cli-core';
@@ -385,6 +386,7 @@ describe('Policy Engine Integration Tests', () => {
toolAnnotations: { readOnlyHint: true },
decision: PolicyDecision.ALLOW,
priority: 10,
modes: MODES_BY_PERMISSIVENESS,
});
const engine = new PolicyEngine(config);
+2
View File
@@ -23,6 +23,7 @@ import {
ExtensionLoader,
AuthType,
ApprovalMode,
MODES_BY_PERMISSIVENESS,
createPolicyEngineConfig,
PolicyDecision,
ToolConfirmationOutcome,
@@ -452,6 +453,7 @@ export class AppRig {
toolName,
decision,
priority,
modes: MODES_BY_PERMISSIVENESS,
source: 'AppRig Override',
});
}
+9 -2
View File
@@ -326,7 +326,8 @@ describe('createPolicyEngineConfig', () => {
(r) =>
r.toolName === 'replace' &&
r.decision === PolicyDecision.ALLOW &&
r.modes?.includes(ApprovalMode.AUTO_EDIT),
r.modes?.includes(ApprovalMode.AUTO_EDIT) &&
!r.argsPattern,
);
expect(rule).toBeDefined();
expect(rule?.priority).toBeCloseTo(1.015, 5);
@@ -421,7 +422,7 @@ describe('createPolicyEngineConfig', () => {
it('should handle complex priority scenarios correctly', async () => {
mockPolicyFile(
nodePath.join(MOCK_DEFAULT_DIR, 'default.toml'),
'[[rule]]\ntoolName = "glob"\ndecision = "allow"\npriority = 50\n',
'[[rule]]\ntoolName = "glob"\ndecision = "allow"\npriority = 50\nmodes = ["default", "plan", "autoEdit", "yolo"]\n',
);
const settings: PolicySettings = {
@@ -543,6 +544,7 @@ describe('createPolicyEngineConfig', () => {
argsPattern = "\\"command\\":\\"git (status|diff|log)\\""
decision = "allow"
priority = 150
modes = ["default", "plan", "autoEdit", "yolo"]
`,
);
@@ -573,10 +575,12 @@ describe('createPolicyEngineConfig', () => {
toolName = "write_file"
decision = "allow"
priority = 10
modes = ["default", "plan", "autoEdit", "yolo"]
[[safety_checker]]
toolName = "write_file"
priority = 10
modes = ["default", "plan", "autoEdit", "yolo"]
[safety_checker.checker]
type = "in-process"
name = "allowed-path"
@@ -610,10 +614,12 @@ required_context = ["environment"]
toolName = "write_file"
decision = "allow"
priority = 10
modes = ["default", "plan", "autoEdit", "yolo"]
[[safety_checker]]
toolName = "write_file"
priority = 10
modes = ["default", "plan", "autoEdit", "yolo"]
[safety_checker.checker]
type = "in-process"
name = "invalid-name"
@@ -639,6 +645,7 @@ name = "invalid-name"
mcpName = "my-server"
decision = "allow"
priority = 150
modes = ["default", "plan", "autoEdit", "yolo"]
`,
);
+1 -4
View File
@@ -584,6 +584,7 @@ function createTomlRule(toolName: string, message: UpdatePolicy): TomlRule {
decision: 'allow',
priority: getAlwaysAllowPriorityFraction(),
toolName,
modes: message.modes ?? MODES_BY_PERMISSIVENESS,
};
if (message.mcpName) {
@@ -600,10 +601,6 @@ function createTomlRule(toolName: string, message: UpdatePolicy): TomlRule {
rule.allowRedirection = message.allowRedirection;
}
if (message.modes) {
rule.modes = message.modes;
}
return rule;
}
+6 -6
View File
@@ -38,7 +38,7 @@ interactive = true
toolName = "replace"
decision = "allow"
priority = 15
modes = ["plan", "default", "autoEdit", "yolo"]
modes = ["autoEdit", "yolo"]
[rule.safety_checker]
type = "in-process"
@@ -63,7 +63,7 @@ interactive = true
toolName = "write_file"
decision = "ask_user"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
modes = ["plan", "default"]
interactive = true
[[rule]]
@@ -77,7 +77,7 @@ interactive = true
toolName = "write_file"
decision = "allow"
priority = 15
modes = ["plan", "default", "autoEdit", "yolo"]
modes = ["autoEdit", "yolo"]
[rule.safety_checker]
type = "in-process"
@@ -88,13 +88,13 @@ required_context = ["environment"]
toolName = "web_fetch"
decision = "allow"
priority = 15
modes = ["plan", "default", "autoEdit", "yolo"]
modes = ["autoEdit", "yolo"]
[[rule]]
toolName = "web_fetch"
decision = "ask_user"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
modes = ["plan", "default"]
interactive = true
# Headless Denial Rule (Priority 10)
@@ -110,5 +110,5 @@ toolName = [
]
decision = "deny"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
modes = ["plan", "default"]
interactive = false
+5 -3
View File
@@ -89,8 +89,10 @@ function ruleMatches(
toolAnnotations?: Record<string, unknown>,
subagent?: string,
): boolean {
// Check if rule applies to current approval mode
if (!rule.modes.includes(currentApprovalMode)) {
// Check if rule applies to current approval mode.
// Legacy rules or those injected manually in tests might not have the modes field.
// If so, we default to matching all modes for backward compatibility.
if (rule.modes && !rule.modes.includes(currentApprovalMode)) {
return false;
}
// Check subagent if specified (only for PolicyRule, SafetyCheckerRule doesn't have it)
@@ -568,7 +570,7 @@ export class PolicyEngine {
if (match) {
debugLogger.debug(
`[PolicyEngine.check] MATCHED rule: toolName=${rule.toolName}, decision=${rule.decision}, priority=${rule.priority}, argsPattern=${rule.argsPattern?.source || 'none'}`,
`[PolicyEngine.check] MATCHED rule: toolName=${rule.toolName}, decision=${rule.decision}, priority=${rule.priority}, source=${rule.source}, argsPattern=${rule.argsPattern?.source || 'none'}`,
);
let ruleDecision = rule.decision;
@@ -91,6 +91,7 @@ describe('Workspace-Level Policies', () => {
toolName = "test_tool"
decision = "allow"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
`; // Tier 1 -> 1.010
}
if (path.includes('user.toml')) {
@@ -98,6 +99,7 @@ priority = 10
toolName = "test_tool"
decision = "deny"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
`; // Tier 4 -> 4.010
}
if (path.includes('workspace.toml')) {
@@ -105,6 +107,7 @@ priority = 10
toolName = "test_tool"
decision = "allow"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
`; // Tier 3 -> 3.010
}
if (path.includes('admin.toml')) {
@@ -112,6 +115,7 @@ priority = 10
toolName = "test_tool"
decision = "deny"
priority = 10
modes = ["plan", "default", "autoEdit", "yolo"]
`; // Tier 5 -> 5.010
}
return '';
@@ -194,7 +198,8 @@ priority = 10
async () => `[[rule]]
toolName="t"
decision="allow"
priority=10`,
priority=10
modes = ["plan", "default", "autoEdit", "yolo"]`,
);
vi.doMock('node:fs/promises', () => ({
@@ -259,7 +264,8 @@ priority=10`,
async () => `[[rule]]
toolName="p_tool"
decision="allow"
priority=500`,
priority=500
modes = ["plan", "default", "autoEdit", "yolo"]`,
);
vi.doMock('node:fs/promises', () => ({