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