vtcode_config/core/
permissions.rs1use serde::{Deserialize, Serialize};
2
3#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
5#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
6#[serde(rename_all = "snake_case")]
7pub enum PermissionMode {
8 #[default]
10 #[serde(alias = "ask", alias = "suggest")]
11 Default,
12 #[serde(alias = "acceptEdits", alias = "accept-edits", alias = "auto-approved")]
14 AcceptEdits,
15 Plan,
17 #[serde(alias = "dontAsk", alias = "dont-ask")]
19 DontAsk,
20 #[serde(
22 alias = "bypassPermissions",
23 alias = "bypass-permissions",
24 alias = "full-auto"
25 )]
26 BypassPermissions,
27}
28
29#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
31#[derive(Debug, Clone, Deserialize, Serialize)]
32pub struct PermissionsConfig {
33 #[serde(default)]
35 pub default_mode: PermissionMode,
36
37 #[serde(default)]
39 pub allowed_tools: Vec<String>,
40
41 #[serde(default)]
43 pub disallowed_tools: Vec<String>,
44
45 #[serde(default)]
47 pub allow: Vec<String>,
48
49 #[serde(default)]
51 pub ask: Vec<String>,
52
53 #[serde(default)]
55 pub deny: Vec<String>,
56
57 #[serde(default = "default_enabled")]
59 pub enabled: bool,
60
61 #[serde(default = "default_resolve_commands")]
63 pub resolve_commands: bool,
64
65 #[serde(default = "default_audit_enabled")]
67 pub audit_enabled: bool,
68
69 #[serde(default = "default_audit_directory")]
72 pub audit_directory: String,
73
74 #[serde(default = "default_log_allowed_commands")]
76 pub log_allowed_commands: bool,
77
78 #[serde(default = "default_log_denied_commands")]
80 pub log_denied_commands: bool,
81
82 #[serde(default = "default_log_permission_prompts")]
84 pub log_permission_prompts: bool,
85
86 #[serde(default = "default_cache_enabled")]
88 pub cache_enabled: bool,
89
90 #[serde(default = "default_cache_ttl_seconds")]
93 pub cache_ttl_seconds: u64,
94}
95
96#[inline]
97const fn default_enabled() -> bool {
98 true
99}
100
101#[inline]
102const fn default_resolve_commands() -> bool {
103 true
104}
105
106#[inline]
107const fn default_audit_enabled() -> bool {
108 true
109}
110
111const DEFAULT_AUDIT_DIR: &str = "~/.vtcode/audit";
112
113#[inline]
114fn default_audit_directory() -> String {
115 DEFAULT_AUDIT_DIR.into()
116}
117
118#[inline]
119const fn default_log_allowed_commands() -> bool {
120 true
121}
122
123#[inline]
124const fn default_log_denied_commands() -> bool {
125 true
126}
127
128#[inline]
129const fn default_log_permission_prompts() -> bool {
130 true
131}
132
133#[inline]
134const fn default_cache_enabled() -> bool {
135 true
136}
137
138#[inline]
139const fn default_cache_ttl_seconds() -> u64 {
140 300 }
142
143impl Default for PermissionsConfig {
144 fn default() -> Self {
145 Self {
146 default_mode: PermissionMode::default(),
147 allowed_tools: Vec::new(),
148 disallowed_tools: Vec::new(),
149 allow: Vec::new(),
150 ask: Vec::new(),
151 deny: Vec::new(),
152 enabled: default_enabled(),
153 resolve_commands: default_resolve_commands(),
154 audit_enabled: default_audit_enabled(),
155 audit_directory: default_audit_directory(),
156 log_allowed_commands: default_log_allowed_commands(),
157 log_denied_commands: default_log_denied_commands(),
158 log_permission_prompts: default_log_permission_prompts(),
159 cache_enabled: default_cache_enabled(),
160 cache_ttl_seconds: default_cache_ttl_seconds(),
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::{PermissionMode, PermissionsConfig};
168
169 #[test]
170 fn parses_claude_style_mode_aliases() {
171 let config: PermissionsConfig = toml::from_str(
172 r#"
173 default_mode = "acceptEdits"
174 "#,
175 )
176 .expect("permissions config");
177 assert_eq!(config.default_mode, PermissionMode::AcceptEdits);
178
179 let config: PermissionsConfig = toml::from_str(
180 r#"
181 default_mode = "dontAsk"
182 "#,
183 )
184 .expect("permissions config");
185 assert_eq!(config.default_mode, PermissionMode::DontAsk);
186
187 let config: PermissionsConfig = toml::from_str(
188 r#"
189 default_mode = "bypassPermissions"
190 "#,
191 )
192 .expect("permissions config");
193 assert_eq!(config.default_mode, PermissionMode::BypassPermissions);
194 }
195
196 #[test]
197 fn parses_legacy_mode_aliases() {
198 let config: PermissionsConfig = toml::from_str(
199 r#"
200 default_mode = "ask"
201 "#,
202 )
203 .expect("permissions config");
204 assert_eq!(config.default_mode, PermissionMode::Default);
205
206 let config: PermissionsConfig = toml::from_str(
207 r#"
208 default_mode = "auto-approved"
209 "#,
210 )
211 .expect("permissions config");
212 assert_eq!(config.default_mode, PermissionMode::AcceptEdits);
213
214 let config: PermissionsConfig = toml::from_str(
215 r#"
216 default_mode = "full-auto"
217 "#,
218 )
219 .expect("permissions config");
220 assert_eq!(config.default_mode, PermissionMode::BypassPermissions);
221 }
222
223 #[test]
224 fn parses_claude_compat_tool_lists() {
225 let config: PermissionsConfig = toml::from_str(
226 r#"
227 allowed_tools = ["read_file", "unified_search"]
228 disallowed_tools = ["unified_exec"]
229 "#,
230 )
231 .expect("permissions config");
232
233 assert_eq!(
234 config.allowed_tools,
235 vec!["read_file".to_string(), "unified_search".to_string()]
236 );
237 assert_eq!(config.disallowed_tools, vec!["unified_exec".to_string()]);
238 }
239}