Skip to main content

telos_agent/tools/command_security/powershell/
static_prefix.rs

1use 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}