Skip to main content

vtcode_config/core/
commands.rs

1use serde::{Deserialize, Serialize};
2
3use crate::constants::commands as command_constants;
4
5/// Command execution configuration
6#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
7#[derive(Debug, Clone, Deserialize, Serialize)]
8pub struct CommandsConfig {
9    /// Commands that can be executed without prompting
10    #[serde(default)]
11    pub allow_list: Vec<String>,
12
13    /// Command prefixes that skip future shell approval prompts when matched
14    #[serde(default)]
15    pub approval_prefixes: Vec<String>,
16
17    /// Additional directories that should be searched/prepended to PATH for command execution
18    #[serde(default = "default_extra_path_entries")]
19    pub extra_path_entries: Vec<String>,
20
21    /// Commands that are always denied
22    #[serde(default)]
23    pub deny_list: Vec<String>,
24
25    /// Glob patterns allowed for shell commands (applies to Bash)
26    #[serde(default)]
27    pub allow_glob: Vec<String>,
28
29    /// Glob patterns denied for shell commands
30    #[serde(default)]
31    pub deny_glob: Vec<String>,
32
33    /// Regex allow patterns for shell commands
34    #[serde(default)]
35    pub allow_regex: Vec<String>,
36
37    /// Regex deny patterns for shell commands
38    #[serde(default)]
39    pub deny_regex: Vec<String>,
40}
41
42const DEFAULT_ALLOW_LIST: &[&str] = &[
43    // File and directory operations
44    "ls",
45    "pwd",
46    "cat",
47    "grep",
48    "find",
49    "head",
50    "tail",
51    "wc",
52    "tree",
53    "stat",
54    "file",
55    "sort",
56    "uniq",
57    "cut",
58    "awk",
59    "sed",
60    // Archive operations
61    "tar",
62    "zip",
63    "unzip",
64    "gzip",
65    "gunzip",
66    // Build tools
67    "make",
68    "cmake",
69    "ninja",
70    "which",
71    "echo",
72    "printf",
73    "date",
74    // Version control
75    "git status",
76    "git diff",
77    "git log",
78    "git show",
79    "git branch",
80    "git remote",
81    // Rust ecosystem
82    "cargo check",
83    "cargo build",
84    "cargo build --release",
85    "cargo build --profile release",
86    "cargo test",
87    "cargo run",
88    "cargo clippy",
89    "cargo fmt",
90    "cargo tree",
91    "cargo metadata",
92    "cargo doc",
93    "rustc",
94    // Python ecosystem
95    "python3",
96    "python3 -m pip install",
97    "python3 -m pytest",
98    "python3 -m build",
99    "python",
100    "pip3",
101    "pip",
102    "virtualenv",
103    // Node.js ecosystem
104    "node",
105    "npm",
106    "npm run build",
107    "npm run test",
108    "npm install",
109    "yarn",
110    "yarn build",
111    "yarn test",
112    "pnpm",
113    "pnpm build",
114    "pnpm test",
115    "bun",
116    "bun install",
117    "bun run",
118    "bun test",
119    "npx",
120    // Go ecosystem
121    "go",
122    "go build",
123    "go test",
124    // C/C++
125    "gcc",
126    "g++",
127    "clang",
128    "clang++",
129    // Java ecosystem
130    "javac",
131    "java",
132    "mvn",
133    "gradle",
134    // Container operations
135    "docker",
136    "docker-compose",
137];
138
139impl Default for CommandsConfig {
140    fn default() -> Self {
141        Self {
142            allow_list: DEFAULT_ALLOW_LIST.iter().map(|s| (*s).into()).collect(),
143            approval_prefixes: Vec::new(),
144            extra_path_entries: default_extra_path_entries(),
145            deny_list: vec![
146                // Dangerous file deletion
147                "rm".into(),
148                "rm -rf /".into(),
149                "rm -rf ~".into(),
150                "rm -rf /*".into(),
151                "rm -rf /home".into(),
152                "rm -rf /usr".into(),
153                "rm -rf /etc".into(),
154                "rm -rf /var".into(),
155                "rm -rf /opt".into(),
156                "rmdir /".into(),
157                "rmdir /home".into(),
158                "rmdir /usr".into(),
159                // System control
160                "shutdown".into(),
161                "reboot".into(),
162                "halt".into(),
163                "poweroff".into(),
164                "init 0".into(),
165                "init 6".into(),
166                "systemctl poweroff".into(),
167                "systemctl reboot".into(),
168                "systemctl halt".into(),
169                // Privilege escalation
170                "sudo rm".into(),
171                "sudo chmod 777".into(),
172                "sudo chown".into(),
173                "sudo passwd".into(),
174                "sudo su".into(),
175                "sudo -i".into(),
176                "sudo bash".into(),
177                "su root".into(),
178                "su -".into(),
179                // Disk operations
180                "format".into(),
181                "fdisk".into(),
182                "mkfs".into(),
183                "mkfs.ext4".into(),
184                "mkfs.xfs".into(),
185                "mkfs.vfat".into(),
186                "dd if=/dev/zero".into(),
187                "dd if=/dev/random".into(),
188                "dd if=/dev/urandom".into(),
189                // Security risks
190                "wget --no-check-certificate".into(),
191                ":(){ :|:& };:".into(), // Fork bomb
192                "nohup bash -i".into(),
193                "exec bash -i".into(),
194                "eval".into(),
195                // Shell configuration
196                "source /etc/bashrc".into(),
197                "source ~/.bashrc".into(),
198                // Permission changes
199                "chmod 777".into(),
200                "chmod -R 777".into(),
201                "chown -R".into(),
202                "chgrp -R".into(),
203                // SSH key destruction
204                "rm ~/.ssh/*".into(),
205                "rm -r ~/.ssh".into(),
206                // Sensitive file access
207                "cat /etc/passwd".into(),
208                "cat /etc/shadow".into(),
209                "cat ~/.ssh/id_*".into(),
210                "tail -f /var/log".into(),
211                "head -n 1 /var/log".into(),
212            ],
213            allow_glob: vec![
214                // Version control
215                "git *".into(),
216                // Rust ecosystem
217                "cargo *".into(),
218                "rustc *".into(),
219                // Python ecosystem
220                "python *".into(),
221                "python3 *".into(),
222                "pip *".into(),
223                "pip3 *".into(),
224                "virtualenv *".into(),
225                // Node.js ecosystem
226                "node *".into(),
227                "npm *".into(),
228                "npm run *".into(),
229                "yarn *".into(),
230                "yarn run *".into(),
231                "pnpm *".into(),
232                "pnpm run *".into(),
233                "bun *".into(),
234                "bun run *".into(),
235                "npx *".into(),
236                // Go
237                "go *".into(),
238                // C/C++
239                "gcc *".into(),
240                "g++ *".into(),
241                "clang *".into(),
242                "clang++ *".into(),
243                // Java
244                "javac *".into(),
245                "java *".into(),
246                "mvn *".into(),
247                "gradle *".into(),
248                // Build tools
249                "make *".into(),
250                "cmake *".into(),
251                "ninja *".into(),
252                // Containers
253                "docker *".into(),
254                "docker-compose *".into(),
255                // Archive tools
256                "tar *".into(),
257                "zip *".into(),
258                "unzip *".into(),
259                "gzip *".into(),
260                "gunzip *".into(),
261            ],
262            deny_glob: vec![
263                // File deletion
264                "rm *".into(),
265                // Privilege escalation
266                "sudo *".into(),
267                // Permission changes
268                "chmod *".into(),
269                "chown *".into(),
270                // Process termination
271                "kill *".into(),
272                "pkill *".into(),
273                // System services
274                "systemctl *".into(),
275                "service *".into(),
276                // Mount operations
277                "mount *".into(),
278                "umount *".into(),
279                // Dangerous container operations
280                "docker run *".into(),
281                // Kubernetes (admin access)
282                "kubectl *".into(),
283            ],
284            allow_regex: vec![
285                // File and text utilities
286                r"^(ls|pwd|cat|grep|find|head|tail|wc|echo|printf|date|tree|stat|file|sort|uniq|cut|awk|sed|tar|zip|unzip|gzip|gunzip)\b".into(),
287                // Version control
288                r"^git (status|diff|log|show|branch|remote)\b".into(),
289                // Rust
290                r"^cargo (check|build|test|run|doc|clippy|fmt|tree|metadata)\b".into(),
291                r"^rustc\b".into(),
292                // Python
293                r"^(python|python3) (-m | )?\w*".into(),
294                r"^(pip|pip3)\b".into(),
295                r"^virtualenv\b".into(),
296                // Node.js
297                r"^(node|npm|yarn|pnpm|bun|npx)\b".into(),
298                // Go
299                r"^go\b".into(),
300                // C/C++
301                r"^(gcc|g\+\+|clang|clang\++)\b".into(),
302                // Java
303                r"^(javac|java)\b".into(),
304                r"^(mvn|gradle)\b".into(),
305                // Build tools
306                r"^(make|cmake)\b".into(),
307                // Containers
308                r"^(docker|docker-compose)\b".into(),
309            ],
310            deny_regex: vec![
311                // Force removal
312                r"rm\s+(-rf|--force)".into(),
313                // Sudo commands
314                r"sudo\s+.*".into(),
315                // Permission changes
316                r"chmod\s+.*".into(),
317                r"chown\s+.*".into(),
318                // Privileged containers
319                r"docker\s+run\s+.*--privileged".into(),
320                // Dangerous kubectl operations
321                r"kubectl\s+(delete|drain|uncordon)".into(),
322            ],
323        }
324    }
325}
326
327fn default_extra_path_entries() -> Vec<String> {
328    command_constants::DEFAULT_EXTRA_PATH_ENTRIES
329        .iter()
330        .map(|value| (*value).into())
331        .collect()
332}