claude_agent/tools/
access.rs1use std::collections::HashSet;
4
5#[derive(Debug, Clone, Default)]
7pub enum ToolAccess {
8 None,
10 #[default]
12 All,
13 Only(HashSet<String>),
15 Except(HashSet<String>),
17}
18
19impl ToolAccess {
20 pub fn all() -> Self {
21 Self::All
22 }
23
24 pub fn none() -> Self {
25 Self::None
26 }
27
28 pub fn only(tools: impl IntoIterator<Item = impl Into<String>>) -> Self {
29 Self::Only(tools.into_iter().map(Into::into).collect())
30 }
31
32 pub fn except(tools: impl IntoIterator<Item = impl Into<String>>) -> Self {
33 Self::Except(tools.into_iter().map(Into::into).collect())
34 }
35
36 #[inline]
37 pub fn is_allowed(&self, tool_name: &str) -> bool {
38 match self {
39 Self::None => false,
40 Self::All => true,
41 Self::Only(allowed) => allowed.contains(tool_name),
42 Self::Except(denied) => !denied.contains(tool_name),
43 }
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn test_all_allows_everything() {
53 let access = ToolAccess::all();
54 assert!(access.is_allowed("Read"));
55 assert!(access.is_allowed("Write"));
56 assert!(access.is_allowed("AnythingElse"));
57 }
58
59 #[test]
60 fn test_none_denies_everything() {
61 let access = ToolAccess::none();
62 assert!(!access.is_allowed("Read"));
63 assert!(!access.is_allowed("Write"));
64 }
65
66 #[test]
67 fn test_only_allows_specified() {
68 let access = ToolAccess::only(["Read", "Write"]);
69 assert!(access.is_allowed("Read"));
70 assert!(access.is_allowed("Write"));
71 assert!(!access.is_allowed("Bash"));
72 assert!(!access.is_allowed("Edit"));
73 }
74
75 #[test]
76 fn test_except_denies_specified() {
77 let access = ToolAccess::except(["Bash", "KillShell"]);
78 assert!(access.is_allowed("Read"));
79 assert!(access.is_allowed("Write"));
80 assert!(!access.is_allowed("Bash"));
81 assert!(!access.is_allowed("KillShell"));
82 }
83}