(command: string)
| 159 | * 'chmod 755 file' → null (number, not a subcommand) |
| 160 | */ |
| 161 | export function getSimpleCommandPrefix(command: string): string | null { |
| 162 | const tokens = command.trim().split(/\s+/).filter(Boolean) |
| 163 | if (tokens.length === 0) return null |
| 164 | |
| 165 | // Skip env var assignments (VAR=value) at the start, but only if they are |
| 166 | // in SAFE_ENV_VARS (or ANT_ONLY_SAFE_ENV_VARS for ant users). If a non-safe |
| 167 | // env var is encountered, return null to fall back to exact match. This |
| 168 | // prevents generating prefix rules like Bash(npm run:*) that can never match |
| 169 | // at allow-rule check time, because stripSafeWrappers only strips safe vars. |
| 170 | let i = 0 |
| 171 | while (i < tokens.length && ENV_VAR_ASSIGN_RE.test(tokens[i]!)) { |
| 172 | const varName = tokens[i]!.split('=')[0]! |
| 173 | const isAntOnlySafe = |
| 174 | process.env.USER_TYPE === 'ant' && ANT_ONLY_SAFE_ENV_VARS.has(varName) |
| 175 | if (!SAFE_ENV_VARS.has(varName) && !isAntOnlySafe) { |
| 176 | return null |
| 177 | } |
| 178 | i++ |
| 179 | } |
| 180 | |
| 181 | const remaining = tokens.slice(i) |
| 182 | if (remaining.length < 2) return null |
| 183 | const subcmd = remaining[1]! |
| 184 | // Second token must look like a subcommand (e.g., "commit", "run", "compose"), |
| 185 | // not a flag (-rf), filename (file.txt), path (/tmp), URL, or number (755). |
| 186 | if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(subcmd)) return null |
| 187 | return remaining.slice(0, 2).join(' ') |
| 188 | } |
| 189 | |
| 190 | // Bare-prefix suggestions like `bash:*` or `sh:*` would allow arbitrary code |
| 191 | // via `-c`. Wrapper suggestions like `env:*` or `sudo:*` would do the same: |
no test coverage detected