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
83fn default_context_prep_timeout() -> u64 {
84 30
85}
86
87fn default_no_providers_backoff_secs() -> u64 {
88 2
89}
90
91#[derive(Debug, Clone, Deserialize, Serialize)]
105pub struct TrustConfig {
106 #[serde(default = "default_trust_default_level")]
108 pub default_level: SkillTrustLevel,
109 #[serde(default = "default_trust_local_level")]
111 pub local_level: SkillTrustLevel,
112 #[serde(default = "default_trust_hash_mismatch_level")]
115 pub hash_mismatch_level: SkillTrustLevel,
116 #[serde(default = "default_trust_bundled_level")]
118 pub bundled_level: SkillTrustLevel,
119 #[serde(default = "default_true")]
127 pub scan_on_load: bool,
128 #[serde(default)]
130 pub scanner: ScannerConfig,
131}
132
133impl Default for TrustConfig {
134 fn default() -> Self {
135 Self {
136 default_level: default_trust_default_level(),
137 local_level: default_trust_local_level(),
138 hash_mismatch_level: default_trust_hash_mismatch_level(),
139 bundled_level: default_trust_bundled_level(),
140 scan_on_load: true,
141 scanner: ScannerConfig::default(),
142 }
143 }
144}
145
146#[derive(Debug, Clone, Deserialize, Serialize)]
164pub struct SecurityConfig {
165 #[serde(default = "default_true")]
168 pub redact_secrets: bool,
169 #[serde(default)]
171 pub autonomy_level: AutonomyLevel,
172 #[serde(default)]
173 pub content_isolation: ContentIsolationConfig,
174 #[serde(default)]
175 pub exfiltration_guard: ExfiltrationGuardConfig,
176 #[serde(default)]
178 pub memory_validation: MemoryWriteValidationConfig,
179 #[serde(default)]
181 pub pii_filter: PiiFilterConfig,
182 #[serde(default)]
184 pub rate_limit: RateLimitConfig,
185 #[serde(default)]
187 pub pre_execution_verify: PreExecutionVerifierConfig,
188 #[serde(default)]
190 pub guardrail: GuardrailConfig,
191 #[serde(default)]
193 pub response_verification: ResponseVerificationConfig,
194 #[serde(default)]
196 pub causal_ipi: CausalIpiConfig,
197 #[serde(default)]
202 pub vigil: VigilConfig,
203}
204
205impl Default for SecurityConfig {
206 fn default() -> Self {
207 Self {
208 redact_secrets: true,
209 autonomy_level: AutonomyLevel::default(),
210 content_isolation: ContentIsolationConfig::default(),
211 exfiltration_guard: ExfiltrationGuardConfig::default(),
212 memory_validation: MemoryWriteValidationConfig::default(),
213 pii_filter: PiiFilterConfig::default(),
214 rate_limit: RateLimitConfig::default(),
215 pre_execution_verify: PreExecutionVerifierConfig::default(),
216 guardrail: GuardrailConfig::default(),
217 response_verification: ResponseVerificationConfig::default(),
218 causal_ipi: CausalIpiConfig::default(),
219 vigil: VigilConfig::default(),
220 }
221 }
222}
223
224#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
238pub struct TimeoutConfig {
239 #[serde(default = "default_llm_timeout")]
241 pub llm_seconds: u64,
242 #[serde(default = "default_llm_request_timeout")]
245 pub llm_request_timeout_secs: u64,
246 #[serde(default = "default_embedding_timeout")]
248 pub embedding_seconds: u64,
249 #[serde(default = "default_a2a_timeout")]
251 pub a2a_seconds: u64,
252 #[serde(default = "default_max_parallel_tools")]
255 pub max_parallel_tools: usize,
256 #[serde(default = "default_context_prep_timeout")]
263 pub context_prep_timeout_secs: u64,
264 #[serde(default = "default_no_providers_backoff_secs")]
268 pub no_providers_backoff_secs: u64,
269}
270
271impl Default for TimeoutConfig {
272 fn default() -> Self {
273 Self {
274 llm_seconds: default_llm_timeout(),
275 llm_request_timeout_secs: default_llm_request_timeout(),
276 embedding_seconds: default_embedding_timeout(),
277 a2a_seconds: default_a2a_timeout(),
278 max_parallel_tools: default_max_parallel_tools(),
279 context_prep_timeout_secs: default_context_prep_timeout(),
280 no_providers_backoff_secs: default_no_providers_backoff_secs(),
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn trust_config_default_has_scan_on_load_true() {
291 let config = TrustConfig::default();
292 assert!(config.scan_on_load);
293 }
294
295 #[test]
296 fn trust_config_serde_roundtrip_with_scan_on_load() {
297 let config = TrustConfig {
298 default_level: SkillTrustLevel::Quarantined,
299 local_level: SkillTrustLevel::Trusted,
300 hash_mismatch_level: SkillTrustLevel::Quarantined,
301 bundled_level: SkillTrustLevel::Trusted,
302 scan_on_load: false,
303 scanner: ScannerConfig::default(),
304 };
305 let toml = toml::to_string(&config).expect("serialize");
306 let deserialized: TrustConfig = toml::from_str(&toml).expect("deserialize");
307 assert!(!deserialized.scan_on_load);
308 assert_eq!(deserialized.bundled_level, SkillTrustLevel::Trusted);
309 }
310
311 #[test]
312 fn trust_config_missing_scan_on_load_defaults_to_true() {
313 let toml = r#"
314default_level = "quarantined"
315local_level = "trusted"
316hash_mismatch_level = "quarantined"
317"#;
318 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
319 assert!(
320 config.scan_on_load,
321 "missing scan_on_load must default to true"
322 );
323 }
324
325 #[test]
326 fn trust_config_default_has_bundled_level_trusted() {
327 let config = TrustConfig::default();
328 assert_eq!(config.bundled_level, SkillTrustLevel::Trusted);
329 }
330
331 #[test]
332 fn trust_config_missing_bundled_level_defaults_to_trusted() {
333 let toml = r#"
334default_level = "quarantined"
335local_level = "trusted"
336hash_mismatch_level = "quarantined"
337"#;
338 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
339 assert_eq!(
340 config.bundled_level,
341 SkillTrustLevel::Trusted,
342 "missing bundled_level must default to trusted"
343 );
344 }
345
346 #[test]
347 fn scanner_config_defaults() {
348 let cfg = ScannerConfig::default();
349 assert!(cfg.injection_patterns);
350 assert!(!cfg.capability_escalation_check);
351 }
352
353 #[test]
354 fn scanner_config_serde_roundtrip() {
355 let cfg = ScannerConfig {
356 injection_patterns: false,
357 capability_escalation_check: true,
358 };
359 let toml = toml::to_string(&cfg).expect("serialize");
360 let back: ScannerConfig = toml::from_str(&toml).expect("deserialize");
361 assert!(!back.injection_patterns);
362 assert!(back.capability_escalation_check);
363 }
364
365 #[test]
366 fn trust_config_scanner_defaults_when_missing() {
367 let toml = r#"
368default_level = "quarantined"
369local_level = "trusted"
370hash_mismatch_level = "quarantined"
371"#;
372 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
373 assert!(config.scanner.injection_patterns);
374 assert!(!config.scanner.capability_escalation_check);
375 }
376
377 #[test]
382 fn timeout_config_context_prep_timeout_default() {
383 let cfg = TimeoutConfig::default();
384 assert_eq!(
385 cfg.context_prep_timeout_secs, 30,
386 "context_prep_timeout_secs default must be 30s (#3357)"
387 );
388 }
389
390 #[test]
391 fn timeout_config_no_providers_backoff_default() {
392 let cfg = TimeoutConfig::default();
393 assert_eq!(
394 cfg.no_providers_backoff_secs, 2,
395 "no_providers_backoff_secs default must be 2s (#3357)"
396 );
397 }
398
399 #[test]
400 fn timeout_config_new_fields_deserialize_from_toml() {
401 let toml = r#"
402context_prep_timeout_secs = 60
403no_providers_backoff_secs = 10
404"#;
405 let cfg: TimeoutConfig = toml::from_str(toml).expect("deserialize");
406 assert_eq!(cfg.context_prep_timeout_secs, 60);
407 assert_eq!(cfg.no_providers_backoff_secs, 10);
408 }
409
410 #[test]
411 fn timeout_config_new_fields_default_when_missing_from_toml() {
412 let cfg: TimeoutConfig = toml::from_str("").expect("deserialize empty");
414 assert_eq!(cfg.context_prep_timeout_secs, 30);
415 assert_eq!(cfg.no_providers_backoff_secs, 2);
416 }
417}