astrid_workspace/
config.rs1use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum WorkspaceMode {
10 #[default]
12 Safe,
13 Guided,
15 Autonomous,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub enum EscapePolicy {
23 #[default]
25 Ask,
26 Deny,
28 Allow,
30}
31
32#[derive(Debug, Clone, Default, Serialize, Deserialize)]
34pub struct AutoAllowPaths {
35 #[serde(default)]
37 pub read: Vec<PathBuf>,
38 #[serde(default)]
40 pub write: Vec<PathBuf>,
41 #[serde(default)]
43 pub patterns: Vec<String>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct WorkspaceConfig {
49 pub root: PathBuf,
51 #[serde(default)]
53 pub mode: WorkspaceMode,
54 #[serde(default)]
56 pub escape_policy: EscapePolicy,
57 #[serde(default)]
59 pub auto_allow: AutoAllowPaths,
60 #[serde(default)]
62 pub never_allow: Vec<PathBuf>,
63 #[serde(default)]
65 pub allow_create_outside: bool,
66 #[serde(default)]
68 pub allow_delete_outside: bool,
69}
70
71impl WorkspaceConfig {
72 #[must_use]
74 pub fn new(root: impl Into<PathBuf>) -> Self {
75 Self {
76 root: root.into(),
77 mode: WorkspaceMode::Safe,
78 escape_policy: EscapePolicy::Ask,
79 auto_allow: AutoAllowPaths::default(),
80 never_allow: vec![
81 PathBuf::from("/etc"),
82 PathBuf::from("/var"),
83 PathBuf::from("/usr"),
84 PathBuf::from("/bin"),
85 PathBuf::from("/sbin"),
86 PathBuf::from("/boot"),
87 PathBuf::from("/root"),
88 ],
89 allow_create_outside: false,
90 allow_delete_outside: false,
91 }
92 }
93
94 #[must_use]
96 pub fn with_mode(mut self, mode: WorkspaceMode) -> Self {
97 self.mode = mode;
98 self
99 }
100
101 #[must_use]
103 pub fn with_escape_policy(mut self, policy: EscapePolicy) -> Self {
104 self.escape_policy = policy;
105 self
106 }
107
108 #[must_use]
110 pub fn allow_read(mut self, path: impl Into<PathBuf>) -> Self {
111 self.auto_allow.read.push(path.into());
112 self
113 }
114
115 #[must_use]
117 pub fn allow_write(mut self, path: impl Into<PathBuf>) -> Self {
118 self.auto_allow.write.push(path.into());
119 self
120 }
121
122 #[must_use]
124 pub fn never_allow(mut self, path: impl Into<PathBuf>) -> Self {
125 self.never_allow.push(path.into());
126 self
127 }
128
129 #[must_use]
131 pub fn is_in_workspace(&self, path: &std::path::Path) -> bool {
132 path.starts_with(&self.root)
133 }
134}
135
136impl Default for WorkspaceConfig {
137 fn default() -> Self {
138 Self::new(".")
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_workspace_config_creation() {
148 let config = WorkspaceConfig::new("/home/user/project");
149 assert_eq!(config.root, PathBuf::from("/home/user/project"));
150 assert_eq!(config.mode, WorkspaceMode::Safe);
151 }
152
153 #[test]
154 fn test_workspace_mode() {
155 let config = WorkspaceConfig::new("/test").with_mode(WorkspaceMode::Autonomous);
156 assert_eq!(config.mode, WorkspaceMode::Autonomous);
157 }
158
159 #[test]
160 fn test_is_in_workspace() {
161 let config = WorkspaceConfig::new("/home/user/project");
162 assert!(config.is_in_workspace(std::path::Path::new("/home/user/project/src/main.rs")));
163 assert!(!config.is_in_workspace(std::path::Path::new("/home/user/other")));
164 }
165}