kindly_guard_server/config.rs
1// Copyright 2025 Kindly Software Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! Configuration for `KindlyGuard`
15//!
16//! This module defines all security-related configuration structures for KindlyGuard.
17//! Each configuration option has been carefully designed with security implications in mind.
18//!
19//! # Security Principles
20//!
21//! 1. **Secure Defaults**: All configuration defaults err on the side of security
22//! 2. **Defense in Depth**: Multiple layers of security can be configured independently
23//! 3. **Least Privilege**: Features are disabled by default and must be explicitly enabled
24//! 4. **Transparency**: Security implications of each setting are clearly documented
25//!
26//! # Configuration Hierarchy
27//!
28//! Configuration sources are checked in order:
29//! 1. Environment variable `KINDLY_GUARD_CONFIG` (highest precedence)
30//! 2. `kindly-guard.toml` in current directory
31//! 3. Built-in secure defaults (lowest precedence)
32
33use anyhow::Result;
34use base64::{engine::general_purpose, Engine as _};
35use serde::{Deserialize, Serialize};
36use std::path::PathBuf;
37
38pub mod reload;
39
40use crate::audit::AuditConfig;
41use crate::auth::AuthConfig;
42#[cfg(feature = "enhanced")]
43use crate::event_processor::EventProcessorConfig;
44use crate::neutralizer::NeutralizationConfig;
45use crate::plugins::PluginConfig;
46use crate::rate_limit::RateLimitConfig;
47use crate::resilience::config::ResilienceConfig;
48use crate::signing::SigningConfig;
49use crate::storage::StorageConfig;
50use crate::telemetry::TelemetryConfig;
51use crate::transport::TransportConfig;
52
53// Stub EventProcessorConfig when enhanced feature is not enabled
54#[cfg(not(feature = "enhanced"))]
55#[derive(Debug, Clone, Serialize, Deserialize, Default)]
56pub struct EventProcessorConfig {
57 pub enabled: bool,
58}
59
60/// Main configuration structure for KindlyGuard
61///
62/// # Security Architecture
63///
64/// KindlyGuard's configuration implements defense-in-depth with multiple
65/// security layers that work together:
66///
67/// 1. **Authentication** (`auth`) - Identity verification and access control
68/// 2. **Rate Limiting** (`rate_limit`) - Abuse and DoS prevention
69/// 3. **Scanner** (`scanner`) - Threat detection and analysis
70/// 4. **Neutralization** (`neutralization`) - Threat remediation
71/// 5. **Audit** (`audit`) - Security event logging and compliance
72///
73/// # Configuration Priority
74///
75/// When multiple security features could conflict:
76/// 1. Authentication failures block everything (highest priority)
77/// 2. Rate limits apply after authentication
78/// 3. Scanner runs on all authenticated requests
79/// 4. Neutralization only acts on detected threats
80///
81/// # Example: Minimum Secure Configuration
82///
83/// ```toml
84/// [auth]
85/// enabled = true
86/// jwt_secret = "your-base64-encoded-secret"
87/// trusted_issuers = ["https://your-auth-server.com"]
88///
89/// [rate_limit]
90/// enabled = true
91/// default_rpm = 60
92///
93/// [scanner]
94/// unicode_detection = true
95/// injection_detection = true
96/// path_traversal_detection = true
97/// xss_detection = true
98///
99/// [neutralization]
100/// mode = "automatic"
101/// audit_all_actions = true
102/// ```
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct Config {
105 /// Server configuration
106 ///
107 /// Controls network exposure and connection handling.
108 /// Lower limits = more secure but less scalable.
109 pub server: ServerConfig,
110
111 /// Security scanning configuration
112 ///
113 /// Primary defense against malicious input.
114 /// More detections enabled = better security coverage.
115 pub scanner: ScannerConfig,
116
117 /// Shield display configuration
118 ///
119 /// Visual security status indicator.
120 /// No direct security impact but aids monitoring.
121 pub shield: ShieldConfig,
122
123 /// Authentication configuration
124 ///
125 /// Access control and identity verification.
126 /// MUST be enabled in production environments.
127 pub auth: AuthConfig,
128
129 /// Message signing configuration
130 ///
131 /// Cryptographic integrity for requests/responses.
132 /// Prevents tampering and replay attacks.
133 pub signing: SigningConfig,
134
135 /// Rate limiting configuration
136 ///
137 /// Prevents abuse and resource exhaustion.
138 /// Essential for public-facing deployments.
139 pub rate_limit: RateLimitConfig,
140
141 /// Enhanced security event processing configuration
142 ///
143 /// Advanced threat correlation and analysis.
144 /// Provides deeper security insights when enabled.
145 pub event_processor: EventProcessorConfig,
146
147 /// Telemetry configuration
148 ///
149 /// Security monitoring and metrics.
150 /// Critical for detecting attacks and anomalies.
151 pub telemetry: TelemetryConfig,
152
153 /// Storage configuration
154 ///
155 /// Secure storage for backups and audit logs.
156 /// Encryption and access control are essential.
157 pub storage: StorageConfig,
158
159 /// Plugin system configuration
160 ///
161 /// Extensibility with security boundaries.
162 /// Only load trusted, signed plugins.
163 pub plugins: PluginConfig,
164
165 /// Audit logging configuration
166 ///
167 /// Forensic trail of all security events.
168 /// Required for compliance and incident response.
169 pub audit: AuditConfig,
170
171 /// Transport layer configuration
172 ///
173 /// Communication security settings.
174 /// Use TLS for all network transports.
175 pub transport: TransportConfig,
176
177 /// Resilience configuration for circuit breakers and retry
178 ///
179 /// Prevents cascading failures under attack.
180 /// Maintains availability during security incidents.
181 pub resilience: ResilienceConfig,
182
183 /// Threat neutralization configuration
184 ///
185 /// Active threat remediation settings.
186 /// Transforms malicious input into safe content.
187 pub neutralization: NeutralizationConfig,
188
189 /// Neutralizer configuration (alias for neutralization)
190 ///
191 /// Some tests expect this field name.
192 /// This is an alias for backwards compatibility.
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub neutralizer: Option<NeutralizationConfig>,
195}
196
197/// Server configuration controlling network and connection settings
198///
199/// # Security Implications
200///
201/// The server configuration affects the attack surface and resource consumption:
202/// - Lower connection limits prevent resource exhaustion attacks
203/// - Shorter timeouts reduce the window for slow loris attacks
204/// - stdio mode is more secure than network modes (no network exposure)
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct ServerConfig {
207 /// Port to listen on (for HTTP transport)
208 ///
209 /// **Default**: 8080
210 /// **Security**: Use non-standard ports to reduce automated scanning.
211 /// Consider using a reverse proxy for production deployments.
212 /// **Range**: 1-65535 (ports < 1024 require root/admin privileges)
213 #[serde(default = "default_port")]
214 pub port: u16,
215
216 /// Enable stdio transport (default for MCP)
217 ///
218 /// **Default**: true (secure by default)
219 /// **Security**: stdio is the most secure transport as it doesn't expose
220 /// a network interface. Recommended for local integrations.
221 /// **Trade-off**: Limited to local process communication only
222 #[serde(default = "default_true")]
223 pub stdio: bool,
224
225 /// Maximum concurrent connections
226 ///
227 /// **Default**: 100
228 /// **Security**: Prevents resource exhaustion attacks. Lower values are more
229 /// secure but may impact legitimate high-traffic scenarios.
230 /// **Range**: 1-10000 (recommend 10-500 for most deployments)
231 /// **Warning**: Values > 1000 may cause memory issues under attack
232 #[serde(default = "default_max_connections")]
233 pub max_connections: usize,
234
235 /// Request timeout in seconds
236 ///
237 /// **Default**: 30 seconds
238 /// **Security**: Shorter timeouts prevent slow loris and resource holding attacks.
239 /// Longer timeouts may be needed for complex operations.
240 /// **Range**: 1-300 (recommend 10-60 for most use cases)
241 /// **Trade-off**: Too short may interrupt legitimate long operations
242 #[serde(default = "default_timeout")]
243 pub request_timeout_secs: u64,
244}
245
246/// Scanner configuration for threat detection settings
247///
248/// # Security Implications
249///
250/// The scanner is your first line of defense against malicious input:
251/// - Disabling any detection reduces security coverage
252/// - Custom patterns can detect organization-specific threats
253/// - Scan depth limits prevent algorithmic complexity attacks
254/// - Enhanced mode provides better detection at a performance cost
255///
256/// # Example: Secure Production Configuration
257///
258/// ```toml
259/// [scanner]
260/// unicode_detection = true # Detect unicode attacks
261/// injection_detection = true # Detect SQL/command injection
262/// path_traversal_detection = true # Detect directory traversal
263/// xss_detection = true # Detect XSS attempts
264/// enhanced_mode = true # Maximum security (if available)
265/// max_scan_depth = 20 # Deep scanning for nested payloads
266/// custom_patterns = "/etc/kindly-guard/patterns.toml"
267/// ```
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct ScannerConfig {
270 /// Enable unicode threat detection
271 ///
272 /// **Default**: true (secure by default)
273 /// **Security**: Detects BiDi overrides, zero-width chars, homoglyphs.
274 /// Essential for preventing unicode-based attacks and spoofing.
275 /// **Warning**: Disabling exposes you to text direction manipulation
276 #[serde(default = "default_true")]
277 pub unicode_detection: bool,
278
279 /// Enable injection detection
280 ///
281 /// **Default**: true (secure by default)
282 /// **Security**: Detects SQL, NoSQL, command, and LDAP injection attempts.
283 /// Critical for preventing code execution and data breaches.
284 /// **Coverage**: SQL, shell commands, LDAP queries, NoSQL operations
285 #[serde(default = "default_true")]
286 pub injection_detection: bool,
287
288 /// Enable path traversal detection
289 ///
290 /// **Default**: true (secure by default)
291 /// **Security**: Detects attempts to access files outside intended directories.
292 /// Prevents unauthorized file access and directory listing.
293 /// **Patterns**: ../, ..\, absolute paths, URL encoding variants
294 #[serde(default = "default_true")]
295 pub path_traversal_detection: bool,
296
297 /// Enable XSS detection
298 ///
299 /// **Default**: Some(true) (secure by default)
300 /// **Security**: Detects cross-site scripting attempts in various contexts.
301 /// Essential for web-facing applications and APIs.
302 /// **Coverage**: Script tags, event handlers, data URIs, SVG attacks
303 #[serde(default = "default_some_true")]
304 pub xss_detection: Option<bool>,
305
306 /// Enable cryptographic security detection
307 ///
308 /// **Default**: true (secure by default)
309 /// **Security**: Detects weak cryptographic patterns and insecure implementations.
310 /// Critical for preventing cryptographic vulnerabilities and data exposure.
311 /// **Coverage**: Deprecated algorithms (MD5, SHA1, DES), weak keys, insecure RNG, bad KDF
312 /// **2025 Standards**: Enforces current NIST recommendations for key sizes and algorithms
313 #[serde(default = "default_true")]
314 pub crypto_detection: bool,
315
316 /// Enable enhanced mode for scanners (uses advanced algorithms when available)
317 ///
318 /// **Default**: Some(false) (standard mode)
319 /// **Security**: Enhanced mode provides deeper analysis and pattern correlation.
320 /// Better detection accuracy at the cost of some performance.
321 /// **Trade-off**: 10-20% performance impact for 50%+ better detection
322 #[serde(default = "default_some_false")]
323 pub enhanced_mode: Option<bool>,
324
325 /// Custom threat patterns file
326 ///
327 /// **Default**: None
328 /// **Security**: Add organization-specific threat patterns.
329 /// Useful for detecting internal security policies violations.
330 /// **Format**: TOML file with regex patterns and metadata
331 /// **Example**: `/etc/kindly-guard/custom-patterns.toml`
332 pub custom_patterns: Option<PathBuf>,
333
334 /// Maximum scan depth for nested structures
335 ///
336 /// **Default**: 10
337 /// **Security**: Prevents algorithmic complexity attacks through deep nesting.
338 /// Lower values are more secure but may miss deeply nested threats.
339 /// **Range**: 1-100 (recommend 5-20 for most use cases)
340 /// **Warning**: Values > 50 may cause performance issues
341 #[serde(default = "default_max_depth")]
342 pub max_scan_depth: usize,
343
344 /// Enable high-performance event buffer
345 ///
346 /// **Default**: false (standard mode)
347 /// **Security**: Enables advanced correlation and pattern matching.
348 /// Provides "purple shield" mode with enhanced threat detection.
349 /// **Requirements**: Additional memory (10-50MB depending on load)
350 #[serde(default = "default_false")]
351 pub enable_event_buffer: bool,
352
353 /// Maximum content size to scan (in bytes)
354 ///
355 /// **Default**: 5MB (5,242,880 bytes)
356 /// **Security**: Prevents DoS attacks through large payload scanning.
357 /// Content larger than this will be rejected with a DosPotential threat.
358 /// **Range**: 1KB-100MB (recommend 1-10MB for most use cases)
359 /// **Trade-off**: Larger values allow bigger legitimate payloads but increase DoS risk
360 #[serde(default = "default_max_content_size")]
361 pub max_content_size: usize,
362
363 /// Maximum input size to scan (alias for max_content_size)
364 ///
365 /// **Default**: Uses max_content_size value
366 /// **Security**: Some tests expect this field name.
367 /// This is an alias for backwards compatibility.
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub max_input_size: Option<usize>,
370
371 /// Allow common text control characters (newline, tab, carriage return)
372 ///
373 /// **Default**: false (strict mode - all control chars are dangerous)
374 /// **Security**: When true, allows \n, \r, \t in text without flagging as threats.
375 /// Useful for wrapping CLI tools that process text documents.
376 /// **Warning**: Only enable for trusted input sources like CLI wrapping.
377 #[serde(default = "default_false")]
378 pub allow_text_control_chars: bool,
379}
380
381/// Shield display configuration
382///
383/// The shield provides visual feedback about security status:
384/// - 🟢 Green: Normal operation, no threats
385/// - 🟣 Purple: Enhanced mode active (better detection)
386/// - 🔴 Red: Active threat detected
387/// - âš« Gray: Disabled or error state
388///
389/// While not a security feature itself, the shield aids in:
390/// - Real-time threat awareness
391/// - System health monitoring
392/// - Security posture visualization
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct ShieldConfig {
395 /// Enable shield display
396 ///
397 /// **Default**: false (no visual output)
398 /// **Security**: No direct impact, but helps operators monitor security status.
399 /// Useful for development and attended deployments.
400 #[serde(default = "default_false")]
401 pub enabled: bool,
402
403 /// Update interval in milliseconds
404 ///
405 /// **Default**: 1000ms (1 second)
406 /// **Performance**: Lower values provide more responsive feedback but use more CPU.
407 /// **Range**: 100-10000ms (recommend 500-2000ms)
408 #[serde(default = "default_update_interval")]
409 pub update_interval_ms: u64,
410
411 /// Show detailed statistics
412 ///
413 /// **Default**: false (basic display only)
414 /// **Security**: Shows threat counts, types, and neutralization stats.
415 /// Helpful for understanding attack patterns in real-time.
416 #[serde(default = "default_false")]
417 pub detailed_stats: bool,
418
419 /// Enable color output
420 ///
421 /// **Default**: true (colored output)
422 /// **Accessibility**: Set to false for screen readers or monochrome terminals.
423 /// Colors help quickly identify security state changes.
424 #[serde(default = "default_true")]
425 pub color: bool,
426}
427
428impl Config {
429 /// Check if event processor is enabled
430 pub const fn is_event_processor_enabled(&self) -> bool {
431 #[cfg(feature = "enhanced")]
432 return self.event_processor.enabled;
433 #[cfg(not(feature = "enhanced"))]
434 return false;
435 }
436
437 /// Get neutralizer configuration
438 /// Returns the neutralizer field if set, otherwise returns neutralization
439 pub fn neutralizer(&self) -> &NeutralizationConfig {
440 self.neutralizer.as_ref().unwrap_or(&self.neutralization)
441 }
442
443 /// Load configuration from environment and files
444 ///
445 /// # Security Notes
446 ///
447 /// - Configuration files should have restricted permissions (600 or 640)
448 /// - Never store secrets directly in config files - use environment variables
449 /// - Validate all loaded configurations before use
450 /// - Default configuration is intentionally conservative for security
451 pub fn load() -> Result<Self> {
452 // First, try to load from config file
453 let config_path = std::env::var("KINDLY_GUARD_CONFIG")
454 .map_or_else(|_| PathBuf::from("kindly-guard.toml"), PathBuf::from);
455
456 if config_path.exists() {
457 Self::load_from_file(&config_path.to_string_lossy())
458 } else {
459 // Use default configuration
460 Ok(Self::default())
461 }
462 }
463
464 /// Load configuration from a specific file
465 ///
466 /// # Security Warning
467 ///
468 /// Ensure the configuration file is from a trusted source and has
469 /// appropriate file permissions to prevent unauthorized modifications.
470 pub fn load_from_file(path: &str) -> Result<Self> {
471 let content = std::fs::read_to_string(path)?;
472 let config: Self = toml::from_str(&content)?;
473 Ok(config)
474 }
475
476 /// Validate configuration for security best practices
477 ///
478 /// # Example
479 ///
480 /// ```
481 /// let config = Config::load()?;
482 /// config.validate_security()?;
483 /// ```
484 pub fn validate_security(&self) -> Result<()> {
485 // Warn if authentication is disabled
486 if !self.auth.enabled {
487 tracing::warn!("Authentication is disabled - this is insecure for production!");
488 }
489
490 // Warn if rate limiting is disabled
491 if !self.rate_limit.enabled {
492 tracing::warn!("Rate limiting is disabled - vulnerable to DoS attacks!");
493 }
494
495 // Check for weak JWT secrets
496 if let Some(ref secret) = self.auth.jwt_secret {
497 let decoded = general_purpose::STANDARD.decode(secret)?;
498 if decoded.len() < 32 {
499 return Err(anyhow::anyhow!(
500 "JWT secret too short - use at least 256 bits (32 bytes)"
501 ));
502 }
503 }
504
505 // Ensure scanner is properly configured
506 if !self.scanner.unicode_detection
507 || !self.scanner.injection_detection
508 || !self.scanner.path_traversal_detection
509 {
510 tracing::warn!("Some threat detections are disabled - reduced security coverage");
511 }
512
513 Ok(())
514 }
515}
516
517impl Default for Config {
518 fn default() -> Self {
519 Self {
520 server: ServerConfig {
521 port: default_port(),
522 stdio: default_true(),
523 max_connections: default_max_connections(),
524 request_timeout_secs: default_timeout(),
525 },
526 scanner: ScannerConfig {
527 unicode_detection: default_true(),
528 injection_detection: default_true(),
529 path_traversal_detection: default_true(),
530 xss_detection: Some(true),
531 crypto_detection: default_true(),
532 enhanced_mode: Some(false),
533 custom_patterns: None,
534 max_scan_depth: default_max_depth(),
535 enable_event_buffer: default_false(),
536 max_content_size: default_max_content_size(),
537 max_input_size: None,
538 allow_text_control_chars: default_false(),
539 },
540 shield: ShieldConfig {
541 enabled: default_false(),
542 update_interval_ms: default_update_interval(),
543 detailed_stats: default_false(),
544 color: default_true(),
545 },
546 auth: AuthConfig::default(),
547 signing: SigningConfig::default(),
548 rate_limit: RateLimitConfig::default(),
549 event_processor: EventProcessorConfig::default(),
550 telemetry: TelemetryConfig::default(),
551 storage: StorageConfig::default(),
552 plugins: PluginConfig::default(),
553 audit: AuditConfig::default(),
554 transport: TransportConfig::default(),
555 resilience: ResilienceConfig::default(),
556 neutralization: NeutralizationConfig::default(),
557 neutralizer: None,
558 }
559 }
560}
561
562impl Default for ShieldConfig {
563 fn default() -> Self {
564 Self {
565 enabled: default_false(),
566 update_interval_ms: default_update_interval(),
567 detailed_stats: default_false(),
568 color: default_true(),
569 }
570 }
571}
572
573impl Default for ServerConfig {
574 fn default() -> Self {
575 Self {
576 port: default_port(),
577 stdio: default_true(),
578 max_connections: default_max_connections(),
579 request_timeout_secs: default_timeout(),
580 }
581 }
582}
583
584impl Default for ScannerConfig {
585 fn default() -> Self {
586 Self {
587 unicode_detection: default_true(),
588 injection_detection: default_true(),
589 path_traversal_detection: default_true(),
590 xss_detection: default_some_true(),
591 crypto_detection: default_true(),
592 enhanced_mode: default_some_false(),
593 custom_patterns: None,
594 max_scan_depth: default_max_depth(),
595 enable_event_buffer: default_false(),
596 max_content_size: default_max_content_size(),
597 max_input_size: None,
598 allow_text_control_chars: default_false(),
599 }
600 }
601}
602
603// Default value functions
604const fn default_port() -> u16 {
605 8080
606}
607const fn default_true() -> bool {
608 true
609}
610const fn default_false() -> bool {
611 false
612}
613fn default_some_true() -> Option<bool> {
614 Some(true)
615}
616fn default_some_false() -> Option<bool> {
617 Some(false)
618}
619const fn default_max_connections() -> usize {
620 100
621}
622const fn default_max_depth() -> usize {
623 10
624}
625const fn default_update_interval() -> u64 {
626 1000
627}
628const fn default_timeout() -> u64 {
629 30
630}
631const fn default_max_content_size() -> usize {
632 5 * 1024 * 1024 // 5MB
633}
634
635/// Example secure production configuration
636///
637/// Save this as `kindly-guard.toml` and adjust for your environment:
638///
639/// ```toml
640/// # Server Configuration
641/// [server]
642/// port = 8443 # Use HTTPS port
643/// stdio = false # Network mode for production
644/// max_connections = 500 # Adjust based on load
645/// request_timeout_secs = 30 # Prevent slow loris attacks
646///
647/// # Authentication - REQUIRED for production
648/// [auth]
649/// enabled = true
650/// validation_endpoint = "https://auth.example.com/oauth2/introspect"
651/// trusted_issuers = ["https://auth.example.com"]
652/// cache_ttl_seconds = 300
653/// validate_resource_indicators = true
654/// jwt_secret = "YOUR-BASE64-ENCODED-256-BIT-SECRET" # Generate with: openssl rand -base64 32
655/// require_signature_verification = true
656///
657/// [auth.required_scopes]
658/// default = ["kindlyguard:access"]
659///
660/// [auth.required_scopes.tools]
661/// "scan" = ["security:read"]
662/// "neutralize" = ["security:write"]
663///
664/// # Rate Limiting - Essential for DoS protection
665/// [rate_limit]
666/// enabled = true
667/// default_rpm = 60
668/// burst_capacity = 10
669/// cleanup_interval_secs = 300
670/// adaptive = true
671/// threat_penalty_multiplier = 0.5
672///
673/// [rate_limit.method_limits]
674/// "tools/list" = { rpm = 120, burst = 20 }
675/// "tools/call" = { rpm = 30, burst = 5 }
676/// "security/threats" = { rpm = 10, burst = 2 }
677///
678/// # Scanner - Core threat detection
679/// [scanner]
680/// unicode_detection = true
681/// injection_detection = true
682/// path_traversal_detection = true
683/// xss_detection = true
684/// enhanced_mode = true # If available
685/// max_scan_depth = 20 # Deep scanning
686/// enable_event_buffer = true # Purple shield mode
687/// custom_patterns = "/etc/kindly-guard/patterns.toml"
688///
689/// # Neutralization - Active threat remediation
690/// [neutralization]
691/// mode = "automatic"
692/// backup_originals = true
693/// audit_all_actions = true
694///
695/// [neutralization.unicode]
696/// bidi_replacement = "marker"
697/// zero_width_action = "remove"
698/// homograph_action = "ascii"
699///
700/// [neutralization.injection]
701/// sql_action = "parameterize"
702/// command_action = "escape"
703/// path_action = "normalize"
704/// prompt_action = "wrap"
705///
706/// # Audit - Security event logging
707/// [audit]
708/// enabled = true
709/// file_path = "/var/log/kindly-guard/audit.log"
710/// max_file_size_mb = 100
711/// max_files = 10
712/// include_request_body = true
713/// include_response_body = false
714///
715/// # Shield Display
716/// [shield]
717/// enabled = true
718/// update_interval_ms = 1000
719/// detailed_stats = true
720/// color = true
721/// ```
722
723#[cfg(test)]
724mod tests {
725 use super::*;
726
727 #[test]
728 fn test_default_config() {
729 let config = Config::default();
730 assert!(config.server.stdio);
731 assert!(config.scanner.unicode_detection);
732 assert_eq!(config.server.port, 8080);
733 }
734
735 #[test]
736 fn test_security_validation() {
737 let mut config = Config::default();
738
739 // Should warn but not error with default config
740 assert!(config.validate_security().is_ok());
741
742 // Should error with weak JWT secret
743 config.auth.jwt_secret = Some("c2hvcnQ=".to_string()); // "short" in base64
744 assert!(config.validate_security().is_err());
745 }
746}