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
38impl Default for CommandsConfig {
39    fn default() -> Self {
40        Self {
41            allow_list: vec![
42                "ls".to_string(),
43                "pwd".to_string(),
44                "cat".to_string(),
45                "grep".to_string(),
46                "find".to_string(),
47                "head".to_string(),
48                "tail".to_string(),
49                "wc".to_string(),
50                "git status".to_string(),
51                "git diff".to_string(),
52                "git log".to_string(),
53                "git show".to_string(),
54                "git branch".to_string(),
55                "git remote".to_string(),
56                "cargo check".to_string(),
57                "cargo build".to_string(),
58                "cargo build --release".to_string(),
59                "cargo build --profile release".to_string(),
60                "cargo test".to_string(),
61                "cargo run".to_string(),
62                "cargo clippy".to_string(),
63                "cargo fmt".to_string(),
64                "cargo tree".to_string(),
65                "cargo metadata".to_string(),
66                "cargo doc".to_string(),
67                "cargo nextest run".to_string(),
68                "cargo nextest".to_string(),
69                "rustc".to_string(),
70                "which".to_string(),
71                "echo".to_string(),
72                "printf".to_string(),
73                "date".to_string(),
74                "tree".to_string(),
75                "stat".to_string(),
76                "file".to_string(),
77                "sort".to_string(),
78                "uniq".to_string(),
79                "cut".to_string(),
80                "awk".to_string(),
81                "sed".to_string(),
82                "tar".to_string(),
83                "zip".to_string(),
84                "unzip".to_string(),
85                "gzip".to_string(),
86                "gunzip".to_string(),
87                "make".to_string(),
88                "cmake".to_string(),
89                "ninja".to_string(),
90                "python3".to_string(),
91                "python3 -m pip install".to_string(),
92                "python3 -m pytest".to_string(),
93                "python3 -m build".to_string(),
94                "python".to_string(),
95                "pip3".to_string(),
96                "pip".to_string(),
97                "virtualenv".to_string(),
98                "node".to_string(),
99                "npm".to_string(),
100                "npm run build".to_string(),
101                "npm run test".to_string(),
102                "npm install".to_string(),
103                "yarn".to_string(),
104                "yarn build".to_string(),
105                "yarn test".to_string(),
106                "pnpm".to_string(),
107                "pnpm build".to_string(),
108                "pnpm test".to_string(),
109                "bun".to_string(),
110                "bun install".to_string(),
111                "bun run".to_string(),
112                "bun test".to_string(),
113                "npx".to_string(),
114                "go".to_string(),
115                "go build".to_string(),
116                "go test".to_string(),
117                "gcc".to_string(),
118                "g++".to_string(),
119                "clang".to_string(),
120                "clang++".to_string(),
121                "javac".to_string(),
122                "java".to_string(),
123                "mvn".to_string(),
124                "gradle".to_string(),
125                "docker".to_string(),
126                "docker-compose".to_string(),
127            ],
128            extra_path_entries: default_extra_path_entries(),
129            deny_list: vec![
130                "rm -rf /".to_string(),
131                "rm -rf ~".to_string(),
132                "rm -rf /*".to_string(),
133                "rm -rf /home".to_string(),
134                "rm -rf /usr".to_string(),
135                "rm -rf /etc".to_string(),
136                "rm -rf /var".to_string(),
137                "rm -rf /opt".to_string(),
138                "rmdir /".to_string(),
139                "rmdir /home".to_string(),
140                "rmdir /usr".to_string(),
141                "shutdown".to_string(),
142                "reboot".to_string(),
143                "halt".to_string(),
144                "poweroff".to_string(),
145                "init 0".to_string(),
146                "init 6".to_string(),
147                "systemctl poweroff".to_string(),
148                "systemctl reboot".to_string(),
149                "systemctl halt".to_string(),
150                "sudo rm".to_string(),
151                "sudo chmod 777".to_string(),
152                "sudo chown".to_string(),
153                "sudo passwd".to_string(),
154                "sudo su".to_string(),
155                "sudo -i".to_string(),
156                "sudo bash".to_string(),
157                "su root".to_string(),
158                "su -".to_string(),
159                "format".to_string(),
160                "fdisk".to_string(),
161                "mkfs".to_string(),
162                "mkfs.ext4".to_string(),
163                "mkfs.xfs".to_string(),
164                "mkfs.vfat".to_string(),
165                "dd if=/dev/zero".to_string(),
166                "dd if=/dev/random".to_string(),
167                "dd if=/dev/urandom".to_string(),
168                "wget --no-check-certificate".to_string(),
169                ":(){ :|:& };:".to_string(), // Fork bomb
170                "nohup bash -i".to_string(),
171                "exec bash -i".to_string(),
172                "eval".to_string(),
173                "source /etc/bashrc".to_string(),
174                "source ~/.bashrc".to_string(),
175                "chmod 777".to_string(),
176                "chmod -R 777".to_string(),
177                "chown -R".to_string(),
178                "chgrp -R".to_string(),
179                "rm ~/.ssh/*".to_string(),
180                "rm -r ~/.ssh".to_string(),
181                "cat /etc/passwd".to_string(),
182                "cat /etc/shadow".to_string(),
183                "cat ~/.ssh/id_*".to_string(),
184                "tail -f /var/log".to_string(),
185                "head -n 1 /var/log".to_string(),
186            ],
187            allow_glob: vec![
188                "git *".to_string(),
189                "cargo *".to_string(),
190                "cargo nextest *".to_string(),
191                "rustc *".to_string(),
192                "python *".to_string(),
193                "python3 *".to_string(),
194                "pip *".to_string(),
195                "pip3 *".to_string(),
196                "node *".to_string(),
197                "npm *".to_string(),
198                "npm run *".to_string(),
199                "yarn *".to_string(),
200                "yarn run *".to_string(),
201                "pnpm *".to_string(),
202                "pnpm run *".to_string(),
203                "bun *".to_string(),
204                "bun run *".to_string(),
205                "npx *".to_string(),
206                "go *".to_string(),
207                "gcc *".to_string(),
208                "g++ *".to_string(),
209                "clang *".to_string(),
210                "clang++ *".to_string(),
211                "javac *".to_string(),
212                "java *".to_string(),
213                "mvn *".to_string(),
214                "gradle *".to_string(),
215                "make *".to_string(),
216                "cmake *".to_string(),
217                "ninja *".to_string(),
218                "docker *".to_string(),
219                "docker-compose *".to_string(),
220                "virtualenv *".to_string(),
221                "tar *".to_string(),
222                "zip *".to_string(),
223                "unzip *".to_string(),
224                "gzip *".to_string(),
225                "gunzip *".to_string(),
226            ],
227            deny_glob: vec![
228                "rm *".to_string(),
229                "sudo *".to_string(),
230                "chmod *".to_string(),
231                "chown *".to_string(),
232                "kill *".to_string(),
233                "pkill *".to_string(),
234                "systemctl *".to_string(),
235                "service *".to_string(),
236                "mount *".to_string(),
237                "umount *".to_string(),
238                "docker run *".to_string(),
239                "kubectl *".to_string(),
240            ],
241            allow_regex: vec![
242                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".to_string(),
243                r"^git (status|diff|log|show|branch|remote)\b".to_string(),
244                r"^cargo (check|build|test|run|doc|clippy|fmt|tree|metadata|nextest)\b".to_string(),
245                r"^rustc\b".to_string(),
246                r"^(python|python3) (-m | )?\w*".to_string(),
247                r"^(pip|pip3)\b".to_string(),
248                r"^virtualenv\b".to_string(),
249                r"^(node|npm|yarn|pnpm|bun|npx)\b".to_string(),
250                r"^go\b".to_string(),
251                r"^(gcc|g\+\+|clang|clang\++)\b".to_string(),
252                r"^(javac|java)\b".to_string(),
253                r"^(mvn|gradle)\b".to_string(),
254                r"^(make|cmake)\b".to_string(),
255                r"^(docker|docker-compose)\b".to_string(),
256            ],
257            deny_regex: vec![
258                r"rm\s+(-rf|--force)".to_string(),
259                r"sudo\s+.*".to_string(),
260                r"chmod\s+.*".to_string(),
261                r"chown\s+.*".to_string(),
262                r"docker\s+run\s+.*--privileged".to_string(),
263                r"kubectl\s+(delete|drain|uncordon)".to_string(),
264            ],
265        }
266    }
267}
268
269fn default_extra_path_entries() -> Vec<String> {
270    command_constants::DEFAULT_EXTRA_PATH_ENTRIES
271        .iter()
272        .map(|value| value.to_string())
273        .collect()
274}