codeprism_mcp/
validation.rs

1//! Configuration Validation & Health Check System (Phase 2.2)
2//!
3//! This module provides comprehensive configuration validation at startup,
4//! system health monitoring, and diagnostic tools for production deployment.
5
6use crate::config::McpConfigProfile;
7use crate::monitoring::PerformanceMonitor;
8use crate::tools::dynamic_enablement::DynamicToolManager;
9use crate::CodePrismMcpServer;
10use anyhow::Result;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::path::{Path, PathBuf};
14use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
15use tracing::{debug, error, info, warn};
16
17/// System validation and health check coordinator
18#[derive(Debug)]
19pub struct SystemValidator {
20    config_profile: McpConfigProfile,
21    performance_monitor: Option<PerformanceMonitor>,
22    tool_manager: Option<DynamicToolManager>,
23    validation_cache: ValidationCache,
24}
25
26/// Cache for validation results to avoid redundant checks
27#[derive(Debug, Default)]
28struct ValidationCache {
29    path_validations: HashMap<PathBuf, PathValidationResult>,
30    last_system_check: Option<SystemTime>,
31    last_dependencies_check: Option<SystemTime>,
32}
33
34/// Comprehensive validation result
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ValidationResult {
37    /// Overall validation status
38    pub status: ValidationStatus,
39    /// Configuration validation results
40    pub config_validation: ConfigValidationResult,
41    /// System readiness checks
42    pub system_readiness: SystemReadinessResult,
43    /// Security validation results
44    pub security_validation: SecurityValidationResult,
45    /// Performance validation results
46    pub performance_validation: PerformanceValidationResult,
47    /// Dependency validation results
48    pub dependency_validation: DependencyValidationResult,
49    /// Validation timestamp
50    pub timestamp: u64,
51    /// Time taken for validation
52    pub validation_duration_ms: u64,
53}
54
55/// Overall validation status
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
57pub enum ValidationStatus {
58    /// All validations passed
59    Valid,
60    /// Some warnings but system can start
61    ValidWithWarnings,
62    /// Critical issues preventing startup
63    Invalid,
64}
65
66/// Configuration validation result
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ConfigValidationResult {
69    pub valid: bool,
70    pub errors: Vec<ConfigValidationError>,
71    pub warnings: Vec<String>,
72    pub profile_name: String,
73    pub validated_settings: ConfigValidationDetails,
74}
75
76/// Configuration validation details
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct ConfigValidationDetails {
79    pub memory_settings_valid: bool,
80    pub timeout_settings_valid: bool,
81    pub path_settings_valid: bool,
82    pub security_settings_valid: bool,
83    pub monitoring_settings_valid: bool,
84    pub caching_settings_valid: bool,
85}
86
87/// Configuration validation error
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct ConfigValidationError {
90    pub field: String,
91    pub error_type: ConfigErrorType,
92    pub message: String,
93    pub suggested_fix: Option<String>,
94}
95
96/// Types of configuration errors
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub enum ConfigErrorType {
99    InvalidValue,
100    MissingRequired,
101    IncompatibleSettings,
102    PathNotAccessible,
103    SecurityRisk,
104    PerformanceIssue,
105}
106
107/// System readiness validation
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct SystemReadinessResult {
110    pub ready: bool,
111    pub system_requirements: SystemRequirementsCheck,
112    pub runtime_environment: RuntimeEnvironmentCheck,
113    pub resource_availability: ResourceAvailabilityCheck,
114}
115
116/// System requirements validation
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct SystemRequirementsCheck {
119    pub minimum_memory_available: bool,
120    pub minimum_disk_space: bool,
121    pub required_permissions: bool,
122    pub system_architecture_supported: bool,
123}
124
125/// Runtime environment validation
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct RuntimeEnvironmentCheck {
128    pub rust_version_compatible: bool,
129    pub required_features_available: bool,
130    pub environment_variables_set: bool,
131    pub network_connectivity: bool,
132}
133
134/// Resource availability validation
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct ResourceAvailabilityCheck {
137    pub available_memory_mb: usize,
138    pub available_disk_space_mb: usize,
139    pub cpu_cores_available: usize,
140    pub can_create_temp_files: bool,
141    pub can_bind_to_stdio: bool,
142}
143
144/// Security validation result
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct SecurityValidationResult {
147    pub secure: bool,
148    pub vulnerabilities: Vec<SecurityVulnerability>,
149    pub recommendations: Vec<SecurityRecommendation>,
150    pub security_score: u32, // 0-100
151}
152
153/// Security vulnerability detected
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct SecurityVulnerability {
156    pub severity: SecuritySeverity,
157    pub category: SecurityCategory,
158    pub description: String,
159    pub mitigation: String,
160}
161
162/// Security recommendation
163#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct SecurityRecommendation {
165    pub priority: SecurityPriority,
166    pub description: String,
167    pub implementation: String,
168}
169
170/// Security severity levels
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub enum SecuritySeverity {
173    Low,
174    Medium,
175    High,
176    Critical,
177}
178
179/// Security categories
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub enum SecurityCategory {
182    PathTraversal,
183    AccessControl,
184    DataExposure,
185    InputValidation,
186    Configuration,
187    NetworkSecurity,
188}
189
190/// Security recommendation priorities
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub enum SecurityPriority {
193    Low,
194    Medium,
195    High,
196    Critical,
197}
198
199/// Performance validation result
200#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct PerformanceValidationResult {
202    pub optimal: bool,
203    pub bottlenecks: Vec<PerformanceBottleneck>,
204    pub optimizations: Vec<PerformanceOptimization>,
205    pub performance_score: u32, // 0-100
206}
207
208/// Performance bottleneck detected
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct PerformanceBottleneck {
211    pub component: String,
212    pub severity: BottleneckSeverity,
213    pub description: String,
214    pub impact: String,
215    pub solution: String,
216}
217
218/// Performance optimization suggestion
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct PerformanceOptimization {
221    pub component: String,
222    pub optimization_type: OptimizationType,
223    pub description: String,
224    pub expected_improvement: String,
225    pub implementation_effort: ImplementationEffort,
226}
227
228/// Bottleneck severity levels
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub enum BottleneckSeverity {
231    Minor,
232    Moderate,
233    Significant,
234    Critical,
235}
236
237/// Types of performance optimizations
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub enum OptimizationType {
240    Memory,
241    Cpu,
242    Disk,
243    Network,
244    Caching,
245    Concurrency,
246    Configuration,
247}
248
249/// Implementation effort levels
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub enum ImplementationEffort {
252    Low,
253    Medium,
254    High,
255}
256
257/// Dependency validation result
258#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct DependencyValidationResult {
260    pub all_available: bool,
261    pub missing_dependencies: Vec<MissingDependency>,
262    pub version_conflicts: Vec<VersionConflict>,
263    pub optional_dependencies: Vec<OptionalDependency>,
264}
265
266/// Missing dependency information
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct MissingDependency {
269    pub name: String,
270    pub dependency_type: DependencyType,
271    pub required_for: Vec<String>,
272    pub installation_hint: Option<String>,
273}
274
275/// Version conflict information
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct VersionConflict {
278    pub dependency: String,
279    pub required_version: String,
280    pub found_version: String,
281    pub impact: String,
282}
283
284/// Optional dependency information
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct OptionalDependency {
287    pub name: String,
288    pub enables_features: Vec<String>,
289    pub installation_hint: String,
290}
291
292/// Types of dependencies
293#[derive(Debug, Clone, Serialize, Deserialize)]
294pub enum DependencyType {
295    SystemLibrary,
296    RuntimeDependency,
297    ToolDependency,
298    LanguageParser,
299}
300
301/// Path validation result for caching
302#[derive(Debug, Clone)]
303struct PathValidationResult {
304    accessible: bool,
305    readable: bool,
306    writable: bool,
307    validated_at: SystemTime,
308}
309
310impl SystemValidator {
311    /// Create a new system validator
312    pub fn new(config_profile: McpConfigProfile) -> Self {
313        Self {
314            config_profile,
315            performance_monitor: None,
316            tool_manager: None,
317            validation_cache: ValidationCache::default(),
318        }
319    }
320
321    /// Set performance monitor for validation
322    pub fn with_performance_monitor(mut self, monitor: PerformanceMonitor) -> Self {
323        self.performance_monitor = Some(monitor);
324        self
325    }
326
327    /// Set tool manager for validation
328    pub fn with_tool_manager(mut self, tool_manager: DynamicToolManager) -> Self {
329        self.tool_manager = Some(tool_manager);
330        self
331    }
332
333    /// Perform comprehensive system validation
334    pub async fn validate_system(&mut self) -> Result<ValidationResult> {
335        let start_time = Instant::now();
336
337        info!("Starting comprehensive system validation");
338
339        // Run all validation checks in parallel where possible
340        let config_validation = self.validate_configuration().await?;
341        let system_readiness = self.validate_system_readiness().await?;
342        let security_validation = self.validate_security().await?;
343        let performance_validation = self.validate_performance().await?;
344        let dependency_validation = self.validate_dependencies().await?;
345
346        // Determine overall validation status
347        let status = self.determine_overall_status(
348            &config_validation,
349            &system_readiness,
350            &security_validation,
351            &performance_validation,
352            &dependency_validation,
353        );
354
355        let validation_duration_ms = start_time.elapsed().as_millis() as u64;
356        let timestamp = SystemTime::now()
357            .duration_since(UNIX_EPOCH)
358            .unwrap_or_default()
359            .as_secs();
360
361        let result = ValidationResult {
362            status,
363            config_validation,
364            system_readiness,
365            security_validation,
366            performance_validation,
367            dependency_validation,
368            timestamp,
369            validation_duration_ms,
370        };
371
372        self.log_validation_summary(&result);
373
374        Ok(result)
375    }
376
377    /// Validate configuration settings
378    async fn validate_configuration(&mut self) -> Result<ConfigValidationResult> {
379        debug!("Validating configuration settings");
380
381        let mut errors = Vec::new();
382        let mut warnings = Vec::new();
383        let profile_name = self.config_profile.name.clone();
384
385        // Validate memory settings
386        let memory_valid = self.validate_memory_settings(&mut errors, &mut warnings);
387
388        // Validate timeout settings
389        let timeout_valid = self.validate_timeout_settings(&mut errors, &mut warnings);
390
391        // Validate path settings
392        let path_valid = self
393            .validate_path_settings(&mut errors, &mut warnings)
394            .await;
395
396        // Validate security settings
397        let security_valid = self.validate_security_settings(&mut errors, &mut warnings);
398
399        // Validate monitoring settings
400        let monitoring_valid = self.validate_monitoring_settings(&mut errors, &mut warnings);
401
402        // Validate caching settings
403        let caching_valid = self.validate_caching_settings(&mut errors, &mut warnings);
404
405        let valid = errors.is_empty();
406
407        Ok(ConfigValidationResult {
408            valid,
409            errors,
410            warnings,
411            profile_name,
412            validated_settings: ConfigValidationDetails {
413                memory_settings_valid: memory_valid,
414                timeout_settings_valid: timeout_valid,
415                path_settings_valid: path_valid,
416                security_settings_valid: security_valid,
417                monitoring_settings_valid: monitoring_valid,
418                caching_settings_valid: caching_valid,
419            },
420        })
421    }
422
423    /// Validate memory configuration
424    fn validate_memory_settings(
425        &self,
426        errors: &mut Vec<ConfigValidationError>,
427        warnings: &mut Vec<String>,
428    ) -> bool {
429        let config = &self.config_profile.settings;
430        let mut valid = true;
431
432        // Check minimum memory limit
433        if config.memory_limit_mb < 256 {
434            errors.push(ConfigValidationError {
435                field: "memory_limit_mb".to_string(),
436                error_type: ConfigErrorType::InvalidValue,
437                message: "Memory limit is too low, minimum 256MB required".to_string(),
438                suggested_fix: Some("Set memory_limit_mb to at least 256".to_string()),
439            });
440            valid = false;
441        }
442
443        // Check for excessive memory limit
444        if config.memory_limit_mb > 32768 {
445            warnings.push(
446                "Memory limit is very high (>32GB), ensure system has sufficient RAM".to_string(),
447            );
448        }
449
450        // Validate batch size relative to memory
451        let estimated_memory_per_file = 2; // MB estimated
452        let max_safe_batch = config.memory_limit_mb / estimated_memory_per_file;
453
454        if config.batch_size > max_safe_batch {
455            warnings.push(format!(
456                "Batch size ({}) may cause memory pressure, consider reducing to {}",
457                config.batch_size, max_safe_batch
458            ));
459        }
460
461        valid
462    }
463
464    /// Validate timeout configuration
465    fn validate_timeout_settings(
466        &self,
467        errors: &mut Vec<ConfigValidationError>,
468        warnings: &mut Vec<String>,
469    ) -> bool {
470        let config = &self.config_profile.settings;
471        let mut valid = true;
472
473        // Check minimum timeout
474        if config.default_timeout < Duration::from_secs(5) {
475            errors.push(ConfigValidationError {
476                field: "default_timeout".to_string(),
477                error_type: ConfigErrorType::InvalidValue,
478                message: "Default timeout is too low, minimum 5 seconds required".to_string(),
479                suggested_fix: Some("Increase default_timeout to at least 5 seconds".to_string()),
480            });
481            valid = false;
482        }
483
484        // Check for excessive timeout
485        if config.default_timeout > Duration::from_secs(600) {
486            warnings.push(
487                "Default timeout is very high (>10 minutes), clients may disconnect".to_string(),
488            );
489        }
490
491        valid
492    }
493
494    /// Validate path-related settings
495    async fn validate_path_settings(
496        &mut self,
497        errors: &mut Vec<ConfigValidationError>,
498        warnings: &mut Vec<String>,
499    ) -> bool {
500        // Clone the configuration values to avoid borrow issues
501        let cache_enabled = self.config_profile.caching.enabled;
502        let cache_dir = self.config_profile.caching.cache_dir.clone();
503        let audit_log_path = self.config_profile.security.audit_log_path.clone();
504        let denied_paths = self.config_profile.security.denied_paths.clone();
505
506        let mut valid = true;
507
508        // Validate cache directory
509        if cache_enabled {
510            if let Err(validation_error) = self.validate_path_access(&cache_dir, true, true).await {
511                errors.push(ConfigValidationError {
512                    field: "caching.cache_dir".to_string(),
513                    error_type: ConfigErrorType::PathNotAccessible,
514                    message: format!("Cache directory not accessible: {}", validation_error),
515                    suggested_fix: Some("Create directory or adjust permissions".to_string()),
516                });
517                valid = false;
518            }
519        }
520
521        // Validate audit log path
522        if let Some(audit_path) = audit_log_path {
523            if let Some(parent) = audit_path.parent() {
524                if let Err(validation_error) = self.validate_path_access(parent, true, true).await {
525                    errors.push(ConfigValidationError {
526                        field: "security.audit_log_path".to_string(),
527                        error_type: ConfigErrorType::PathNotAccessible,
528                        message: format!(
529                            "Audit log directory not accessible: {}",
530                            validation_error
531                        ),
532                        suggested_fix: Some("Create directory or adjust permissions".to_string()),
533                    });
534                    valid = false;
535                }
536            }
537        }
538
539        // Validate denied paths for security
540        for denied_path in &denied_paths {
541            if denied_path.starts_with("/") {
542                // Good - absolute path restriction
543                continue;
544            } else {
545                warnings.push(format!(
546                    "Denied path '{}' is not absolute, may not provide expected security",
547                    denied_path.display()
548                ));
549            }
550        }
551
552        valid
553    }
554
555    /// Validate security settings
556    fn validate_security_settings(
557        &self,
558        errors: &mut Vec<ConfigValidationError>,
559        warnings: &mut Vec<String>,
560    ) -> bool {
561        let security_config = &self.config_profile.security;
562        let mut valid = true;
563
564        // Check if path validation is disabled in production
565        if !security_config.validate_paths {
566            errors.push(ConfigValidationError {
567                field: "security.validate_paths".to_string(),
568                error_type: ConfigErrorType::SecurityRisk,
569                message: "Path validation is disabled, security risk in production".to_string(),
570                suggested_fix: Some("Enable validate_paths for production deployment".to_string()),
571            });
572            valid = false;
573        }
574
575        // Check rate limiting configuration
576        if security_config.rate_limiting.enabled {
577            if security_config.rate_limiting.requests_per_minute > 1000 {
578                warnings
579                    .push("Rate limit is very high, may not prevent abuse effectively".to_string());
580            }
581
582            if security_config.rate_limiting.max_concurrent > 50 {
583                warnings.push(
584                    "Max concurrent requests is very high, may cause resource exhaustion"
585                        .to_string(),
586                );
587            }
588        } else {
589            warnings
590                .push("Rate limiting is disabled, consider enabling for production".to_string());
591        }
592
593        // Check audit logging
594        if !security_config.enable_audit_log {
595            warnings
596                .push("Audit logging is disabled, enable for production compliance".to_string());
597        }
598
599        valid
600    }
601
602    /// Validate monitoring settings
603    fn validate_monitoring_settings(
604        &self,
605        _errors: &mut [ConfigValidationError],
606        warnings: &mut Vec<String>,
607    ) -> bool {
608        let monitoring_config = &self.config_profile.monitoring;
609
610        if !monitoring_config.enabled {
611            warnings.push(
612                "Performance monitoring is disabled, enable for production visibility".to_string(),
613            );
614        }
615
616        if monitoring_config.export_metrics && monitoring_config.metrics_export_path.is_none() {
617            warnings.push("Metrics export enabled but no export path configured".to_string());
618        }
619
620        true // Monitoring configuration rarely prevents startup
621    }
622
623    /// Validate caching settings
624    fn validate_caching_settings(
625        &self,
626        _errors: &mut [ConfigValidationError],
627        warnings: &mut Vec<String>,
628    ) -> bool {
629        let caching_config = &self.config_profile.caching;
630
631        if caching_config.enabled && caching_config.max_cache_size_mb > 10240 {
632            warnings
633                .push("Cache size is very large (>10GB), ensure sufficient disk space".to_string());
634        }
635
636        if caching_config.analysis_ttl > Duration::from_secs(86400) {
637            warnings.push("Analysis cache TTL is very long (>24h), may use stale data".to_string());
638        }
639
640        true
641    }
642
643    /// Validate path accessibility
644    async fn validate_path_access(
645        &mut self,
646        path: &Path,
647        need_read: bool,
648        need_write: bool,
649    ) -> Result<()> {
650        // Check cache first
651        if let Some(cached) = self.validation_cache.path_validations.get(path) {
652            if cached.validated_at.elapsed().unwrap_or_default() < Duration::from_secs(300) {
653                if !cached.accessible
654                    || (need_read && !cached.readable)
655                    || (need_write && !cached.writable)
656                {
657                    return Err(anyhow::anyhow!("Path validation failed (cached)"));
658                }
659                return Ok(());
660            }
661        }
662
663        // Perform actual validation
664        let accessible = path.exists() || path.parent().is_some_and(|p| p.exists());
665        let readable = accessible && std::fs::metadata(path).is_ok();
666        let writable = if accessible {
667            // Try to create a temporary file to test write access
668            let test_file = path.join(".test_write_access");
669            std::fs::write(&test_file, "test").is_ok() && std::fs::remove_file(&test_file).is_ok()
670        } else {
671            false
672        };
673
674        // Cache the result
675        self.validation_cache.path_validations.insert(
676            path.to_path_buf(),
677            PathValidationResult {
678                accessible,
679                readable,
680                writable,
681                validated_at: SystemTime::now(),
682            },
683        );
684
685        // Check requirements
686        if !accessible || (need_read && !readable) || (need_write && !writable) {
687            return Err(anyhow::anyhow!(
688                "Path requirements not met: accessible={}, readable={}, writable={}",
689                accessible,
690                readable,
691                writable
692            ));
693        }
694
695        Ok(())
696    }
697
698    /// Validate system readiness
699    async fn validate_system_readiness(&mut self) -> Result<SystemReadinessResult> {
700        debug!("Validating system readiness");
701
702        let system_requirements = self.check_system_requirements().await;
703        let runtime_environment = self.check_runtime_environment().await;
704        let resource_availability = self.check_resource_availability().await;
705
706        let ready = system_requirements.minimum_memory_available
707            && system_requirements.minimum_disk_space
708            && runtime_environment.rust_version_compatible
709            && resource_availability.can_bind_to_stdio;
710
711        Ok(SystemReadinessResult {
712            ready,
713            system_requirements,
714            runtime_environment,
715            resource_availability,
716        })
717    }
718
719    /// Check system requirements
720    async fn check_system_requirements(&self) -> SystemRequirementsCheck {
721        // Simplified system requirements check
722        SystemRequirementsCheck {
723            minimum_memory_available: true, // Would check actual system memory
724            minimum_disk_space: true,       // Would check actual disk space
725            required_permissions: true,     // Would check file system permissions
726            system_architecture_supported: true, // Would check CPU architecture
727        }
728    }
729
730    /// Check runtime environment
731    async fn check_runtime_environment(&mut self) -> RuntimeEnvironmentCheck {
732        // Check if we've validated recently
733        if let Some(last_check) = self.validation_cache.last_system_check {
734            if last_check.elapsed().unwrap_or_default() < Duration::from_secs(300) {
735                // Use cached result for 5 minutes
736                return RuntimeEnvironmentCheck {
737                    rust_version_compatible: true,
738                    required_features_available: true,
739                    environment_variables_set: true,
740                    network_connectivity: true, // Simplified
741                };
742            }
743        }
744
745        self.validation_cache.last_system_check = Some(SystemTime::now());
746
747        RuntimeEnvironmentCheck {
748            rust_version_compatible: true,     // Would check actual Rust version
749            required_features_available: true, // Would check feature flags
750            environment_variables_set: std::env::var("RUST_LOG").is_ok(), // Check some env vars
751            network_connectivity: true,        // Simplified for stdio transport
752        }
753    }
754
755    /// Check resource availability
756    async fn check_resource_availability(&self) -> ResourceAvailabilityCheck {
757        ResourceAvailabilityCheck {
758            available_memory_mb: 4096,      // Would get actual available memory
759            available_disk_space_mb: 10240, // Would get actual disk space
760            cpu_cores_available: num_cpus::get(),
761            can_create_temp_files: std::env::temp_dir().exists(),
762            can_bind_to_stdio: true, // Always true for MCP stdio transport
763        }
764    }
765
766    /// Validate security configuration and detect vulnerabilities
767    async fn validate_security(&self) -> Result<SecurityValidationResult> {
768        debug!("Validating security configuration");
769
770        let mut vulnerabilities = Vec::new();
771        let mut recommendations = Vec::new();
772        let security_config = &self.config_profile.security;
773
774        // Check for path traversal vulnerabilities
775        if !security_config.validate_paths {
776            vulnerabilities.push(SecurityVulnerability {
777                severity: SecuritySeverity::High,
778                category: SecurityCategory::PathTraversal,
779                description:
780                    "Path validation is disabled, allowing potential path traversal attacks"
781                        .to_string(),
782                mitigation: "Enable validate_paths in security configuration".to_string(),
783            });
784        }
785
786        // Check access control
787        if security_config.allowed_paths.is_empty() && security_config.denied_paths.is_empty() {
788            recommendations.push(SecurityRecommendation {
789                priority: SecurityPriority::Medium,
790                description: "Configure allowed or denied paths for access control".to_string(),
791                implementation: "Add paths to allowed_paths or denied_paths in security config"
792                    .to_string(),
793            });
794        }
795
796        // Check audit logging
797        if !security_config.enable_audit_log {
798            recommendations.push(SecurityRecommendation {
799                priority: SecurityPriority::Medium,
800                description: "Enable audit logging for security compliance".to_string(),
801                implementation: "Set enable_audit_log to true and configure audit_log_path"
802                    .to_string(),
803            });
804        }
805
806        // Calculate security score
807        let security_score = self.calculate_security_score(&vulnerabilities, &recommendations);
808
809        Ok(SecurityValidationResult {
810            secure: vulnerabilities.iter().all(|v| {
811                !matches!(
812                    v.severity,
813                    SecuritySeverity::Critical | SecuritySeverity::High
814                )
815            }),
816            vulnerabilities,
817            recommendations,
818            security_score,
819        })
820    }
821
822    /// Calculate security score based on vulnerabilities and recommendations
823    fn calculate_security_score(
824        &self,
825        vulnerabilities: &[SecurityVulnerability],
826        recommendations: &[SecurityRecommendation],
827    ) -> u32 {
828        let mut score = 100u32;
829
830        // Deduct points for vulnerabilities
831        for vuln in vulnerabilities {
832            let deduction = match vuln.severity {
833                SecuritySeverity::Critical => 30,
834                SecuritySeverity::High => 20,
835                SecuritySeverity::Medium => 10,
836                SecuritySeverity::Low => 5,
837            };
838            score = score.saturating_sub(deduction);
839        }
840
841        // Deduct smaller amounts for recommendations
842        for rec in recommendations {
843            let deduction = match rec.priority {
844                SecurityPriority::Critical => 15,
845                SecurityPriority::High => 10,
846                SecurityPriority::Medium => 5,
847                SecurityPriority::Low => 2,
848            };
849            score = score.saturating_sub(deduction);
850        }
851
852        score
853    }
854
855    /// Validate performance configuration
856    async fn validate_performance(&self) -> Result<PerformanceValidationResult> {
857        debug!("Validating performance configuration");
858
859        let mut bottlenecks = Vec::new();
860        let mut optimizations = Vec::new();
861        let config = &self.config_profile.settings;
862
863        // Check memory configuration
864        if config.memory_limit_mb < 1024 {
865            bottlenecks.push(PerformanceBottleneck {
866                component: "memory".to_string(),
867                severity: BottleneckSeverity::Significant,
868                description: "Memory limit is low, may cause frequent garbage collection"
869                    .to_string(),
870                impact: "Increased latency and reduced throughput".to_string(),
871                solution: "Increase memory_limit_mb to at least 1024MB".to_string(),
872            });
873        }
874
875        // Check batch size optimization
876        if config.batch_size < 10 {
877            optimizations.push(PerformanceOptimization {
878                component: "indexing".to_string(),
879                optimization_type: OptimizationType::Concurrency,
880                description: "Small batch size may underutilize system resources".to_string(),
881                expected_improvement: "20-40% faster indexing".to_string(),
882                implementation_effort: ImplementationEffort::Low,
883            });
884        }
885
886        // Check caching configuration
887        if !self.config_profile.caching.enabled {
888            optimizations.push(PerformanceOptimization {
889                component: "caching".to_string(),
890                optimization_type: OptimizationType::Caching,
891                description: "Enable caching to improve response times for repeated queries"
892                    .to_string(),
893                expected_improvement: "50-80% faster repeated operations".to_string(),
894                implementation_effort: ImplementationEffort::Low,
895            });
896        }
897
898        let performance_score = self.calculate_performance_score(&bottlenecks, &optimizations);
899
900        Ok(PerformanceValidationResult {
901            optimal: bottlenecks.is_empty(),
902            bottlenecks,
903            optimizations,
904            performance_score,
905        })
906    }
907
908    /// Calculate performance score
909    fn calculate_performance_score(
910        &self,
911        bottlenecks: &[PerformanceBottleneck],
912        optimizations: &[PerformanceOptimization],
913    ) -> u32 {
914        let mut score = 100u32;
915
916        // Deduct for bottlenecks
917        for bottleneck in bottlenecks {
918            let deduction = match bottleneck.severity {
919                BottleneckSeverity::Critical => 25,
920                BottleneckSeverity::Significant => 15,
921                BottleneckSeverity::Moderate => 10,
922                BottleneckSeverity::Minor => 5,
923            };
924            score = score.saturating_sub(deduction);
925        }
926
927        // Small deduction for missed optimizations
928        for optimization in optimizations {
929            let deduction = match optimization.implementation_effort {
930                ImplementationEffort::Low => 3,
931                ImplementationEffort::Medium => 2,
932                ImplementationEffort::High => 1,
933            };
934            score = score.saturating_sub(deduction);
935        }
936
937        score
938    }
939
940    /// Validate dependencies
941    async fn validate_dependencies(&mut self) -> Result<DependencyValidationResult> {
942        debug!("Validating dependencies");
943
944        // Check if we've validated recently
945        if let Some(last_check) = self.validation_cache.last_dependencies_check {
946            if last_check.elapsed().unwrap_or_default() < Duration::from_secs(600) {
947                // Use cached result for 10 minutes
948                return Ok(DependencyValidationResult {
949                    all_available: true,
950                    missing_dependencies: Vec::new(),
951                    version_conflicts: Vec::new(),
952                    optional_dependencies: Vec::new(),
953                });
954            }
955        }
956
957        self.validation_cache.last_dependencies_check = Some(SystemTime::now());
958
959        let mut missing_dependencies = Vec::new();
960        let version_conflicts = Vec::new(); // Would check actual version conflicts
961        let optional_dependencies = Vec::new(); // Would check optional features
962
963        // Check for required system tools (simplified)
964        if !self.check_git_available() {
965            missing_dependencies.push(MissingDependency {
966                name: "git".to_string(),
967                dependency_type: DependencyType::ToolDependency,
968                required_for: vec!["repository analysis".to_string()],
969                installation_hint: Some("Install git from https://git-scm.com/".to_string()),
970            });
971        }
972
973        Ok(DependencyValidationResult {
974            all_available: missing_dependencies.is_empty() && version_conflicts.is_empty(),
975            missing_dependencies,
976            version_conflicts,
977            optional_dependencies,
978        })
979    }
980
981    /// Check if git is available (simplified check)
982    fn check_git_available(&self) -> bool {
983        std::process::Command::new("git")
984            .arg("--version")
985            .output()
986            .is_ok()
987    }
988
989    /// Determine overall validation status
990    fn determine_overall_status(
991        &self,
992        config: &ConfigValidationResult,
993        system: &SystemReadinessResult,
994        security: &SecurityValidationResult,
995        performance: &PerformanceValidationResult,
996        dependencies: &DependencyValidationResult,
997    ) -> ValidationStatus {
998        // Critical failures prevent startup
999        if !config.valid || !system.ready || !security.secure || !dependencies.all_available {
1000            return ValidationStatus::Invalid;
1001        }
1002
1003        // Check for warnings
1004        let has_warnings = !config.warnings.is_empty()
1005            || !security.vulnerabilities.is_empty()
1006            || !performance.bottlenecks.is_empty();
1007
1008        if has_warnings {
1009            ValidationStatus::ValidWithWarnings
1010        } else {
1011            ValidationStatus::Valid
1012        }
1013    }
1014
1015    /// Log validation summary
1016    fn log_validation_summary(&self, result: &ValidationResult) {
1017        match result.status {
1018            ValidationStatus::Valid => {
1019                info!(
1020                    "✅ System validation completed successfully in {}ms",
1021                    result.validation_duration_ms
1022                );
1023            }
1024            ValidationStatus::ValidWithWarnings => {
1025                warn!(
1026                    "⚠️ System validation completed with warnings in {}ms",
1027                    result.validation_duration_ms
1028                );
1029
1030                for warning in &result.config_validation.warnings {
1031                    warn!("Config warning: {}", warning);
1032                }
1033
1034                for vuln in &result.security_validation.vulnerabilities {
1035                    warn!("Security issue: {:?} - {}", vuln.category, vuln.description);
1036                }
1037            }
1038            ValidationStatus::Invalid => {
1039                error!(
1040                    "❌ System validation failed in {}ms",
1041                    result.validation_duration_ms
1042                );
1043
1044                for error in &result.config_validation.errors {
1045                    error!("Config error: {} - {}", error.field, error.message);
1046                }
1047
1048                if !result.system_readiness.ready {
1049                    error!("System readiness check failed");
1050                }
1051            }
1052        }
1053    }
1054
1055    /// Generate startup health report
1056    pub async fn generate_startup_report(
1057        &mut self,
1058        _server: &CodePrismMcpServer,
1059    ) -> Result<StartupReport> {
1060        info!("Generating comprehensive startup report");
1061
1062        let validation_result = self.validate_system().await?;
1063
1064        let tool_status = self
1065            .tool_manager
1066            .as_ref()
1067            .map(|tool_manager| tool_manager.get_summary());
1068
1069        let system_info = self.collect_system_info().await;
1070
1071        Ok(StartupReport {
1072            validation_result,
1073            tool_status,
1074            system_info,
1075            server_version: env!("CARGO_PKG_VERSION").to_string(),
1076            startup_timestamp: SystemTime::now()
1077                .duration_since(UNIX_EPOCH)
1078                .unwrap_or_default()
1079                .as_secs(),
1080        })
1081    }
1082
1083    /// Collect system information for reporting
1084    async fn collect_system_info(&self) -> SystemInfo {
1085        SystemInfo {
1086            os: std::env::consts::OS.to_string(),
1087            architecture: std::env::consts::ARCH.to_string(),
1088            cpu_cores: num_cpus::get(),
1089            rust_version: std::env::var("RUSTC_VERSION").unwrap_or_else(|_| "unknown".to_string()),
1090            build_timestamp: std::env::var("BUILD_TIMESTAMP")
1091                .unwrap_or_else(|_| "unknown".to_string()),
1092            features_enabled: self.get_enabled_features(),
1093        }
1094    }
1095
1096    /// Get list of enabled features
1097    fn get_enabled_features(&self) -> Vec<String> {
1098        let mut features = Vec::new();
1099
1100        if self.config_profile.monitoring.enabled {
1101            features.push("monitoring".to_string());
1102        }
1103
1104        if self.config_profile.caching.enabled {
1105            features.push("caching".to_string());
1106        }
1107
1108        if self.config_profile.security.enable_audit_log {
1109            features.push("audit_logging".to_string());
1110        }
1111
1112        if self.config_profile.security.rate_limiting.enabled {
1113            features.push("rate_limiting".to_string());
1114        }
1115
1116        features
1117    }
1118}
1119
1120/// Comprehensive startup report
1121#[derive(Debug, Clone, Serialize, Deserialize)]
1122pub struct StartupReport {
1123    pub validation_result: ValidationResult,
1124    pub tool_status: Option<crate::tools::dynamic_enablement::ToolEnablementSummary>,
1125    pub system_info: SystemInfo,
1126    pub server_version: String,
1127    pub startup_timestamp: u64,
1128}
1129
1130/// System information
1131#[derive(Debug, Clone, Serialize, Deserialize)]
1132pub struct SystemInfo {
1133    pub os: String,
1134    pub architecture: String,
1135    pub cpu_cores: usize,
1136    pub rust_version: String,
1137    pub build_timestamp: String,
1138    pub features_enabled: Vec<String>,
1139}
1140
1141#[cfg(test)]
1142mod tests {
1143    use super::*;
1144    use crate::config::{
1145        CachingConfig, McpConfig, MonitoringConfig, SecurityConfig, ToolConfiguration,
1146    };
1147
1148    fn create_test_profile() -> McpConfigProfile {
1149        McpConfigProfile {
1150            name: "test".to_string(),
1151            description: "Test profile".to_string(),
1152            settings: McpConfig::default(),
1153            tool_config: ToolConfiguration {
1154                enabled_categories: vec![],
1155                disabled_tools: vec![],
1156                tool_configs: HashMap::new(),
1157                enablement_rules: vec![],
1158            },
1159            monitoring: MonitoringConfig::default(),
1160            security: SecurityConfig::default(),
1161            caching: CachingConfig::default(),
1162        }
1163    }
1164
1165    #[tokio::test]
1166    async fn test_system_validator_creation() {
1167        let profile = create_test_profile();
1168        let validator = SystemValidator::new(profile);
1169
1170        assert_eq!(validator.config_profile.name, "test");
1171    }
1172
1173    #[tokio::test]
1174    async fn test_configuration_validation() {
1175        let mut profile = create_test_profile();
1176        profile.settings.memory_limit_mb = 128; // Too low
1177
1178        let mut validator = SystemValidator::new(profile);
1179        let config_result = validator.validate_configuration().await.unwrap();
1180
1181        assert!(!config_result.valid);
1182        assert!(!config_result.errors.is_empty());
1183    }
1184
1185    #[tokio::test]
1186    async fn test_security_validation() {
1187        let mut profile = create_test_profile();
1188        profile.security.validate_paths = false; // Security risk
1189
1190        let validator = SystemValidator::new(profile);
1191        let security_result = validator.validate_security().await.unwrap();
1192
1193        assert!(!security_result.secure);
1194        assert!(!security_result.vulnerabilities.is_empty());
1195    }
1196
1197    #[tokio::test]
1198    async fn test_performance_validation() {
1199        let mut profile = create_test_profile();
1200        profile.settings.memory_limit_mb = 512; // Low memory
1201
1202        let validator = SystemValidator::new(profile);
1203        let perf_result = validator.validate_performance().await.unwrap();
1204
1205        assert!(!perf_result.optimal);
1206        assert!(!perf_result.bottlenecks.is_empty());
1207    }
1208}