1use serde::{Deserialize, Serialize};
5use zeph_tools::AutonomyLevel;
6use zeph_tools::PreExecutionVerifierConfig;
7use zeph_tools::SkillTrustLevel;
8
9use crate::defaults::default_true;
10use crate::vigil::VigilConfig;
11
12#[derive(Debug, Clone, Deserialize, Serialize)]
16pub struct ScannerConfig {
17 #[serde(default = "default_true")]
23 pub injection_patterns: bool,
24 #[serde(default)]
29 pub capability_escalation_check: bool,
30}
31
32impl Default for ScannerConfig {
33 fn default() -> Self {
34 Self {
35 injection_patterns: true,
36 capability_escalation_check: false,
37 }
38 }
39}
40use crate::rate_limit::RateLimitConfig;
41use crate::sanitizer::GuardrailConfig;
42use crate::sanitizer::{
43 CausalIpiConfig, ContentIsolationConfig, ExfiltrationGuardConfig, MemoryWriteValidationConfig,
44 PiiFilterConfig, ResponseVerificationConfig,
45};
46
47fn default_trust_default_level() -> SkillTrustLevel {
48 SkillTrustLevel::Quarantined
49}
50
51fn default_trust_local_level() -> SkillTrustLevel {
52 SkillTrustLevel::Trusted
53}
54
55fn default_trust_hash_mismatch_level() -> SkillTrustLevel {
56 SkillTrustLevel::Quarantined
57}
58
59fn default_trust_bundled_level() -> SkillTrustLevel {
60 SkillTrustLevel::Trusted
61}
62
63fn default_llm_timeout() -> u64 {
64 120
65}
66
67fn default_embedding_timeout() -> u64 {
68 30
69}
70
71fn default_a2a_timeout() -> u64 {
72 30
73}
74
75fn default_max_parallel_tools() -> usize {
76 8
77}
78
79fn default_llm_request_timeout() -> u64 {
80 600
81}
82
83#[derive(Debug, Clone, Deserialize, Serialize)]
97pub struct TrustConfig {
98 #[serde(default = "default_trust_default_level")]
100 pub default_level: SkillTrustLevel,
101 #[serde(default = "default_trust_local_level")]
103 pub local_level: SkillTrustLevel,
104 #[serde(default = "default_trust_hash_mismatch_level")]
107 pub hash_mismatch_level: SkillTrustLevel,
108 #[serde(default = "default_trust_bundled_level")]
110 pub bundled_level: SkillTrustLevel,
111 #[serde(default = "default_true")]
119 pub scan_on_load: bool,
120 #[serde(default)]
122 pub scanner: ScannerConfig,
123}
124
125impl Default for TrustConfig {
126 fn default() -> Self {
127 Self {
128 default_level: default_trust_default_level(),
129 local_level: default_trust_local_level(),
130 hash_mismatch_level: default_trust_hash_mismatch_level(),
131 bundled_level: default_trust_bundled_level(),
132 scan_on_load: true,
133 scanner: ScannerConfig::default(),
134 }
135 }
136}
137
138#[derive(Debug, Clone, Deserialize, Serialize)]
156pub struct SecurityConfig {
157 #[serde(default = "default_true")]
160 pub redact_secrets: bool,
161 #[serde(default)]
163 pub autonomy_level: AutonomyLevel,
164 #[serde(default)]
165 pub content_isolation: ContentIsolationConfig,
166 #[serde(default)]
167 pub exfiltration_guard: ExfiltrationGuardConfig,
168 #[serde(default)]
170 pub memory_validation: MemoryWriteValidationConfig,
171 #[serde(default)]
173 pub pii_filter: PiiFilterConfig,
174 #[serde(default)]
176 pub rate_limit: RateLimitConfig,
177 #[serde(default)]
179 pub pre_execution_verify: PreExecutionVerifierConfig,
180 #[serde(default)]
182 pub guardrail: GuardrailConfig,
183 #[serde(default)]
185 pub response_verification: ResponseVerificationConfig,
186 #[serde(default)]
188 pub causal_ipi: CausalIpiConfig,
189 #[serde(default)]
194 pub vigil: VigilConfig,
195}
196
197impl Default for SecurityConfig {
198 fn default() -> Self {
199 Self {
200 redact_secrets: true,
201 autonomy_level: AutonomyLevel::default(),
202 content_isolation: ContentIsolationConfig::default(),
203 exfiltration_guard: ExfiltrationGuardConfig::default(),
204 memory_validation: MemoryWriteValidationConfig::default(),
205 pii_filter: PiiFilterConfig::default(),
206 rate_limit: RateLimitConfig::default(),
207 pre_execution_verify: PreExecutionVerifierConfig::default(),
208 guardrail: GuardrailConfig::default(),
209 response_verification: ResponseVerificationConfig::default(),
210 causal_ipi: CausalIpiConfig::default(),
211 vigil: VigilConfig::default(),
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
230pub struct TimeoutConfig {
231 #[serde(default = "default_llm_timeout")]
233 pub llm_seconds: u64,
234 #[serde(default = "default_llm_request_timeout")]
237 pub llm_request_timeout_secs: u64,
238 #[serde(default = "default_embedding_timeout")]
240 pub embedding_seconds: u64,
241 #[serde(default = "default_a2a_timeout")]
243 pub a2a_seconds: u64,
244 #[serde(default = "default_max_parallel_tools")]
247 pub max_parallel_tools: usize,
248}
249
250impl Default for TimeoutConfig {
251 fn default() -> Self {
252 Self {
253 llm_seconds: default_llm_timeout(),
254 llm_request_timeout_secs: default_llm_request_timeout(),
255 embedding_seconds: default_embedding_timeout(),
256 a2a_seconds: default_a2a_timeout(),
257 max_parallel_tools: default_max_parallel_tools(),
258 }
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265
266 #[test]
267 fn trust_config_default_has_scan_on_load_true() {
268 let config = TrustConfig::default();
269 assert!(config.scan_on_load);
270 }
271
272 #[test]
273 fn trust_config_serde_roundtrip_with_scan_on_load() {
274 let config = TrustConfig {
275 default_level: SkillTrustLevel::Quarantined,
276 local_level: SkillTrustLevel::Trusted,
277 hash_mismatch_level: SkillTrustLevel::Quarantined,
278 bundled_level: SkillTrustLevel::Trusted,
279 scan_on_load: false,
280 scanner: ScannerConfig::default(),
281 };
282 let toml = toml::to_string(&config).expect("serialize");
283 let deserialized: TrustConfig = toml::from_str(&toml).expect("deserialize");
284 assert!(!deserialized.scan_on_load);
285 assert_eq!(deserialized.bundled_level, SkillTrustLevel::Trusted);
286 }
287
288 #[test]
289 fn trust_config_missing_scan_on_load_defaults_to_true() {
290 let toml = r#"
291default_level = "quarantined"
292local_level = "trusted"
293hash_mismatch_level = "quarantined"
294"#;
295 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
296 assert!(
297 config.scan_on_load,
298 "missing scan_on_load must default to true"
299 );
300 }
301
302 #[test]
303 fn trust_config_default_has_bundled_level_trusted() {
304 let config = TrustConfig::default();
305 assert_eq!(config.bundled_level, SkillTrustLevel::Trusted);
306 }
307
308 #[test]
309 fn trust_config_missing_bundled_level_defaults_to_trusted() {
310 let toml = r#"
311default_level = "quarantined"
312local_level = "trusted"
313hash_mismatch_level = "quarantined"
314"#;
315 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
316 assert_eq!(
317 config.bundled_level,
318 SkillTrustLevel::Trusted,
319 "missing bundled_level must default to trusted"
320 );
321 }
322
323 #[test]
324 fn scanner_config_defaults() {
325 let cfg = ScannerConfig::default();
326 assert!(cfg.injection_patterns);
327 assert!(!cfg.capability_escalation_check);
328 }
329
330 #[test]
331 fn scanner_config_serde_roundtrip() {
332 let cfg = ScannerConfig {
333 injection_patterns: false,
334 capability_escalation_check: true,
335 };
336 let toml = toml::to_string(&cfg).expect("serialize");
337 let back: ScannerConfig = toml::from_str(&toml).expect("deserialize");
338 assert!(!back.injection_patterns);
339 assert!(back.capability_escalation_check);
340 }
341
342 #[test]
343 fn trust_config_scanner_defaults_when_missing() {
344 let toml = r#"
345default_level = "quarantined"
346local_level = "trusted"
347hash_mismatch_level = "quarantined"
348"#;
349 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
350 assert!(config.scanner.injection_patterns);
351 assert!(!config.scanner.capability_escalation_check);
352 }
353}