piko-permissions 0.1.1

Permission and access control for PikoClaw
Documentation
use crate::rules::{CompiledRules, Rule, RuleDecision};
use piko_config::config::PermissionMode;
use std::collections::HashMap;

pub struct PermissionPolicy {
    tool_modes: HashMap<String, PermissionMode>,
    default_mode: PermissionMode,
    compiled_rules: CompiledRules,
}

impl PermissionPolicy {
    pub fn new(
        tool_modes: HashMap<String, PermissionMode>,
        default_mode: PermissionMode,
        rules: &[Rule],
    ) -> Result<Self, globset::Error> {
        let compiled_rules = CompiledRules::compile(rules)?;
        Ok(Self {
            tool_modes,
            default_mode,
            compiled_rules,
        })
    }

    pub fn from_config(config: &piko_config::config::PermissionsConfig) -> Self {
        let mut tool_modes = HashMap::new();
        tool_modes.insert("bash".to_string(), config.bash.clone());
        tool_modes.insert("file_write".to_string(), config.file_write.clone());
        tool_modes.insert("file_read".to_string(), config.file_read.clone());
        tool_modes.insert("web_fetch".to_string(), config.web_fetch.clone());

        let rules: Vec<Rule> = config
            .rules
            .iter()
            .map(|r| Rule {
                tool: r.tool.clone(),
                pattern: r.pattern.clone(),
                decision: match r.decision {
                    PermissionMode::Allow => RuleDecision::Allow,
                    PermissionMode::Deny => RuleDecision::Deny,
                    PermissionMode::Ask => RuleDecision::Ask,
                },
            })
            .collect();

        let compiled_rules =
            CompiledRules::compile(&rules).unwrap_or_else(|_| CompiledRules::compile(&[]).unwrap());

        Self {
            tool_modes,
            default_mode: config.default_mode.clone(),
            compiled_rules,
        }
    }

    pub fn lookup(&self, tool: &str, input_str: &str) -> &PermissionMode {
        if let Some(rule_decision) = self.compiled_rules.check(tool, input_str) {
            return match rule_decision {
                RuleDecision::Allow => &PermissionMode::Allow,
                RuleDecision::Deny => &PermissionMode::Deny,
                RuleDecision::Ask => &PermissionMode::Ask,
            };
        }

        self.tool_modes.get(tool).unwrap_or(&self.default_mode)
    }
}