runtimo_core/cmd.rs
1//! Shared command execution helper.
2//!
3//! Provides a single `run_cmd` function used by telemetry and process modules
4//! to avoid duplication. Returns only stdout (stderr is logged separately).
5//!
6//! # Security Warning
7//!
8//! This function uses `sh -c` to execute commands. **NEVER interpolate user input**
9//! into command strings — only hardcoded, trusted commands should be used.
10//! All commands in this codebase are static literals with no user data interpolation.
11//!
12//! Violating this rule enables shell injection attacks. Use [`std::process::Command`]
13//! directly with `.arg()` for user-provided values.
14
15use std::process::Command;
16
17/// Run a shell command and return trimmed stdout.
18///
19/// # Safety
20///
21/// **CRITICAL:** Only use with hardcoded, trusted command strings.
22/// Never interpolate user input, file paths, or any external data into `cmd`.
23/// This function uses `sh -c` which enables shell injection if user data is included.
24///
25/// For user-provided values, use [`std::process::Command`] directly:
26/// ```rust,ignore
27/// std::process::Command::new("cat").arg(user_path).output()
28/// ```
29///
30/// Returns an empty string on failure. Stderr is discarded — callers should
31/// not mix error output with data.
32pub fn run_cmd(cmd: &str) -> String {
33 // SECURITY: This is safe because all callers use hardcoded command literals.
34 // The commands are: "cat /proc/cpuinfo | grep...", "free -h | grep...", etc.
35 // None of them interpolate user input.
36 let output = Command::new("sh")
37 .arg("-c")
38 .arg(cmd)
39 .output()
40 .map(|out| out.stdout)
41 .unwrap_or_default();
42
43 String::from_utf8_lossy(&output).trim().to_string()
44}