use std::collections::HashMap;
use std::time::Duration;
#[derive(Clone, Debug, serde::Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct ProcessMatcher {
pub exe_contains: String,
#[serde(default)]
pub cmdline_contains: Option<String>,
}
#[derive(Clone)]
pub struct ScaphandreConfig {
pub endpoint: String,
pub scrape_interval: Duration,
pub process_map: HashMap<String, ProcessMatcher>,
pub auth_header: Option<String>,
}
impl std::fmt::Debug for ScaphandreConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ScaphandreConfig")
.field("endpoint", &self.endpoint)
.field("scrape_interval", &self.scrape_interval)
.field("process_map", &self.process_map)
.field(
"auth_header",
&self.auth_header.as_ref().map(|_| "[REDACTED]"),
)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_config() -> ScaphandreConfig {
let mut process_map = HashMap::new();
process_map.insert(
"order-svc".to_string(),
ProcessMatcher {
exe_contains: "bin/java".to_string(),
cmdline_contains: Some("order-svc.jar".to_string()),
},
);
ScaphandreConfig {
endpoint: "http://localhost:8080/metrics".to_string(),
scrape_interval: Duration::from_secs(5),
process_map,
auth_header: Some("Authorization: Bearer super-secret-do-not-log".to_string()),
}
}
#[test]
fn debug_impl_redacts_auth_header() {
let cfg = sample_config();
crate::test_helpers::assert_debug_redacts_secret!(&cfg, "super-secret-do-not-log");
}
#[test]
fn debug_impl_preserves_non_secret_fields() {
let cfg = sample_config();
let dbg = format!("{cfg:?}");
assert!(dbg.contains("endpoint"));
assert!(dbg.contains("http://localhost:8080/metrics"));
assert!(dbg.contains("order-svc"));
assert!(dbg.contains("bin/java"));
assert!(dbg.contains("order-svc.jar"));
}
}