//! Native diagnostics service for WireGuard, Linux networking, kernel sysctl, and reconciliation. use crate::error::ApiResult; use crate::reconciliation::ReconciliationEngine; use crate::state::AppState; use chrono::Utc; use nx9_wg_core::types::diagnostics::{ DiagnosticCheck, DiagnosticReport, DiagnosticStatus, DiagnosticSubsystem, }; use nx9_wg_network::NetworkEngine; use nx9_wireguard::WireGuardEngine; use std::sync::Arc; use uuid::Uuid; /// Native diagnostics inspection service. pub struct DiagnosticsService { state: AppState, wg_engine: Arc, net_engine: Arc, reconciler: Arc, } impl DiagnosticsService { /// Create a new diagnostics service. pub fn new( state: AppState, wg_engine: Arc, net_engine: Arc, reconciler: Arc, ) -> Self { Self { state, wg_engine, net_engine, reconciler, } } /// Run diagnostic check for a target subsystem. pub async fn run_diagnostic( &self, subsystem: DiagnosticSubsystem, peer_id: Option, ) -> ApiResult> { match subsystem { DiagnosticSubsystem::System => Ok(vec![self.diagnose_system().await?]), DiagnosticSubsystem::Network => Ok(vec![self.diagnose_network().await?]), DiagnosticSubsystem::Wan => Ok(vec![self.diagnose_wan().await?]), DiagnosticSubsystem::Wireguard => Ok(vec![self.diagnose_wireguard(None).await?]), DiagnosticSubsystem::Peer => { if let Some(id) = peer_id { Ok(vec![self.diagnose_peer(id).await?]) } else { let peers = self.state.store.list_all_peers().await?; let mut reports = Vec::new(); for p in peers { reports.push(self.diagnose_peer(p.id).await?); } if reports.is_empty() { reports.push(DiagnosticReport { subsystem: "peer".to_string(), timestamp: Utc::now().naive_utc(), overall_status: DiagnosticStatus::Pass, checks: vec![DiagnosticCheck { check_name: "enrolled_peers".to_string(), status: DiagnosticStatus::Pass, observed_value: "0 peers".to_string(), expected_value: None, diagnostic_message: "No peers are currently enrolled in the database".to_string(), remediation_hint: None, }], }); } Ok(reports) } } DiagnosticSubsystem::Routing => Ok(vec![self.diagnose_routing().await?]), DiagnosticSubsystem::Forwarding => Ok(vec![self.diagnose_forwarding().await?]), DiagnosticSubsystem::Firewall => Ok(vec![self.diagnose_firewall().await?]), DiagnosticSubsystem::Nat => Ok(vec![self.diagnose_nat().await?]), DiagnosticSubsystem::Mtu => Ok(vec![self.diagnose_mtu().await?]), DiagnosticSubsystem::Reconciliation => Ok(vec![self.diagnose_reconciliation().await?]), DiagnosticSubsystem::All => self.diagnose_all().await, } } /// System subsystem diagnostics. pub async fn diagnose_system(&self) -> ApiResult { let mut checks = Vec::new(); // Hostname let hostname = std::fs::read_to_string("/etc/hostname") .map(|s| s.trim().to_string()) .unwrap_or_else(|_| "localhost".to_string()); checks.push(DiagnosticCheck { check_name: "hostname".to_string(), status: DiagnosticStatus::Pass, observed_value: hostname, expected_value: None, diagnostic_message: "System hostname read successfully".to_string(), remediation_hint: None, }); // OS and Architecture checks.push(DiagnosticCheck { check_name: "os_architecture".to_string(), status: DiagnosticStatus::Pass, observed_value: format!("{}-{}", std::env::consts::OS, std::env::consts::ARCH), expected_value: Some("linux-*".to_string()), diagnostic_message: "Supported target platform".to_string(), remediation_hint: None, }); // Kernel Version let kernel = std::fs::read_to_string("/proc/sys/kernel/osrelease") .map(|s| s.trim().to_string()) .unwrap_or_else(|_| "Linux".to_string()); checks.push(DiagnosticCheck { check_name: "kernel_version".to_string(), status: DiagnosticStatus::Pass, observed_value: kernel, expected_value: None, diagnostic_message: "Linux kernel release inspected".to_string(), remediation_hint: None, }); // Memory Info if let Ok(mem) = std::fs::read_to_string("/proc/meminfo") { let mem_total = mem .lines() .find(|l| l.starts_with("MemTotal:")) .unwrap_or("MemTotal: unknown"); checks.push(DiagnosticCheck { check_name: "memory_status".to_string(), status: DiagnosticStatus::Pass, observed_value: mem_total.to_string(), expected_value: None, diagnostic_message: "System memory available".to_string(), remediation_hint: None, }); } // Database Health Check let db_health = self.state.store.health_check().await; match db_health { Ok(_) => checks.push(DiagnosticCheck { check_name: "sqlite_persistence".to_string(), status: DiagnosticStatus::Pass, observed_value: "connected_and_healthy".to_string(), expected_value: Some("connected_and_healthy".to_string()), diagnostic_message: "SQLite WAL persistence layer is responsive".to_string(), remediation_hint: None, }), Err(e) => checks.push(DiagnosticCheck { check_name: "sqlite_persistence".to_string(), status: DiagnosticStatus::Fail, observed_value: format!("error: {e}"), expected_value: Some("connected_and_healthy".to_string()), diagnostic_message: "Database connectivity failure".to_string(), remediation_hint: Some( "Verify database file permissions and disk space".to_string(), ), }), } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "system".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// Network subsystem diagnostics. pub async fn diagnose_network(&self) -> ApiResult { let mut checks = Vec::new(); // Interface device list if let Ok(devs) = std::fs::read_to_string("/proc/net/dev") { let iface_names: Vec = devs .lines() .skip(2) .filter_map(|l| l.split(':').next().map(|s| s.trim().to_string())) .filter(|s| !s.is_empty()) .collect(); checks.push(DiagnosticCheck { check_name: "linux_network_interfaces".to_string(), status: DiagnosticStatus::Pass, observed_value: format!( "{} interfaces ({})", iface_names.len(), iface_names.join(", ") ), expected_value: None, diagnostic_message: "Network interfaces discovered in kernel".to_string(), remediation_hint: None, }); } // DNS Configuration let resolv = std::fs::read_to_string("/etc/resolv.conf").unwrap_or_default(); let nameservers: Vec<&str> = resolv .lines() .filter(|l| l.starts_with("nameserver")) .filter_map(|l| l.split_whitespace().nth(1)) .collect(); if nameservers.is_empty() { checks.push(DiagnosticCheck { check_name: "dns_nameservers".to_string(), status: DiagnosticStatus::Warning, observed_value: "none_configured".to_string(), expected_value: Some("valid nameserver entries".to_string()), diagnostic_message: "No DNS nameservers found in /etc/resolv.conf".to_string(), remediation_hint: Some( "Configure DNS servers in /etc/resolv.conf or interface settings".to_string(), ), }); } else { checks.push(DiagnosticCheck { check_name: "dns_nameservers".to_string(), status: DiagnosticStatus::Pass, observed_value: nameservers.join(", "), expected_value: None, diagnostic_message: "System DNS nameservers configured".to_string(), remediation_hint: None, }); } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "network".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// WAN and external reachability diagnostics. pub async fn diagnose_wan(&self) -> ApiResult { let mut checks = Vec::new(); // Default Route check let routes = std::fs::read_to_string("/proc/net/route").unwrap_or_default(); let has_default_gateway = routes.lines().skip(1).any(|l| { let cols: Vec<&str> = l.split_whitespace().collect(); cols.len() > 1 && cols[1] == "00000000" }); if has_default_gateway { checks.push(DiagnosticCheck { check_name: "default_gateway_route".to_string(), status: DiagnosticStatus::Pass, observed_value: "default_gateway_present".to_string(), expected_value: Some("default_gateway_present".to_string()), diagnostic_message: "Default route to WAN/gateway is present".to_string(), remediation_hint: None, }); } else { checks.push(DiagnosticCheck { check_name: "default_gateway_route".to_string(), status: DiagnosticStatus::Warning, observed_value: "missing_default_gateway".to_string(), expected_value: Some("default_gateway_present".to_string()), diagnostic_message: "No default gateway (0.0.0.0/0) detected in kernel routing table".to_string(), remediation_hint: Some( "Verify network connection or add a default route using 'nx9-wg route add'" .to_string(), ), }); } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "wan".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// WireGuard interface diagnostics. pub async fn diagnose_wireguard( &self, interface_name: Option<&str>, ) -> ApiResult { let mut checks = Vec::new(); let interfaces = self.state.store.list_interfaces().await?; if interfaces.is_empty() { checks.push(DiagnosticCheck { check_name: "configured_interfaces".to_string(), status: DiagnosticStatus::Pass, observed_value: "0 interfaces".to_string(), expected_value: None, diagnostic_message: "No WireGuard interfaces configured yet".to_string(), remediation_hint: Some( "Create an interface using 'nx9-wg interface create'".to_string(), ), }); } for iface in &interfaces { if interface_name.is_some_and(|target| iface.name != target) { continue; } let live_stats = self .wg_engine .get_interface_stats(&iface.name) .await .ok() .flatten(); match live_stats { Some(stats) => { checks.push(DiagnosticCheck { check_name: format!("interface_{}_status", iface.name), status: DiagnosticStatus::Pass, observed_value: format!( "active: port {}, peers {}", stats.listen_port, stats.peers.len() ), expected_value: Some( iface .listen_port .map(|p| format!("port {p}")) .unwrap_or_else(|| "port auto".to_string()), ), diagnostic_message: format!( "Interface '{}' is running and responsive", iface.name ), remediation_hint: None, }); } None => { if iface.enabled { checks.push(DiagnosticCheck { check_name: format!("interface_{}_status", iface.name), status: DiagnosticStatus::Warning, observed_value: "down_or_uninitialized".to_string(), expected_value: Some("running".to_string()), diagnostic_message: format!( "Interface '{}' is enabled in database but not active in kernel", iface.name ), remediation_hint: Some( "Run 'nx9-wg reconcile apply' to synchronize interface to kernel" .to_string(), ), }); } else { checks.push(DiagnosticCheck { check_name: format!("interface_{}_status", iface.name), status: DiagnosticStatus::Pass, observed_value: "administratively_disabled".to_string(), expected_value: Some("disabled".to_string()), diagnostic_message: format!( "Interface '{}' is disabled as intended", iface.name ), remediation_hint: None, }); } } } } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "wireguard".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// Single peer diagnostics. pub async fn diagnose_peer(&self, peer_id: Uuid) -> ApiResult { let mut checks = Vec::new(); let peer = self.state.store.get_peer(peer_id).await?; match peer { Some(p) => { // Peer State checks.push(DiagnosticCheck { check_name: "lifecycle_state".to_string(), status: match p.state { nx9_wg_core::types::wireguard::PeerState::Active => DiagnosticStatus::Pass, nx9_wg_core::types::wireguard::PeerState::Disabled => { DiagnosticStatus::Warning } nx9_wg_core::types::wireguard::PeerState::Expired => { DiagnosticStatus::Warning } nx9_wg_core::types::wireguard::PeerState::Revoked => DiagnosticStatus::Fail, }, observed_value: p.state.to_string(), expected_value: Some("active".to_string()), diagnostic_message: format!("Peer '{}' is in '{}' state", p.name, p.state), remediation_hint: match p.state { nx9_wg_core::types::wireguard::PeerState::Expired => { Some("Extend or renew peer expiration date".to_string()) } nx9_wg_core::types::wireguard::PeerState::Disabled => { Some("Enable peer using 'nx9-wg peer enable'".to_string()) } _ => None, }, }); // Address allocation let v4_str = p .address_v4 .map(|a| a.to_string()) .unwrap_or_else(|| "none".to_string()); checks.push(DiagnosticCheck { check_name: "assigned_address".to_string(), status: if p.address_v4.is_some() { DiagnosticStatus::Pass } else { DiagnosticStatus::Warning }, observed_value: v4_str, expected_value: Some("valid CIDR".to_string()), diagnostic_message: format!( "Peer address assignment: allowed_ips={}", p.allowed_ips ), remediation_hint: None, }); // Expiration timeline if let Some(exp) = p.expires_at { let now = Utc::now().naive_utc(); if exp <= now { checks.push(DiagnosticCheck { check_name: "expiration_status".to_string(), status: DiagnosticStatus::Warning, observed_value: format!("expired_at_{exp}"), expected_value: Some("future_expiration".to_string()), diagnostic_message: "Peer expiration timestamp has elapsed".to_string(), remediation_hint: Some( "Update peer expiration date to restore access".to_string(), ), }); } else { checks.push(DiagnosticCheck { check_name: "expiration_status".to_string(), status: DiagnosticStatus::Pass, observed_value: format!("valid_until_{exp}"), expected_value: None, diagnostic_message: "Peer credential is within validity period" .to_string(), remediation_hint: None, }); } } } None => { checks.push(DiagnosticCheck { check_name: "peer_lookup".to_string(), status: DiagnosticStatus::Fail, observed_value: "not_found".to_string(), expected_value: Some("valid_peer_record".to_string()), diagnostic_message: format!( "Peer '{peer_id}' does not exist in SQLite database" ), remediation_hint: Some("Verify peer ID with 'nx9-wg peer list'".to_string()), }); } } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: format!("peer:{}", peer_id), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// Routing subsystem diagnostics. pub async fn diagnose_routing(&self) -> ApiResult { let mut checks = Vec::new(); let routes = self.state.store.list_routes().await?; let active_routes: Vec<_> = routes.iter().filter(|r| r.enabled).collect(); checks.push(DiagnosticCheck { check_name: "configured_routes".to_string(), status: DiagnosticStatus::Pass, observed_value: format!("{} total ({} active)", routes.len(), active_routes.len()), expected_value: None, diagnostic_message: "Kernel routing rules configured in database".to_string(), remediation_hint: None, }); let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "routing".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// IP packet forwarding diagnostics. pub async fn diagnose_forwarding(&self) -> ApiResult { let mut checks = Vec::new(); let fwd = self.net_engine.get_forwarding_status().await; match fwd { Ok(status) => { checks.push(DiagnosticCheck { check_name: "ipv4_forwarding".to_string(), status: if status.ipv4_enabled { DiagnosticStatus::Pass } else { DiagnosticStatus::Warning }, observed_value: if status.ipv4_enabled { "enabled".to_string() } else { "disabled".to_string() }, expected_value: Some("enabled".to_string()), diagnostic_message: if status.ipv4_enabled { "IPv4 packet forwarding is enabled in sysctl".to_string() } else { "IPv4 packet forwarding is disabled in sysctl; VPN clients cannot route traffic".to_string() }, remediation_hint: if !status.ipv4_enabled { Some("Enable IP forwarding with 'nx9-wg forwarding enable'".to_string()) } else { None }, }); } Err(e) => { checks.push(DiagnosticCheck { check_name: "forwarding_sysctl_read".to_string(), status: DiagnosticStatus::Fail, observed_value: format!("error: {e}"), expected_value: Some("readable".to_string()), diagnostic_message: "Failed to read kernel forwarding state".to_string(), remediation_hint: Some("Verify /proc filesystem is mounted".to_string()), }); } } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "forwarding".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// Firewall subsystem diagnostics. pub async fn diagnose_firewall(&self) -> ApiResult { let mut checks = Vec::new(); let rules = self.state.store.list_firewall_rules().await?; let active_rules: Vec<_> = rules.iter().filter(|r| r.enabled).collect(); checks.push(DiagnosticCheck { check_name: "firewall_rules_count".to_string(), status: DiagnosticStatus::Pass, observed_value: format!("{} total ({} active)", rules.len(), active_rules.len()), expected_value: None, diagnostic_message: "Configured nftables packet filtering rules".to_string(), remediation_hint: None, }); let active_nft = self.net_engine.get_active_nftables_ruleset().await; match active_nft { Ok(ruleset) => { let has_table = ruleset.contains("table inet nx9_wg"); checks.push(DiagnosticCheck { check_name: "nftables_table_nx9_wg".to_string(), status: if has_table { DiagnosticStatus::Pass } else { DiagnosticStatus::Warning }, observed_value: if has_table { "active".to_string() } else { "not_loaded".to_string() }, expected_value: Some("active".to_string()), diagnostic_message: "Dedicated table inet nx9_wg presence in kernel nftables" .to_string(), remediation_hint: if !has_table { Some("Synchronize firewall with 'nx9-wg firewall sync'".to_string()) } else { None }, }); } Err(e) => { checks.push(DiagnosticCheck { check_name: "nftables_access".to_string(), status: DiagnosticStatus::Warning, observed_value: format!("error: {e}"), expected_value: Some("accessible".to_string()), diagnostic_message: "Could not inspect live nftables ruleset".to_string(), remediation_hint: Some("Verify CAP_NET_ADMIN / root permissions".to_string()), }); } } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "firewall".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// NAT masquerade diagnostics. pub async fn diagnose_nat(&self) -> ApiResult { let mut checks = Vec::new(); let nat_setting = self .state .store .get_setting("enable_nat") .await? .map(|s| s.value == "true" || s.value == "1") .unwrap_or(true); checks.push(DiagnosticCheck { check_name: "nat_setting".to_string(), status: DiagnosticStatus::Pass, observed_value: if nat_setting { "enabled".to_string() } else { "disabled".to_string() }, expected_value: None, diagnostic_message: "NAT masquerade setting configured in database".to_string(), remediation_hint: None, }); let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "nat".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// MTU consistency and client profile diagnostics. pub async fn diagnose_mtu(&self) -> ApiResult { let mut checks = Vec::new(); let interfaces = self.state.store.list_interfaces().await?; let peers = self.state.store.list_all_peers().await?; // 1. Interface MTU Checks for iface in &interfaces { let mtu = iface.mtu.unwrap_or(1420); if mtu > 1500 { checks.push(DiagnosticCheck { check_name: format!("server_mtu_{}", iface.name), status: DiagnosticStatus::Warning, observed_value: format!("{mtu} bytes (jumbo)"), expected_value: Some("1420 bytes (<= 1500)".to_string()), diagnostic_message: format!( "Interface '{}' MTU ({mtu}) exceeds standard physical MTU 1500; may cause fragmentation on WAN egress", iface.name ), remediation_hint: Some( "Set WireGuard server MTU to 1420 to prevent packet fragmentation".to_string(), ), }); } else if mtu < 1280 { checks.push(DiagnosticCheck { check_name: format!("server_mtu_{}", iface.name), status: DiagnosticStatus::Fail, observed_value: format!("{mtu} bytes"), expected_value: Some(">= 1280 bytes".to_string()), diagnostic_message: format!( "Interface '{}' MTU ({mtu}) is below the IPv6 minimum MTU (1280)", iface.name ), remediation_hint: Some( "Increase interface MTU to at least 1280 bytes".to_string(), ), }); } else { checks.push(DiagnosticCheck { check_name: format!("server_mtu_{}", iface.name), status: DiagnosticStatus::Pass, observed_value: format!("{mtu} bytes"), expected_value: None, diagnostic_message: format!( "Server interface '{}' MTU ({mtu}) is within safe WAN limits (1280-1500)", iface.name ), remediation_hint: None, }); } // Check peer MTU consistency against server MTU let iface_peers: Vec<_> = peers .iter() .filter(|p| p.interface_id == iface.id) .collect(); for p in iface_peers { if let Some(peer_mtu) = p.mtu.filter(|&pm| pm > mtu) { checks.push(DiagnosticCheck { check_name: format!("peer_mtu_{}", p.name), status: DiagnosticStatus::Warning, observed_value: format!("{peer_mtu} bytes"), expected_value: Some(format!("<= {mtu} bytes")), diagnostic_message: format!( "Peer '{}' MTU ({peer_mtu}) exceeds server interface '{}' MTU ({mtu})", p.name, iface.name ), remediation_hint: Some( "Align peer MTU to be equal to or less than server interface MTU" .to_string(), ), }); } } } // 2. Client Profile Recommendations Check checks.push(DiagnosticCheck { check_name: "client_profile_mobile_recommendation".to_string(), status: DiagnosticStatus::Pass, observed_value: "1280 bytes (keepalive: 25s)".to_string(), expected_value: Some("1280 bytes".to_string()), diagnostic_message: "Recommended MTU for mobile/cellular connections is 1280 to prevent carrier fragmentation".to_string(), remediation_hint: None, }); checks.push(DiagnosticCheck { check_name: "client_profile_cgnat_recommendation".to_string(), status: DiagnosticStatus::Pass, observed_value: "1360 bytes (keepalive: 25s)".to_string(), expected_value: Some("1360 bytes".to_string()), diagnostic_message: "Recommended MTU for CGNAT connections is 1360 to accommodate carrier-grade NAT encapsulation".to_string(), remediation_hint: None, }); checks.push(DiagnosticCheck { check_name: "client_profile_wifi_recommendation".to_string(), status: DiagnosticStatus::Pass, observed_value: "1420 bytes (keepalive: 25s)".to_string(), expected_value: Some("1420 bytes".to_string()), diagnostic_message: "Recommended MTU for standard Wi-Fi and wired connections is 1420 bytes".to_string(), remediation_hint: None, }); let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "mtu".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// Reconciliation drift diagnostics. pub async fn diagnose_reconciliation(&self) -> ApiResult { let mut checks = Vec::new(); let plan = self.reconciler.plan().await?; checks.push(DiagnosticCheck { check_name: "overall_drift".to_string(), status: if plan.has_drift { DiagnosticStatus::Warning } else { DiagnosticStatus::Pass }, observed_value: if plan.has_drift { format!("{} drift actions pending", plan.actions.len()) } else { "zero_drift".to_string() }, expected_value: Some("zero_drift".to_string()), diagnostic_message: if plan.has_drift { "Discrepancies detected between SQLite desired state and Linux kernel state" .to_string() } else { "SQLite desired state and live kernel state are in full synchronization".to_string() }, remediation_hint: if plan.has_drift { Some("Execute 'nx9-wg reconcile apply' to synchronize changes".to_string()) } else { None }, }); for action in plan.actions { checks.push(DiagnosticCheck { check_name: format!("drift:{}:{}", action.subsystem, action.action_type), status: DiagnosticStatus::Warning, observed_value: action.resource_id, expected_value: None, diagnostic_message: action.description, remediation_hint: Some("Run 'nx9-wg reconcile apply'".to_string()), }); } let overall = Self::calculate_overall_status(&checks); Ok(DiagnosticReport { subsystem: "reconciliation".to_string(), timestamp: Utc::now().naive_utc(), overall_status: overall, checks, }) } /// Run full diagnosis across all subsystems. pub async fn diagnose_all(&self) -> ApiResult> { let mut reports = Vec::new(); reports.push(self.diagnose_system().await?); reports.push(self.diagnose_network().await?); reports.push(self.diagnose_wan().await?); reports.push(self.diagnose_wireguard(None).await?); reports.push(self.diagnose_routing().await?); reports.push(self.diagnose_forwarding().await?); reports.push(self.diagnose_firewall().await?); reports.push(self.diagnose_nat().await?); reports.push(self.diagnose_mtu().await?); reports.push(self.diagnose_reconciliation().await?); Ok(reports) } fn calculate_overall_status(checks: &[DiagnosticCheck]) -> DiagnosticStatus { if checks.iter().any(|c| c.status == DiagnosticStatus::Fail) { DiagnosticStatus::Fail } else if checks.iter().any(|c| c.status == DiagnosticStatus::Warning) { DiagnosticStatus::Warning } else { DiagnosticStatus::Pass } } }