telos_agent/tools/command_security/powershell/
static_prefix.rs1use crate::tools::command_security::powershell::aliases::canonical_command_name;
2use crate::tools::command_security::powershell::parser;
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum PrefixResult {
6 Prefix(String),
7 None,
8 NeedsReview,
9}
10
11pub fn extract_command_prefix(command: &str) -> PrefixResult {
12 let parsed = match parser::parse(command) {
13 Ok(parsed) => parsed,
14 Err(_) => return PrefixResult::NeedsReview,
15 };
16 let commands = parsed.commands();
17 if commands.is_empty() {
18 return PrefixResult::None;
19 }
20 if commands.iter().any(|cmd| cmd.dynamic) {
21 return PrefixResult::NeedsReview;
22 }
23 if commands.len() != 1 {
24 return PrefixResult::NeedsReview;
25 }
26 let name = commands[0].name.trim();
27 if name.is_empty() {
28 PrefixResult::None
29 } else {
30 PrefixResult::Prefix(canonical_command_name(name))
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn extracts_simple_prefix() {
40 assert_eq!(
41 extract_command_prefix("Get-Process -Name pwsh"),
42 PrefixResult::Prefix("Get-Process".into())
43 );
44 }
45
46 #[test]
47 fn extracts_alias_as_canonical_prefix() {
48 assert_eq!(
49 extract_command_prefix("rm ./file.txt"),
50 PrefixResult::Prefix("Remove-Item".into())
51 );
52 }
53
54 #[test]
55 fn dynamic_command_needs_review() {
56 assert_eq!(extract_command_prefix("& ('i' + 'ex') payload"), PrefixResult::NeedsReview);
57 }
58}