use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PermissionDecision {
Allow,
AllowOnce,
Deny,
Ask,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermissionQuery {
pub tool: String,
pub path: String,
pub action: String,
pub always_patterns: Vec<String>,
#[serde(default)]
pub metadata: Value,
}
pub type PermissionHook = Arc<
dyn Fn(PermissionQuery) -> Pin<Box<dyn Future<Output = PermissionDecision> + Send>>
+ Send
+ Sync,
>;
#[derive(Clone)]
pub struct PermissionPolicy {
pub roots: Vec<String>,
pub sensitive_patterns: Vec<String>,
pub hook: Option<PermissionHook>,
pub bypass_workspace_guard: bool,
}
impl PermissionPolicy {
pub fn new(roots: impl IntoIterator<Item = String>) -> Self {
Self {
roots: roots.into_iter().collect(),
sensitive_patterns: Vec::new(),
hook: None,
bypass_workspace_guard: false,
}
}
pub fn with_sensitive_patterns(
mut self,
patterns: impl IntoIterator<Item = String>,
) -> Self {
self.sensitive_patterns = patterns.into_iter().collect();
self
}
}
impl std::fmt::Debug for PermissionPolicy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PermissionPolicy")
.field("roots", &self.roots)
.field("sensitive_patterns", &self.sensitive_patterns)
.field("has_hook", &self.hook.is_some())
.field("bypass_workspace_guard", &self.bypass_workspace_guard)
.finish()
}
}