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)]
92pub struct TrustConfig {
93 #[serde(default = "default_trust_default_level")]
95 pub default_level: SkillTrustLevel,
96 #[serde(default = "default_trust_local_level")]
98 pub local_level: SkillTrustLevel,
99 #[serde(default = "default_trust_hash_mismatch_level")]
102 pub hash_mismatch_level: SkillTrustLevel,
103 #[serde(default = "default_true")]
111 pub scan_on_load: bool,
112 #[serde(default)]
114 pub scanner: ScannerConfig,
115}
116
117impl Default for TrustConfig {
118 fn default() -> Self {
119 Self {
120 default_level: default_trust_default_level(),
121 local_level: default_trust_local_level(),
122 hash_mismatch_level: default_trust_hash_mismatch_level(),
123 scan_on_load: true,
124 scanner: ScannerConfig::default(),
125 }
126 }
127}
128
129#[derive(Debug, Clone, Deserialize, Serialize)]
147pub struct SecurityConfig {
148 #[serde(default = "default_true")]
151 pub redact_secrets: bool,
152 #[serde(default)]
154 pub autonomy_level: AutonomyLevel,
155 #[serde(default)]
156 pub content_isolation: ContentIsolationConfig,
157 #[serde(default)]
158 pub exfiltration_guard: ExfiltrationGuardConfig,
159 #[serde(default)]
161 pub memory_validation: MemoryWriteValidationConfig,
162 #[serde(default)]
164 pub pii_filter: PiiFilterConfig,
165 #[serde(default)]
167 pub rate_limit: RateLimitConfig,
168 #[serde(default)]
170 pub pre_execution_verify: PreExecutionVerifierConfig,
171 #[serde(default)]
173 pub guardrail: GuardrailConfig,
174 #[serde(default)]
176 pub response_verification: ResponseVerificationConfig,
177 #[serde(default)]
179 pub causal_ipi: CausalIpiConfig,
180}
181
182impl Default for SecurityConfig {
183 fn default() -> Self {
184 Self {
185 redact_secrets: true,
186 autonomy_level: AutonomyLevel::default(),
187 content_isolation: ContentIsolationConfig::default(),
188 exfiltration_guard: ExfiltrationGuardConfig::default(),
189 memory_validation: MemoryWriteValidationConfig::default(),
190 pii_filter: PiiFilterConfig::default(),
191 rate_limit: RateLimitConfig::default(),
192 pre_execution_verify: PreExecutionVerifierConfig::default(),
193 guardrail: GuardrailConfig::default(),
194 response_verification: ResponseVerificationConfig::default(),
195 causal_ipi: CausalIpiConfig::default(),
196 }
197 }
198}
199
200#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
214pub struct TimeoutConfig {
215 #[serde(default = "default_llm_timeout")]
217 pub llm_seconds: u64,
218 #[serde(default = "default_llm_request_timeout")]
221 pub llm_request_timeout_secs: u64,
222 #[serde(default = "default_embedding_timeout")]
224 pub embedding_seconds: u64,
225 #[serde(default = "default_a2a_timeout")]
227 pub a2a_seconds: u64,
228 #[serde(default = "default_max_parallel_tools")]
231 pub max_parallel_tools: usize,
232}
233
234impl Default for TimeoutConfig {
235 fn default() -> Self {
236 Self {
237 llm_seconds: default_llm_timeout(),
238 llm_request_timeout_secs: default_llm_request_timeout(),
239 embedding_seconds: default_embedding_timeout(),
240 a2a_seconds: default_a2a_timeout(),
241 max_parallel_tools: default_max_parallel_tools(),
242 }
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn trust_config_default_has_scan_on_load_true() {
252 let config = TrustConfig::default();
253 assert!(config.scan_on_load);
254 }
255
256 #[test]
257 fn trust_config_serde_roundtrip_with_scan_on_load() {
258 let config = TrustConfig {
259 default_level: SkillTrustLevel::Quarantined,
260 local_level: SkillTrustLevel::Trusted,
261 hash_mismatch_level: SkillTrustLevel::Quarantined,
262 scan_on_load: false,
263 scanner: ScannerConfig::default(),
264 };
265 let toml = toml::to_string(&config).expect("serialize");
266 let deserialized: TrustConfig = toml::from_str(&toml).expect("deserialize");
267 assert!(!deserialized.scan_on_load);
268 }
269
270 #[test]
271 fn trust_config_missing_scan_on_load_defaults_to_true() {
272 let toml = r#"
273default_level = "quarantined"
274local_level = "trusted"
275hash_mismatch_level = "quarantined"
276"#;
277 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
278 assert!(
279 config.scan_on_load,
280 "missing scan_on_load must default to true"
281 );
282 }
283
284 #[test]
285 fn scanner_config_defaults() {
286 let cfg = ScannerConfig::default();
287 assert!(cfg.injection_patterns);
288 assert!(!cfg.capability_escalation_check);
289 }
290
291 #[test]
292 fn scanner_config_serde_roundtrip() {
293 let cfg = ScannerConfig {
294 injection_patterns: false,
295 capability_escalation_check: true,
296 };
297 let toml = toml::to_string(&cfg).expect("serialize");
298 let back: ScannerConfig = toml::from_str(&toml).expect("deserialize");
299 assert!(!back.injection_patterns);
300 assert!(back.capability_escalation_check);
301 }
302
303 #[test]
304 fn trust_config_scanner_defaults_when_missing() {
305 let toml = r#"
306default_level = "quarantined"
307local_level = "trusted"
308hash_mismatch_level = "quarantined"
309"#;
310 let config: TrustConfig = toml::from_str(toml).expect("deserialize");
311 assert!(config.scanner.injection_patterns);
312 assert!(!config.scanner.capability_escalation_check);
313 }
314}