claude_agent/tools/
matcher.rs1pub fn matches_tool_pattern(pattern: &str, tool_name: &str) -> bool {
9 if let Some(base) = pattern.split('(').next() {
10 base == tool_name || pattern == tool_name
11 } else {
12 pattern == tool_name
13 }
14}
15
16pub fn is_tool_allowed(allowed: &[String], tool_name: &str) -> bool {
22 if allowed.is_empty() {
23 return true;
24 }
25 allowed.iter().any(|p| matches_tool_pattern(p, tool_name))
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31
32 #[test]
33 fn test_exact_match() {
34 assert!(matches_tool_pattern("Read", "Read"));
35 assert!(!matches_tool_pattern("Read", "Write"));
36 }
37
38 #[test]
39 fn test_scoped_pattern() {
40 assert!(matches_tool_pattern("Bash(git:*)", "Bash"));
41 assert!(!matches_tool_pattern("Bash(git:*)", "Read"));
42 }
43
44 #[test]
45 fn test_is_tool_allowed_empty() {
46 let allowed: Vec<String> = vec![];
47 assert!(is_tool_allowed(&allowed, "Anything"));
48 }
49
50 #[test]
51 fn test_is_tool_allowed_restricted() {
52 let allowed = vec![
53 "Read".to_string(),
54 "Grep".to_string(),
55 "Bash(git:*)".to_string(),
56 ];
57 assert!(is_tool_allowed(&allowed, "Read"));
58 assert!(is_tool_allowed(&allowed, "Grep"));
59 assert!(is_tool_allowed(&allowed, "Bash"));
60 assert!(!is_tool_allowed(&allowed, "Write"));
61 }
62}