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    "read",
74    "date",
75    "sleep",
76    // Version control
77    "git status",
78    "git diff",
79    "git log",
80    "git show",
81    "git branch",
82    "git remote",
83    // Rust ecosystem
84    "cargo check",
85    "cargo build",
86    "cargo build --release",
87    "cargo build --profile release",
88    "cargo test",
89    "cargo run",
90    "cargo clippy",
91    "cargo fmt",
92    "cargo tree",
93    "cargo metadata",
94    "cargo doc",
95    "rustc",
96    // Python ecosystem
97    "python3",
98    "python3 -m pip install",
99    "python3 -m pytest",
100    "python3 -m build",
101    "python",
102    "pip3",
103    "pip",
104    "virtualenv",
105    // Node.js ecosystem
106    "node",
107    "npm",
108    "npm run build",
109    "npm run test",
110    "npm install",
111    "yarn",
112    "yarn build",
113    "yarn test",
114    "pnpm",
115    "pnpm build",
116    "pnpm test",
117    "bun",
118    "bun install",
119    "bun run",
120    "bun test",
121    "npx",
122    // Go ecosystem
123    "go",
124    "go build",
125    "go test",
126    // C/C++
127    "gcc",
128    "g++",
129    "clang",
130    "clang++",
131    // Java ecosystem
132    "javac",
133    "java",
134    "mvn",
135    "gradle",
136    // Container operations
137    "docker",
138    "docker-compose",
139];
140
141impl Default for CommandsConfig {
142    fn default() -> Self {
143        Self {
144            allow_list: DEFAULT_ALLOW_LIST.iter().map(|s| (*s).into()).collect(),
145            approval_prefixes: Vec::new(),
146            extra_path_entries: default_extra_path_entries(),
147            deny_list: vec![
148                // Dangerous file deletion
149                "rm".into(),
150                "rm -rf /".into(),
151                "rm -rf ~".into(),
152                "rm -rf /*".into(),
153                "rm -rf /home".into(),
154                "rm -rf /usr".into(),
155                "rm -rf /etc".into(),
156                "rm -rf /var".into(),
157                "rm -rf /opt".into(),
158                "rmdir /".into(),
159                "rmdir /home".into(),
160                "rmdir /usr".into(),
161                // System control
162                "shutdown".into(),
163                "reboot".into(),
164                "halt".into(),
165                "poweroff".into(),
166                "init 0".into(),
167                "init 6".into(),
168                "systemctl poweroff".into(),
169                "systemctl reboot".into(),
170                "systemctl halt".into(),
171                // Privilege escalation
172                "sudo rm".into(),
173                "sudo chmod 777".into(),
174                "sudo chown".into(),
175                "sudo passwd".into(),
176                "sudo su".into(),
177                "sudo -i".into(),
178                "sudo bash".into(),
179                "su root".into(),
180                "su -".into(),
181                // Disk operations
182                "format".into(),
183                "fdisk".into(),
184                "mkfs".into(),
185                "mkfs.ext4".into(),
186                "mkfs.xfs".into(),
187                "mkfs.vfat".into(),
188                "dd if=/dev/zero".into(),
189                "dd if=/dev/random".into(),
190                "dd if=/dev/urandom".into(),
191                // Security risks
192                "wget --no-check-certificate".into(),
193                ":(){ :|:& };:".into(), // Fork bomb
194                "nohup bash -i".into(),
195                "exec bash -i".into(),
196                "eval".into(),
197                // Shell configuration
198                "source /etc/bashrc".into(),
199                "source ~/.bashrc".into(),
200                // Permission changes
201                "chmod 777".into(),
202                "chmod -R 777".into(),
203                "chown -R".into(),
204                "chgrp -R".into(),
205                // SSH key destruction
206                "rm ~/.ssh/*".into(),
207                "rm -r ~/.ssh".into(),
208                // Sensitive file access
209                "cat /etc/passwd".into(),
210                "cat /etc/shadow".into(),
211                "cat ~/.ssh/id_*".into(),
212                "tail -f /var/log".into(),
213                "head -n 1 /var/log".into(),
214            ],
215            allow_glob: vec![
216                // Version control
217                "git *".into(),
218                // Rust ecosystem
219                "cargo *".into(),
220                "rustc *".into(),
221                // Python ecosystem
222                "python *".into(),
223                "python3 *".into(),
224                "pip *".into(),
225                "pip3 *".into(),
226                "virtualenv *".into(),
227                // Node.js ecosystem
228                "node *".into(),
229                "npm *".into(),
230                "npm run *".into(),
231                "yarn *".into(),
232                "yarn run *".into(),
233                "pnpm *".into(),
234                "pnpm run *".into(),
235                "bun *".into(),
236                "bun run *".into(),
237                "npx *".into(),
238                // Go
239                "go *".into(),
240                // C/C++
241                "gcc *".into(),
242                "g++ *".into(),
243                "clang *".into(),
244                "clang++ *".into(),
245                // Java
246                "javac *".into(),
247                "java *".into(),
248                "mvn *".into(),
249                "gradle *".into(),
250                // Build tools
251                "make *".into(),
252                "cmake *".into(),
253                "ninja *".into(),
254                // Containers
255                "docker *".into(),
256                "docker-compose *".into(),
257                // Archive tools
258                "tar *".into(),
259                "zip *".into(),
260                "unzip *".into(),
261                "gzip *".into(),
262                "gunzip *".into(),
263            ],
264            deny_glob: vec![
265                // File deletion
266                "rm *".into(),
267                // Privilege escalation
268                "sudo *".into(),
269                // Permission changes
270                "chmod *".into(),
271                "chown *".into(),
272                // Process termination
273                "kill *".into(),
274                "pkill *".into(),
275                // System services
276                "systemctl *".into(),
277                "service *".into(),
278                // Mount operations
279                "mount *".into(),
280                "umount *".into(),
281                // Dangerous container operations
282                "docker run *".into(),
283                // Kubernetes (admin access)
284                "kubectl *".into(),
285            ],
286            allow_regex: vec![
287                // File and text utilities
288                r"^(ls|pwd|cat|grep|find|head|tail|wc|echo|printf|read|date|sleep|tree|stat|file|sort|uniq|cut|awk|sed|tar|zip|unzip|gzip|gunzip)\b".into(),
289                // Version control
290                r"^git (status|diff|log|show|branch|remote)\b".into(),
291                // Rust
292                r"^cargo (check|build|test|run|doc|clippy|fmt|tree|metadata)\b".into(),
293                r"^rustc\b".into(),
294                // Python
295                r"^(python|python3) (-m | )?\w*".into(),
296                r"^(pip|pip3)\b".into(),
297                r"^virtualenv\b".into(),
298                // Node.js
299                r"^(node|npm|yarn|pnpm|bun|npx)\b".into(),
300                // Go
301                r"^go\b".into(),
302                // C/C++
303                r"^(gcc|g\+\+|clang|clang\++)\b".into(),
304                // Java
305                r"^(javac|java)\b".into(),
306                r"^(mvn|gradle)\b".into(),
307                // Build tools
308                r"^(make|cmake)\b".into(),
309                // Containers
310                r"^(docker|docker-compose)\b".into(),
311            ],
312            deny_regex: vec![
313                // Force removal
314                r"rm\s+(-rf|--force)".into(),
315                // Sudo commands
316                r"sudo\s+.*".into(),
317                // Permission changes
318                r"chmod\s+.*".into(),
319                r"chown\s+.*".into(),
320                // Privileged containers
321                r"docker\s+run\s+.*--privileged".into(),
322                // Dangerous kubectl operations
323                r"kubectl\s+(delete|drain|uncordon)".into(),
324            ],
325        }
326    }
327}
328
329fn default_extra_path_entries() -> Vec<String> {
330    command_constants::DEFAULT_EXTRA_PATH_ENTRIES
331        .iter()
332        .map(|value| (*value).into())
333        .collect()
334}