Skip to content

Commit 20a4431

Browse files
committed
Merge branch 'feat/init-command' of https://github.com/getsentry/cli into feat/init-command
2 parents 9fb739d + 184dff6 commit 20a4431

File tree

6 files changed

+1607
-27
lines changed

6 files changed

+1607
-27
lines changed

src/lib/init/local-ops.ts

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,40 +28,76 @@ import type {
2828
* Shell metacharacters that enable chaining, piping, substitution, or redirection.
2929
* All legitimate install commands are simple single commands that don't need these.
3030
*/
31-
const SHELL_METACHARACTER_PATTERNS: Array<{ pattern: string; label: string }> = [
32-
{ pattern: ";", label: "command chaining (;)" },
33-
// Check multi-char operators before single `|` so labels are accurate
34-
{ pattern: "&&", label: "command chaining (&&)" },
35-
{ pattern: "||", label: "command chaining (||)" },
36-
{ pattern: "|", label: "piping (|)" },
37-
{ pattern: "`", label: "command substitution (`)" },
38-
{ pattern: "$(", label: "command substitution ($()" },
39-
{ pattern: "\n", label: "newline" },
40-
{ pattern: "\r", label: "carriage return" },
41-
];
31+
const SHELL_METACHARACTER_PATTERNS: Array<{ pattern: string; label: string }> =
32+
[
33+
{ pattern: ";", label: "command chaining (;)" },
34+
// Check multi-char operators before single `|` so labels are accurate
35+
{ pattern: "&&", label: "command chaining (&&)" },
36+
{ pattern: "||", label: "command chaining (||)" },
37+
{ pattern: "|", label: "piping (|)" },
38+
{ pattern: "`", label: "command substitution (`)" },
39+
{ pattern: "$(", label: "command substitution ($()" },
40+
{ pattern: "\n", label: "newline" },
41+
{ pattern: "\r", label: "carriage return" },
42+
];
43+
44+
const WHITESPACE_RE = /\s+/;
4245

4346
/**
4447
* Executables that should never appear in a package install command.
4548
*/
4649
const BLOCKED_EXECUTABLES = new Set([
4750
// Destructive
48-
"rm", "rmdir", "del",
51+
"rm",
52+
"rmdir",
53+
"del",
4954
// Network/exfil
50-
"curl", "wget", "nc", "ncat", "netcat", "socat", "telnet", "ftp",
55+
"curl",
56+
"wget",
57+
"nc",
58+
"ncat",
59+
"netcat",
60+
"socat",
61+
"telnet",
62+
"ftp",
5163
// Privilege escalation
52-
"sudo", "su", "doas",
64+
"sudo",
65+
"su",
66+
"doas",
5367
// Permissions
54-
"chmod", "chown", "chgrp",
68+
"chmod",
69+
"chown",
70+
"chgrp",
5571
// Process/system
56-
"kill", "killall", "pkill", "shutdown", "reboot", "halt", "poweroff",
72+
"kill",
73+
"killall",
74+
"pkill",
75+
"shutdown",
76+
"reboot",
77+
"halt",
78+
"poweroff",
5779
// Disk
58-
"dd", "mkfs", "fdisk", "mount", "umount",
80+
"dd",
81+
"mkfs",
82+
"fdisk",
83+
"mount",
84+
"umount",
5985
// Remote access
60-
"ssh", "scp", "sftp",
86+
"ssh",
87+
"scp",
88+
"sftp",
6189
// Shells
62-
"bash", "sh", "zsh", "fish", "csh", "dash",
90+
"bash",
91+
"sh",
92+
"zsh",
93+
"fish",
94+
"csh",
95+
"dash",
6396
// Misc dangerous
64-
"eval", "exec", "env", "xargs",
97+
"eval",
98+
"exec",
99+
"env",
100+
"xargs",
65101
]);
66102

67103
/**
@@ -77,16 +113,16 @@ export function validateCommand(command: string): string | undefined {
77113
}
78114

79115
// Layer 2: Block dangerous executables
80-
const firstToken = command.trimStart().split(/\s+/)[0];
116+
const firstToken = command.trimStart().split(WHITESPACE_RE)[0];
81117
if (!firstToken) {
82-
return `Blocked command: empty command`;
118+
return "Blocked command: empty command";
83119
}
84120
const executable = path.basename(firstToken);
85121
if (BLOCKED_EXECUTABLES.has(executable)) {
86122
return `Blocked command: disallowed executable "${executable}" — "${command}"`;
87123
}
88124

89-
return undefined;
125+
return;
90126
}
91127

92128
/**

0 commit comments

Comments
 (0)