use serde::{Deserialize, Serialize};
use super::{MatchingRules, PermissionChecker, PermissionDecision, PermissionRule};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermissionPolicy {
#[serde(default)]
pub deny: Vec<PermissionRule>,
#[serde(default)]
pub allow: Vec<PermissionRule>,
#[serde(default)]
pub ask: Vec<PermissionRule>,
#[serde(default = "default_decision")]
pub default_decision: PermissionDecision,
#[serde(default = "default_enabled")]
pub enabled: bool,
}
fn default_decision() -> PermissionDecision {
PermissionDecision::Ask
}
fn default_enabled() -> bool {
true
}
impl Default for PermissionPolicy {
fn default() -> Self {
Self {
deny: Vec::new(),
allow: Vec::new(),
ask: Vec::new(),
default_decision: PermissionDecision::Ask,
enabled: true,
}
}
}
impl PermissionPolicy {
pub fn new() -> Self {
Self::default()
}
pub fn strict() -> Self {
Self {
deny: Vec::new(),
allow: Vec::new(),
ask: Vec::new(),
default_decision: PermissionDecision::Ask,
enabled: true,
}
}
pub fn deny(mut self, rule: &str) -> Self {
self.deny.push(PermissionRule::new(rule));
self
}
pub fn allow(mut self, rule: &str) -> Self {
self.allow.push(PermissionRule::new(rule));
self
}
pub fn ask(mut self, rule: &str) -> Self {
self.ask.push(PermissionRule::new(rule));
self
}
pub fn deny_all(mut self, rules: &[&str]) -> Self {
for rule in rules {
self.deny.push(PermissionRule::new(rule));
}
self
}
pub fn allow_all(mut self, rules: &[&str]) -> Self {
for rule in rules {
self.allow.push(PermissionRule::new(rule));
}
self
}
pub fn ask_all(mut self, rules: &[&str]) -> Self {
for rule in rules {
self.ask.push(PermissionRule::new(rule));
}
self
}
pub fn check(&self, tool_name: &str, args: &serde_json::Value) -> PermissionDecision {
if !self.enabled {
return PermissionDecision::Allow;
}
for rule in &self.deny {
if rule.matches(tool_name, args) {
return PermissionDecision::Deny;
}
}
for rule in &self.allow {
if rule.matches(tool_name, args) {
return PermissionDecision::Allow;
}
}
for rule in &self.ask {
if rule.matches(tool_name, args) {
return PermissionDecision::Ask;
}
}
self.default_decision
}
pub fn is_allowed(&self, tool_name: &str, args: &serde_json::Value) -> bool {
matches!(self.check(tool_name, args), PermissionDecision::Allow)
}
pub fn is_denied(&self, tool_name: &str, args: &serde_json::Value) -> bool {
matches!(self.check(tool_name, args), PermissionDecision::Deny)
}
pub fn requires_confirmation(&self, tool_name: &str, args: &serde_json::Value) -> bool {
matches!(self.check(tool_name, args), PermissionDecision::Ask)
}
pub fn get_matching_rules(&self, tool_name: &str, args: &serde_json::Value) -> MatchingRules {
let mut result = MatchingRules::default();
for rule in &self.deny {
if rule.matches(tool_name, args) {
result.deny.push(rule.rule.clone());
}
}
for rule in &self.allow {
if rule.matches(tool_name, args) {
result.allow.push(rule.rule.clone());
}
}
for rule in &self.ask {
if rule.matches(tool_name, args) {
result.ask.push(rule.rule.clone());
}
}
result
}
}
impl PermissionChecker for PermissionPolicy {
fn check(&self, tool_name: &str, args: &serde_json::Value) -> PermissionDecision {
self.check(tool_name, args)
}
}