@@ -962,75 +962,26 @@
// Per-tool permission rules for granular control over tool actions.
// This setting only applies to the native Zed agent.
"tool_permissions": {
+ // Here are some examples of tool-specific permissions.
"tools": {
- "terminal": {
- "default_mode": "confirm",
- "always_deny": [
- // Dangerous rm commands
- { "pattern": "rm\\s+-rf\\s+(/|\\.\\.|\"|~|\\*)" },
- { "pattern": "rm\\s+-rf\\s*$" },
- // Disk destruction
- { "pattern": "> /dev/sd" },
- { "pattern": "mkfs\\." },
- { "pattern": "dd\\s+if=/dev/(zero|random)" },
- // Fork bomb
- { "pattern": ":\\(\\)\\{\\s*:\\|:&\\s*\\};:" },
- // System files
- { "pattern": "/etc/passwd" },
- { "pattern": "/etc/shadow" },
- // Windows destructive commands
- { "pattern": "del /f /s /q c:\\\\" },
- { "pattern": "format c:" },
- { "pattern": "rd /s /q" },
- ],
- "always_confirm": [
- // File deletion
- { "pattern": "rm\\s" },
- // Destructive git operations
- { "pattern": "git\\s+(reset|clean)\\s+--hard" },
- { "pattern": "git\\s+push\\s+(-f|--force)" },
- // Database operations
- { "pattern": "DROP\\s+TABLE", "case_sensitive": true },
- { "pattern": "DELETE\\s+FROM", "case_sensitive": true },
- // Privileged commands
- { "pattern": "sudo\\s" },
- ],
- },
- "edit_file": {
- "default_mode": "confirm",
- "always_deny": [
- // Secrets and credentials
- { "pattern": "\\.env($|\\.)" },
- { "pattern": "secrets?/" },
- { "pattern": "\\.pem$" },
- { "pattern": "\\.key$" },
- ],
- },
- "delete_path": {
- "default_mode": "confirm",
- "always_deny": [
- // System directories
- { "pattern": "^/etc" },
- { "pattern": "^/usr" },
- { "pattern": "^/bin" },
- { "pattern": "^/sbin" },
- { "pattern": "^/var" },
- { "pattern": "^/boot" },
- { "pattern": "^/root" },
- // Home directory root
- { "pattern": "^~$" },
- { "pattern": "^/Users/[^/]+$" },
- { "pattern": "^/home/[^/]+$" },
- // Git directory
- { "pattern": "\\.git/?$" },
- // Windows system directories
- { "pattern": "^C:\\\\Windows" },
- { "pattern": "^C:\\\\Program Files" },
- ],
- },
- "fetch": {
- "default_mode": "confirm",
- },
+ // "terminal": {
+ // "default_mode": "confirm",
+ // "always_confirm": [
+ // // Destructive git operations
+ // { "pattern": "git\\s+(reset|clean)\\s+--hard" },
+ // { "pattern": "git\\s+push\\s+(-f|--force)" },
+ // ],
+ // },
+ // "edit_file": {
+ // "default_mode": "confirm",
+ // "always_deny": [
+ // // Secrets and credentials
+ // { "pattern": "\\.env($|\\.)" },
+ // { "pattern": "secrets?/" },
+ // { "pattern": "\\.pem$" },
+ // { "pattern": "\\.key$" },
+ // ],
+ // },
},
},
// When enabled, agent edits will be displayed in single-file editors for review
@@ -542,98 +542,6 @@ mod tests {
assert_eq!(permissions.invalid_patterns().len(), 2);
}
- #[test]
- fn test_default_json_tool_permissions_parse() {
- let default_json = include_str!("../../../assets/settings/default.json");
-
- let value: serde_json::Value = serde_json_lenient::from_str(default_json)
- .expect("default.json should be valid JSON with comments");
-
- let agent = value
- .get("agent")
- .expect("default.json should have 'agent' key");
- let tool_permissions = agent
- .get("tool_permissions")
- .expect("agent should have 'tool_permissions' key");
-
- let content: ToolPermissionsContent = serde_json::from_value(tool_permissions.clone())
- .expect("tool_permissions should parse into ToolPermissionsContent");
-
- let permissions = compile_tool_permissions(Some(content));
-
- let terminal = permissions
- .tools
- .get("terminal")
- .expect("terminal tool should be configured");
- assert!(
- !terminal.always_deny.is_empty(),
- "terminal should have deny rules"
- );
- assert!(
- !terminal.always_confirm.is_empty(),
- "terminal should have confirm rules"
- );
- let edit_file = permissions
- .tools
- .get("edit_file")
- .expect("edit_file tool should be configured");
- assert!(
- !edit_file.always_deny.is_empty(),
- "edit_file should have deny rules"
- );
-
- let delete_path = permissions
- .tools
- .get("delete_path")
- .expect("delete_path tool should be configured");
- assert!(
- !delete_path.always_deny.is_empty(),
- "delete_path should have deny rules"
- );
-
- let fetch = permissions
- .tools
- .get("fetch")
- .expect("fetch tool should be configured");
- assert_eq!(
- fetch.default_mode,
- settings::ToolPermissionMode::Confirm,
- "fetch should have confirm as default mode"
- );
- }
-
- #[test]
- fn test_default_deny_rules_match_dangerous_commands() {
- let default_json = include_str!("../../../assets/settings/default.json");
- let value: serde_json::Value = serde_json_lenient::from_str(default_json).unwrap();
- let tool_permissions = value["agent"]["tool_permissions"].clone();
- let content: ToolPermissionsContent = serde_json::from_value(tool_permissions).unwrap();
- let permissions = compile_tool_permissions(Some(content));
-
- let terminal = permissions.tools.get("terminal").unwrap();
-
- let dangerous_commands = [
- "rm -rf /",
- "rm -rf ~",
- "rm -rf ..",
- "mkfs.ext4 /dev/sda",
- "dd if=/dev/zero of=/dev/sda",
- "cat /etc/passwd",
- "cat /etc/shadow",
- "del /f /s /q c:\\",
- "format c:",
- "rd /s /q c:\\windows",
- ];
-
- for cmd in &dangerous_commands {
- assert!(
- terminal.always_deny.iter().any(|r| r.is_match(cmd)),
- "Command '{}' should be blocked by deny rules",
- cmd
- );
- }
- }
-
#[test]
fn test_deny_takes_precedence_over_allow_and_confirm() {
let json = json!({
@@ -739,25 +647,6 @@ mod tests {
);
}
- #[test]
- fn test_default_json_fork_bomb_pattern_matches() {
- let default_json = include_str!("../../../assets/settings/default.json");
- let value: serde_json::Value = serde_json_lenient::from_str(default_json).unwrap();
- let tool_permissions = value["agent"]["tool_permissions"].clone();
- let content: ToolPermissionsContent = serde_json::from_value(tool_permissions).unwrap();
- let permissions = compile_tool_permissions(Some(content));
-
- let terminal = permissions.tools.get("terminal").unwrap();
-
- assert!(
- terminal
- .always_deny
- .iter()
- .any(|r| r.is_match(":(){ :|:& };:")),
- "Default deny rules should block the classic fork bomb"
- );
- }
-
#[test]
fn test_compiled_regex_stores_case_sensitivity() {
let case_sensitive = CompiledRegex::new("test", true).unwrap();