harness_core/
permissions.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum PermissionDecision {
12 Allow,
13 AllowOnce,
14 Deny,
15 Ask,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct PermissionQuery {
23 pub tool: String,
24 pub path: String,
25 pub action: String,
26 pub always_patterns: Vec<String>,
27 #[serde(default)]
28 pub metadata: Value,
29}
30
31pub type PermissionHook = Arc<
35 dyn Fn(PermissionQuery) -> Pin<Box<dyn Future<Output = PermissionDecision> + Send>>
36 + Send
37 + Sync,
38>;
39
40#[derive(Clone)]
45pub struct PermissionPolicy {
46 pub roots: Vec<String>,
47 pub sensitive_patterns: Vec<String>,
48 pub hook: Option<PermissionHook>,
49 pub bypass_workspace_guard: bool,
50}
51
52impl PermissionPolicy {
53 pub fn new(roots: impl IntoIterator<Item = String>) -> Self {
54 Self {
55 roots: roots.into_iter().collect(),
56 sensitive_patterns: Vec::new(),
57 hook: None,
58 bypass_workspace_guard: false,
59 }
60 }
61
62 pub fn with_sensitive_patterns(
63 mut self,
64 patterns: impl IntoIterator<Item = String>,
65 ) -> Self {
66 self.sensitive_patterns = patterns.into_iter().collect();
67 self
68 }
69}
70
71impl std::fmt::Debug for PermissionPolicy {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 f.debug_struct("PermissionPolicy")
74 .field("roots", &self.roots)
75 .field("sensitive_patterns", &self.sensitive_patterns)
76 .field("has_hook", &self.hook.is_some())
77 .field("bypass_workspace_guard", &self.bypass_workspace_guard)
78 .finish()
79 }
80}