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