tirith_core/rules/
environment.rs1use crate::verdict::{Evidence, Finding, RuleId, Severity};
2
3pub trait EnvSnapshot {
5 fn get(&self, key: &str) -> Option<String>;
6}
7
8pub struct RealEnv;
10
11impl EnvSnapshot for RealEnv {
12 fn get(&self, key: &str) -> Option<String> {
13 std::env::var(key).ok()
14 }
15}
16
17#[cfg(test)]
19pub struct TestEnv {
20 pub vars: std::collections::HashMap<String, String>,
21}
22
23#[cfg(test)]
24impl EnvSnapshot for TestEnv {
25 fn get(&self, key: &str) -> Option<String> {
26 self.vars.get(key).cloned()
27 }
28}
29
30pub fn check(env: &dyn EnvSnapshot) -> Vec<Finding> {
32 let mut findings = Vec::new();
33
34 let proxy_vars = [
35 "HTTP_PROXY",
36 "http_proxy",
37 "HTTPS_PROXY",
38 "https_proxy",
39 "ALL_PROXY",
40 "all_proxy",
41 ];
42
43 for var in &proxy_vars {
44 if let Some(val) = env.get(var) {
45 if !val.is_empty() {
46 findings.push(Finding {
47 rule_id: RuleId::ProxyEnvSet,
48 severity: Severity::Low,
49 title: format!("Proxy environment variable {var} is set"),
50 description: format!(
51 "Environment variable {} is set to '{}'. Traffic may be intercepted by the proxy.",
52 var,
53 redact_value(&val)
54 ),
55 evidence: vec![Evidence::EnvVar {
56 name: var.to_string(),
57 value_preview: redact_value(&val),
58 }],
59 human_view: None,
60 agent_view: None,
61 mitre_id: None,
62 custom_rule_id: None,
63 });
64 }
65 }
66 }
67
68 findings
69}
70
71fn redact_value(val: &str) -> String {
72 let prefix = crate::util::truncate_bytes(val, 20);
73 if prefix.len() == val.len() {
74 val.to_string()
75 } else {
76 format!("{prefix}...")
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_no_proxy() {
86 let env = TestEnv {
87 vars: std::collections::HashMap::new(),
88 };
89 let findings = check(&env);
90 assert!(findings.is_empty());
91 }
92
93 #[test]
94 fn test_http_proxy_set() {
95 let mut vars = std::collections::HashMap::new();
96 vars.insert(
97 "HTTP_PROXY".to_string(),
98 "http://proxy.corp:8080".to_string(),
99 );
100 let env = TestEnv { vars };
101 let findings = check(&env);
102 assert_eq!(findings.len(), 1);
103 assert_eq!(findings[0].rule_id, RuleId::ProxyEnvSet);
104 }
105}