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 });
60 }
61 }
62 }
63
64 findings
65}
66
67fn redact_value(val: &str) -> String {
68 let prefix = crate::util::truncate_bytes(val, 20);
69 if prefix.len() == val.len() {
70 val.to_string()
71 } else {
72 format!("{prefix}...")
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_no_proxy() {
82 let env = TestEnv {
83 vars: std::collections::HashMap::new(),
84 };
85 let findings = check(&env);
86 assert!(findings.is_empty());
87 }
88
89 #[test]
90 fn test_http_proxy_set() {
91 let mut vars = std::collections::HashMap::new();
92 vars.insert(
93 "HTTP_PROXY".to_string(),
94 "http://proxy.corp:8080".to_string(),
95 );
96 let env = TestEnv { vars };
97 let findings = check(&env);
98 assert_eq!(findings.len(), 1);
99 assert_eq!(findings[0].rule_id, RuleId::ProxyEnvSet);
100 }
101}