hh_cli/permission/
matcher.rs1use crate::config::Settings;
2use crate::core::{ApprovalDecision, ApprovalPolicy};
3use crate::permission::policy::Decision;
4use crate::tool::ToolSchema;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone)]
8pub struct PermissionMatcher {
9 decisions_by_tool: HashMap<String, Decision>,
10}
11
12impl PermissionMatcher {
13 pub fn new(settings: Settings, schemas: &[ToolSchema]) -> Self {
14 let decisions_by_tool = schemas
15 .iter()
16 .map(|schema| {
17 let capability = schema.capability.as_deref().unwrap_or(schema.name.as_str());
18 let raw = capability_policy(&settings, capability);
19 (schema.name.clone(), Decision::parse(raw))
20 })
21 .collect();
22
23 Self { decisions_by_tool }
24 }
25
26 pub fn decision_for_tool(&self, tool_name: &str) -> Decision {
27 self.decisions_by_tool
28 .get(tool_name)
29 .copied()
30 .unwrap_or(Decision::Deny)
31 }
32}
33
34impl ApprovalPolicy for PermissionMatcher {
35 fn decision_for_tool(&self, tool_name: &str) -> ApprovalDecision {
36 match self.decision_for_tool(tool_name) {
37 Decision::Allow => ApprovalDecision::Allow,
38 Decision::Ask => ApprovalDecision::Ask,
39 Decision::Deny => ApprovalDecision::Deny,
40 }
41 }
42}
43
44fn capability_policy<'a>(settings: &'a Settings, capability: &str) -> &'a str {
45 let permission = &settings.permission;
46 if let Some(raw) = permission.capabilities.get(capability) {
47 return raw;
48 }
49
50 match capability {
51 "read" => &permission.read,
52 "list" => &permission.list,
53 "glob" => &permission.glob,
54 "grep" => &permission.grep,
55 "write" => &permission.write,
56 "edit" => &permission.edit,
57 "todo_write" => &permission.todo_write,
58 "todo_read" => &permission.todo_read,
59 "question" => &permission.question,
60 "task" => &permission.task,
61 "bash" => &permission.bash,
62 "web" => &permission.web,
63 _ => "deny",
64 }
65}