1use serde::{Deserialize, Serialize};
5use zeph_tools::AutonomyLevel;
6use zeph_tools::PreExecutionVerifierConfig;
7use zeph_tools::SkillTrustLevel;
8
9use crate::defaults::default_true;
10
11#[derive(Debug, Clone, Deserialize, Serialize)]
15pub struct ScannerConfig {
16 #[serde(default = "default_true")]
22 pub injection_patterns: bool,
23 #[serde(default)]
28 pub capability_escalation_check: bool,
29}
30
31impl Default for ScannerConfig {
32 fn default() -> Self {
33 Self {
34 injection_patterns: true,
35 capability_escalation_check: false,
36 }
37 }
38}
39use crate::rate_limit::RateLimitConfig;
40use crate::sanitizer::GuardrailConfig;
41use crate::sanitizer::{
42 CausalIpiConfig, ContentIsolationConfig, ExfiltrationGuardConfig, MemoryWriteValidationConfig,
43 PiiFilterConfig, ResponseVerificationConfig,
44};
45
46fn default_trust_default_level() -> SkillTrustLevel {
47 SkillTrustLevel::Quarantined
48}
49
50fn default_trust_local_level() -> SkillTrustLevel {
51 SkillTrustLevel::Trusted
52}
53
54fn default_trust_hash_mismatch_level() -> SkillTrustLevel {
55 SkillTrustLevel::Quarantined
56}
57
58fn default_llm_timeout() -> u64 {
59 120
60}
61
62fn default_embedding_timeout() -> u64 {
63 30
64}
65
66fn default_a2a_timeout() -> u64 {
67 30
68}
69
70fn default_max_parallel_tools() -> usize {
71 8
72}
73
74fn default_llm_request_timeout() -> u64 {
75 600
76}
77
78#[derive(Debug, Clone, Deserialize, Serialize)]
79pub struct TrustConfig {
80 #[serde(default = "default_trust_default_level")]
81 pub default_level: SkillTrustLevel,
82 #[serde(default = "default_trust_local_level")]
83 pub local_level: SkillTrustLevel,
84 #[serde(default = "default_trust_hash_mismatch_level")]
85 pub hash_mismatch_level: SkillTrustLevel,
86 #[serde(default = "default_true")]
94 pub scan_on_load: bool,
95 #[serde(default)]
97 pub scanner: ScannerConfig,
98}
99
100impl Default for TrustConfig {
101 fn default() -> Self {
102 Self {
103 default_level: default_trust_default_level(),
104 local_level: default_trust_local_level(),
105 hash_mismatch_level: default_trust_hash_mismatch_level(),
106 scan_on_load: true,
107 scanner: ScannerConfig::default(),
108 }
109 }
110}
111
112#[derive(Debug, Clone, Deserialize, Serialize)]
113pub struct SecurityConfig {
114 #[serde(default = "default_true")]
115 pub redact_secrets: bool,
116 #[serde(default)]
117 pub autonomy_level: AutonomyLevel,
118 #[serde(default)]
119 pub content_isolation: ContentIsolationConfig,
120 #[serde(default)]
121 pub exfiltration_guard: ExfiltrationGuardConfig,
122 #[serde(default)]
124 pub memory_validation: MemoryWriteValidationConfig,
125 #[serde(default)]
127 pub pii_filter: PiiFilterConfig,
128 #[serde(default)]
130 pub rate_limit: RateLimitConfig,
131 #[serde(default)]
133 pub pre_execution_verify: PreExecutionVerifierConfig,
134 #[serde(default)]
136 pub guardrail: GuardrailConfig,
137 #[serde(default)]
139 pub response_verification: ResponseVerificationConfig,
140 #[serde(default)]
142 pub causal_ipi: CausalIpiConfig,
143}
144
145impl Default for SecurityConfig {
146 fn default() -> Self {
147 Self {
148 redact_secrets: true,
149 autonomy_level: AutonomyLevel::default(),
150 content_isolation: ContentIsolationConfig::default(),
151 exfiltration_guard: ExfiltrationGuardConfig::default(),
152 memory_validation: MemoryWriteValidationConfig::default(),
153 pii_filter: PiiFilterConfig::default(),
154 rate_limit: RateLimitConfig::default(),
155 pre_execution_verify: PreExecutionVerifierConfig::default(),
156 guardrail: GuardrailConfig::default(),
157 response_verification: ResponseVerificationConfig::default(),
158 causal_ipi: CausalIpiConfig::default(),
159 }
160 }
161}
162
163#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
164pub struct TimeoutConfig {
165 #[serde(default = "default_llm_timeout")]
166 pub llm_seconds: u64,
167 #[serde(default = "default_llm_request_timeout")]
168 pub llm_request_timeout_secs: u64,
169 #[serde(default = "default_embedding_timeout")]
170 pub embedding_seconds: u64,
171 #[serde(default = "default_a2a_timeout")]
172 pub a2a_seconds: u64,
173 #[serde(default = "default_max_parallel_tools")]
174 pub max_parallel_tools: usize,
175}
176
177impl Default for TimeoutConfig {
178 fn default() -> Self {
179 Self {
180 llm_seconds: default_llm_timeout(),
181 llm_request_timeout_secs: default_llm_request_timeout(),
182 embedding_seconds: default_embedding_timeout(),
183 a2a_seconds: default_a2a_timeout(),
184 max_parallel_tools: default_max_parallel_tools(),
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn trust_config_default_has_scan_on_load_true() {
195 let config = TrustConfig::default();
196 assert!(config.scan_on_load);
197 }
198
199 #[test]
200 fn trust_config_serde_roundtrip_with_scan_on_load() {
201 let config = TrustConfig {
202 default_level: SkillTrustLevel::Quarantined,
203 local_level: SkillTrustLevel::Trusted,
204 hash_mismatch_level: SkillTrustLevel::Quarantined,
205 scan_on_load: false,
206 scanner: ScannerConfig::default(),
207 };
208 let toml = toml::to_string(&config).expect("serialize");
209 let deserialized: TrustConfig = toml::from_str(&toml).expect("deserialize");
210 assert!(!deserialized.scan_on_load);
211 }
212
213 #[test]
214 fn trust_config_missing_scan_on_load_defaults_to_true() {
215 let toml = r#"
216default_level = "quarantined"
217local_level = "trusted"
218hash_mismatch_level = "quarantined"
219"#;
220 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
221 assert!(
222 config.scan_on_load,
223 "missing scan_on_load must default to true"
224 );
225 }
226
227 #[test]
228 fn scanner_config_defaults() {
229 let cfg = ScannerConfig::default();
230 assert!(cfg.injection_patterns);
231 assert!(!cfg.capability_escalation_check);
232 }
233
234 #[test]
235 fn scanner_config_serde_roundtrip() {
236 let cfg = ScannerConfig {
237 injection_patterns: false,
238 capability_escalation_check: true,
239 };
240 let toml = toml::to_string(&cfg).expect("serialize");
241 let back: ScannerConfig = toml::from_str(&toml).expect("deserialize");
242 assert!(!back.injection_patterns);
243 assert!(back.capability_escalation_check);
244 }
245
246 #[test]
247 fn trust_config_scanner_defaults_when_missing() {
248 let toml = r#"
249default_level = "quarantined"
250local_level = "trusted"
251hash_mismatch_level = "quarantined"
252"#;
253 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
254 assert!(config.scanner.injection_patterns);
255 assert!(!config.scanner.capability_escalation_check);
256 }
257}