Skip to main content

hh_cli/permission/
matcher.rs

1use 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}