autopulse_service/settings/targets/
command.rs1use crate::settings::rewrite::Rewrite;
2use crate::settings::targets::TargetProcess;
3use autopulse_database::models::ScanEvent;
4use serde::{Deserialize, Serialize};
5use tracing::{debug, error};
6
7#[derive(Serialize, Clone, Deserialize)]
11pub struct Command {
12 pub path: Option<String>,
16 pub timeout: Option<u64>,
20 pub raw: Option<String>,
24 pub rewrite: Option<Rewrite>,
26}
27
28impl Command {
29 pub async fn run(&self, ev: &ScanEvent) -> anyhow::Result<()> {
30 if self.path.is_some() && self.raw.is_some() {
31 return Err(anyhow::anyhow!("command cannot have both path and raw"));
32 }
33
34 let ev_path = ev.get_path(&self.rewrite);
35
36 if let Some(path) = self.path.clone() {
37 let output = tokio::process::Command::new(path.clone())
38 .arg(&ev_path)
39 .output();
40
41 let timeout = self.timeout.unwrap_or(10);
42
43 let output = tokio::time::timeout(std::time::Duration::from_secs(timeout), output)
44 .await
45 .map_err(|_| anyhow::anyhow!("command timed out"))??;
46
47 if !output.status.success() {
48 return Err(anyhow::anyhow!(
49 "command failed with status: {}",
50 output.status
51 ));
52 }
53
54 debug!("command output: {:?}", output);
55 }
56
57 if let Some(raw) = self.raw.clone() {
58 let output = tokio::process::Command::new("sh")
59 .env("FILE_PATH", &ev_path)
60 .arg("-c")
61 .arg(&raw)
62 .output();
63
64 let timeout = self.timeout.unwrap_or(10000);
65
66 let output = tokio::time::timeout(std::time::Duration::from_millis(timeout), output)
67 .await
68 .map_err(|_| anyhow::anyhow!("command timed out"))??;
69
70 if !output.status.success() {
71 return Err(anyhow::anyhow!(
72 "command failed with status: {}",
73 output.status
74 ));
75 }
76
77 debug!("command output: {:?}", output);
78 }
79
80 Ok(())
81 }
82}
83
84impl TargetProcess for Command {
85 async fn process(&self, evs: &[&ScanEvent]) -> anyhow::Result<Vec<String>> {
86 let mut succeeded = Vec::new();
87
88 for ev in evs {
89 if let Err(e) = self.run(ev).await {
90 error!("failed to process '{}': {}", ev.get_path(&self.rewrite), e);
91 } else {
92 succeeded.push(ev.id.clone());
93 }
94 }
95
96 Ok(succeeded)
97 }
98}