From 655585d9ef047309b9cd2c6fe3c6799e2a329922 Mon Sep 17 00:00:00 2001 From: pandaadir05 Date: Thu, 20 Nov 2025 15:13:16 +0200 Subject: [PATCH] Fix all clippy lints and pass CI checks - Box large enum variants in EventData to reduce memory footprint - Add Default trait implementations for types with new() methods - Replace or_insert_with(Vec::new) with or_default() - Convert vec init+push patterns to vec! macro - Fix field reassignment with default initialization - Convert match to if for simple equality checks - Remove unused Backend type parameters from TUI draw functions - Apply rustfmt formatting All tests passing (24 total). Zero clippy warnings. Ready for CI/CD. --- ghost-core/src/streaming.rs | 10 +- ghost-core/src/testing.rs | 230 +++++++++++++--------------- ghost-core/src/threat_intel.rs | 34 +++- ghost-core/tests/detection_tests.rs | 12 +- ghost-tui/src/app.rs | 19 +-- ghost-tui/src/main.rs | 2 +- ghost-tui/src/ui.rs | 46 +++--- 7 files changed, 187 insertions(+), 166 deletions(-) diff --git a/ghost-core/src/streaming.rs b/ghost-core/src/streaming.rs index 41050a9..c6ba97e 100644 --- a/ghost-core/src/streaming.rs +++ b/ghost-core/src/streaming.rs @@ -75,11 +75,11 @@ pub enum EventSeverity { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum EventData { - Detection(DetectionEventData), - ThreatIntel(ThreatIntelEventData), + Detection(Box), + ThreatIntel(Box), Evasion(EvasionEventData), System(SystemEventData), - Alert(AlertEventData), + Alert(Box), Performance(PerformanceEventData), } @@ -559,11 +559,11 @@ impl EventStreamingSystem { ThreatLevel::Suspicious => EventSeverity::Medium, ThreatLevel::Malicious => EventSeverity::High, }, - data: EventData::Detection(DetectionEventData { + data: EventData::Detection(Box::new(DetectionEventData { detection_result: detection, analysis_duration: Duration::from_millis(100), // Would be actual duration confidence_threshold: 0.7, - }), + })), correlation_id: None, tags: vec!["process-injection".to_string(), "detection".to_string()], }; diff --git a/ghost-core/src/testing.rs b/ghost-core/src/testing.rs index e5857b1..d736836 100644 --- a/ghost-core/src/testing.rs +++ b/ghost-core/src/testing.rs @@ -398,80 +398,78 @@ impl TestFramework { /// Create detection engine unit tests fn create_detection_engine_tests(&mut self) { - let mut test_cases = Vec::new(); - - // Test clean process detection - test_cases.push(TestCase { - name: "clean_process_detection".to_string(), - description: "Verify clean processes are not flagged".to_string(), - test_function: TestFunction::DetectionTest(DetectionTestParams { - process_data: ProcessTestData { - name: "notepad.exe".to_string(), - pid: 1234, - path: Some("C:\\Windows\\System32\\notepad.exe".to_string()), - thread_count: 1, - suspicious_indicators: Vec::new(), - }, - memory_data: vec![MemoryTestData { - base_address: 0x400000, - size: 0x10000, - protection: MemoryProtection::ReadExecute, - contains_shellcode: false, - shellcode_pattern: None, - }], - thread_data: vec![ThreadTestData { - tid: 5678, - entry_point: 0x401000, - stack_base: 0x500000, - stack_size: 0x10000, - is_suspicious: false, - }], - injection_type: None, - }), - expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Clean), - timeout: Duration::from_secs(5), - tags: vec!["unit".to_string(), "detection".to_string()], - }); - - // Test malicious process detection - test_cases.push(TestCase { - name: "malicious_process_detection".to_string(), - description: "Verify malicious processes are properly detected".to_string(), - test_function: TestFunction::DetectionTest(DetectionTestParams { - process_data: ProcessTestData { - name: "malware.exe".to_string(), - pid: 9999, - path: Some("C:\\Temp\\malware.exe".to_string()), - thread_count: 5, - suspicious_indicators: vec![ - "High RWX memory usage".to_string(), - "Suspicious API calls".to_string(), - ], - }, - memory_data: vec![MemoryTestData { - base_address: 0x200000, - size: 0x1000, - protection: MemoryProtection::ReadWriteExecute, - contains_shellcode: true, - shellcode_pattern: Some(vec![0x90, 0x90, 0xEB, 0xFE]), // NOP NOP JMP -2 - }], - thread_data: vec![ThreadTestData { - tid: 1111, - entry_point: 0x200000, - stack_base: 0x600000, - stack_size: 0x10000, - is_suspicious: true, - }], - injection_type: Some(InjectionTestType::ShellcodeInjection), - }), - expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Malicious), - timeout: Duration::from_secs(10), - tags: vec![ - "unit".to_string(), - "detection".to_string(), - "malware".to_string(), - ], - }); + let test_cases = vec![ + TestCase { + name: "clean_process_detection".to_string(), + description: "Verify clean processes are not flagged".to_string(), + test_function: TestFunction::DetectionTest(DetectionTestParams { + process_data: ProcessTestData { + name: "notepad.exe".to_string(), + pid: 1234, + path: Some("C:\\Windows\\System32\\notepad.exe".to_string()), + thread_count: 1, + suspicious_indicators: Vec::new(), + }, + memory_data: vec![MemoryTestData { + base_address: 0x400000, + size: 0x10000, + protection: MemoryProtection::ReadExecute, + contains_shellcode: false, + shellcode_pattern: None, + }], + thread_data: vec![ThreadTestData { + tid: 5678, + entry_point: 0x401000, + stack_base: 0x500000, + stack_size: 0x10000, + is_suspicious: false, + }], + injection_type: None, + }), + expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Clean), + timeout: Duration::from_secs(5), + tags: vec!["unit".to_string(), "detection".to_string()], + }, + // Test malicious process detection + TestCase { + name: "malicious_process_detection".to_string(), + description: "Verify malicious processes are properly detected".to_string(), + test_function: TestFunction::DetectionTest(DetectionTestParams { + process_data: ProcessTestData { + name: "malware.exe".to_string(), + pid: 9999, + path: Some("C:\\Temp\\malware.exe".to_string()), + thread_count: 5, + suspicious_indicators: vec![ + "High RWX memory usage".to_string(), + "Suspicious API calls".to_string(), + ], + }, + memory_data: vec![MemoryTestData { + base_address: 0x200000, + size: 0x1000, + protection: MemoryProtection::ReadWriteExecute, + contains_shellcode: true, + shellcode_pattern: Some(vec![0x90, 0x90, 0xEB, 0xFE]), // NOP NOP JMP -2 + }], + thread_data: vec![ThreadTestData { + tid: 1111, + entry_point: 0x200000, + stack_base: 0x600000, + stack_size: 0x10000, + is_suspicious: true, + }], + injection_type: Some(InjectionTestType::ShellcodeInjection), + }), + expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Malicious), + timeout: Duration::from_secs(10), + tags: vec![ + "unit".to_string(), + "detection".to_string(), + "malware".to_string(), + ], + }, + ]; let test_suite = TestSuite { name: "detection_engine_tests".to_string(), @@ -487,10 +485,7 @@ impl TestFramework { /// Create shellcode detection tests fn create_shellcode_detection_tests(&mut self) { - let mut test_cases = Vec::new(); - - // Test common shellcode patterns - test_cases.push(TestCase { + let test_cases = vec![TestCase { name: "common_shellcode_patterns".to_string(), description: "Detect common shellcode patterns".to_string(), test_function: TestFunction::DetectionTest(DetectionTestParams { @@ -519,7 +514,7 @@ impl TestFramework { expected_result: ExpectedResult::IndicatorPresent("Shellcode detected".to_string()), timeout: Duration::from_secs(5), tags: vec!["unit".to_string(), "shellcode".to_string()], - }); + }]; let test_suite = TestSuite { name: "shellcode_detection_tests".to_string(), @@ -535,9 +530,7 @@ impl TestFramework { /// Create process hollowing detection tests fn create_process_hollowing_tests(&mut self) { - let mut test_cases = Vec::new(); - - test_cases.push(TestCase { + let test_cases = vec![TestCase { name: "process_hollowing_detection".to_string(), description: "Detect process hollowing techniques".to_string(), test_function: TestFunction::DetectionTest(DetectionTestParams { @@ -564,7 +557,7 @@ impl TestFramework { expected_result: ExpectedResult::IndicatorPresent("Process hollowing".to_string()), timeout: Duration::from_secs(10), tags: vec!["unit".to_string(), "hollowing".to_string()], - }); + }]; let test_suite = TestSuite { name: "process_hollowing_tests".to_string(), @@ -580,9 +573,7 @@ impl TestFramework { /// Create evasion detection tests fn create_evasion_detection_tests(&mut self) { - let mut test_cases = Vec::new(); - - test_cases.push(TestCase { + let test_cases = vec![TestCase { name: "anti_debug_detection".to_string(), description: "Detect anti-debugging techniques".to_string(), test_function: TestFunction::DetectionTest(DetectionTestParams { @@ -603,7 +594,7 @@ impl TestFramework { expected_result: ExpectedResult::IndicatorPresent("Evasion technique".to_string()), timeout: Duration::from_secs(15), tags: vec!["unit".to_string(), "evasion".to_string()], - }); + }]; let test_suite = TestSuite { name: "evasion_detection_tests".to_string(), @@ -625,39 +616,38 @@ impl TestFramework { /// Create performance benchmark tests fn create_performance_tests(&mut self) { - let mut benchmarks = Vec::new(); - - benchmarks.push(Benchmark { - name: "single_process_analysis".to_string(), - description: "Benchmark single process analysis performance".to_string(), - benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark { - process_count: 1, - complexity_level: ComplexityLevel::Moderate, - }), - warm_up_iterations: 10, - measurement_iterations: 100, - target_metrics: vec![ - PerformanceMetric::ExecutionTime, - PerformanceMetric::MemoryUsage, - PerformanceMetric::CPUUtilization, - ], - }); - - benchmarks.push(Benchmark { - name: "bulk_process_analysis".to_string(), - description: "Benchmark bulk process analysis performance".to_string(), - benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark { - process_count: 100, - complexity_level: ComplexityLevel::Simple, - }), - warm_up_iterations: 5, - measurement_iterations: 20, - target_metrics: vec![ - PerformanceMetric::ThroughputRate, - PerformanceMetric::LatencyP95, - PerformanceMetric::MemoryUsage, - ], - }); + let benchmarks = vec![ + Benchmark { + name: "single_process_analysis".to_string(), + description: "Benchmark single process analysis performance".to_string(), + benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark { + process_count: 1, + complexity_level: ComplexityLevel::Moderate, + }), + warm_up_iterations: 10, + measurement_iterations: 100, + target_metrics: vec![ + PerformanceMetric::ExecutionTime, + PerformanceMetric::MemoryUsage, + PerformanceMetric::CPUUtilization, + ], + }, + Benchmark { + name: "bulk_process_analysis".to_string(), + description: "Benchmark bulk process analysis performance".to_string(), + benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark { + process_count: 100, + complexity_level: ComplexityLevel::Simple, + }), + warm_up_iterations: 5, + measurement_iterations: 20, + target_metrics: vec![ + PerformanceMetric::ThroughputRate, + PerformanceMetric::LatencyP95, + PerformanceMetric::MemoryUsage, + ], + }, + ]; let benchmark_suite = BenchmarkSuite { name: "performance_benchmarks".to_string(), diff --git a/ghost-core/src/threat_intel.rs b/ghost-core/src/threat_intel.rs index 15f5a99..ce379cb 100644 --- a/ghost-core/src/threat_intel.rs +++ b/ghost-core/src/threat_intel.rs @@ -296,6 +296,12 @@ pub struct CertificateInfo { pub valid_to: SystemTime, } +impl Default for ThreatIntelligence { + fn default() -> Self { + Self::new() + } +} + impl ThreatIntelligence { pub fn new() -> Self { Self { @@ -551,6 +557,12 @@ impl ThreatIntelligence { } } +impl Default for IocDatabase { + fn default() -> Self { + Self::new() + } +} + impl IocDatabase { pub fn new() -> Self { Self { @@ -570,13 +582,13 @@ impl IocDatabase { IocType::FileHash => { self.hash_index .entry(ioc.value.clone()) - .or_insert_with(Vec::new) + .or_default() .push(ioc.id.clone()); } IocType::MemorySignature | IocType::BehaviorPattern => { self.pattern_index .entry(ioc.value.clone()) - .or_insert_with(Vec::new) + .or_default() .push(ioc.id.clone()); } _ => {} @@ -637,6 +649,12 @@ impl IocDatabase { } } +impl Default for AttributionEngine { + fn default() -> Self { + Self::new() + } +} + impl AttributionEngine { pub fn new() -> Self { Self { @@ -725,6 +743,12 @@ impl AttributionEngine { } } +impl Default for SimilarityCalculator { + fn default() -> Self { + Self::new() + } +} + impl SimilarityCalculator { pub fn new() -> Self { Self { @@ -735,6 +759,12 @@ impl SimilarityCalculator { } } +impl Default for ReputationCache { + fn default() -> Self { + Self::new() + } +} + impl ReputationCache { pub fn new() -> Self { Self { diff --git a/ghost-core/tests/detection_tests.rs b/ghost-core/tests/detection_tests.rs index 8578f2c..bfe99d1 100644 --- a/ghost-core/tests/detection_tests.rs +++ b/ghost-core/tests/detection_tests.rs @@ -139,8 +139,10 @@ mod tests { let config = DetectionConfig::default(); assert!(config.validate().is_ok()); - let mut invalid_config = DetectionConfig::default(); - invalid_config.confidence_threshold = 1.5; // Invalid + let mut invalid_config = DetectionConfig { + confidence_threshold: 1.5, // Invalid + ..Default::default() + }; assert!(invalid_config.validate().is_err()); invalid_config.confidence_threshold = -0.1; // Invalid @@ -165,8 +167,10 @@ mod tests { #[test] fn test_engine_with_custom_config() { - let mut config = DetectionConfig::default(); - config.hook_detection = false; + let config = DetectionConfig { + hook_detection: false, + ..Default::default() + }; let mut engine = DetectionEngine::with_config(Some(config)).expect("Failed to create engine"); diff --git a/ghost-tui/src/app.rs b/ghost-tui/src/app.rs index 269faba..83a37d2 100644 --- a/ghost-tui/src/app.rs +++ b/ghost-tui/src/app.rs @@ -379,19 +379,16 @@ impl App { } pub fn select_item(&mut self) { - match self.current_tab { - TabIndex::Processes => { - if let Some(i) = self.processes_state.selected() { - if let Some(process) = self.processes.get(i) { - self.selected_process = Some(process.clone()); - self.add_log_message(format!( - "Selected process: {} (PID: {})", - process.name, process.pid - )); - } + if self.current_tab == TabIndex::Processes { + if let Some(i) = self.processes_state.selected() { + if let Some(process) = self.processes.get(i) { + self.selected_process = Some(process.clone()); + self.add_log_message(format!( + "Selected process: {} (PID: {})", + process.name, process.pid + )); } } - _ => {} } } diff --git a/ghost-tui/src/main.rs b/ghost-tui/src/main.rs index c306ff3..5901e9b 100644 --- a/ghost-tui/src/main.rs +++ b/ghost-tui/src/main.rs @@ -69,7 +69,7 @@ async fn run_app(terminal: &mut Terminal, app: Arc>) - // Draw the UI terminal.draw(|f| { if let Ok(app) = app.try_lock() { - ui::draw::>(f, &app); + ui::draw(f, &app); } })?; diff --git a/ghost-tui/src/ui.rs b/ghost-tui/src/ui.rs index 42eb1a0..884a506 100644 --- a/ghost-tui/src/ui.rs +++ b/ghost-tui/src/ui.rs @@ -32,7 +32,7 @@ mod colors { use colors::*; -pub fn draw(f: &mut Frame, app: &App) { +pub fn draw(f: &mut Frame, app: &App) { let size = f.size(); // Create main layout @@ -46,23 +46,23 @@ pub fn draw(f: &mut Frame, app: &App) { .split(size); // Draw header - draw_header::(f, chunks[0], app); + draw_header(f, chunks[0], app); // Draw main content based on selected tab match app.current_tab { - TabIndex::Overview => draw_overview::(f, chunks[1], app), - TabIndex::Processes => draw_processes::(f, chunks[1], app), - TabIndex::Detections => draw_detections::(f, chunks[1], app), - TabIndex::Memory => draw_memory::(f, chunks[1], app), - TabIndex::Logs => draw_logs::(f, chunks[1], app), + TabIndex::Overview => draw_overview(f, chunks[1], app), + TabIndex::Processes => draw_processes(f, chunks[1], app), + TabIndex::Detections => draw_detections(f, chunks[1], app), + TabIndex::Memory => draw_memory(f, chunks[1], app), + TabIndex::Logs => draw_logs(f, chunks[1], app), TabIndex::ThreatIntel => {} // TODO: Implement threat intel view } // Draw footer - draw_footer::(f, chunks[2], app); + draw_footer(f, chunks[2], app); } -fn draw_header(f: &mut Frame, area: Rect, app: &App) { +fn draw_header(f: &mut Frame, area: Rect, app: &App) { let titles = app.get_tab_titles(); let tabs = Tabs::new(titles) .block( @@ -84,7 +84,7 @@ fn draw_header(f: &mut Frame, area: Rect, app: &App) { f.render_widget(tabs, area); } -fn draw_footer(f: &mut Frame, area: Rect, app: &App) { +fn draw_footer(f: &mut Frame, area: Rect, app: &App) { let help_text = match app.current_tab { TabIndex::Overview => { "Up/Down: Navigate | Tab: Switch tabs | R: Refresh | C: Clear | Q: Quit" @@ -112,7 +112,7 @@ fn draw_footer(f: &mut Frame, area: Rect, app: &App) { f.render_widget(footer, area); } -fn draw_overview(f: &mut Frame, area: Rect, app: &App) { +fn draw_overview(f: &mut Frame, area: Rect, app: &App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([ @@ -123,16 +123,16 @@ fn draw_overview(f: &mut Frame, area: Rect, app: &App) { .split(area); // Statistics panel - draw_stats_panel::(f, chunks[0], app); + draw_stats_panel(f, chunks[0], app); // Threat level gauge - draw_threat_gauge::(f, chunks[1], app); + draw_threat_gauge(f, chunks[1], app); // Recent detections - draw_recent_detections::(f, chunks[2], app); + draw_recent_detections(f, chunks[2], app); } -fn draw_stats_panel(f: &mut Frame, area: Rect, app: &App) { +fn draw_stats_panel(f: &mut Frame, area: Rect, app: &App) { let stats_chunks = Layout::default() .direction(Direction::Horizontal) .constraints([ @@ -204,7 +204,7 @@ fn draw_stats_panel(f: &mut Frame, area: Rect, app: &App) { f.render_widget(perf_gauge, stats_chunks[3]); } -fn draw_threat_gauge(f: &mut Frame, area: Rect, app: &App) { +fn draw_threat_gauge(f: &mut Frame, area: Rect, app: &App) { let threat_level = if app.stats.malicious_processes > 0 { 100 } else if app.stats.suspicious_processes > 0 { @@ -239,7 +239,7 @@ fn draw_threat_gauge(f: &mut Frame, area: Rect, app: &App) { f.render_widget(threat_gauge, area); } -fn draw_recent_detections(f: &mut Frame, area: Rect, app: &App) { +fn draw_recent_detections(f: &mut Frame, area: Rect, app: &App) { let items: Vec = app .detections .iter() @@ -277,7 +277,7 @@ fn draw_recent_detections(f: &mut Frame, area: Rect, app: &App) { f.render_widget(list, area); } -fn draw_processes(f: &mut Frame, area: Rect, app: &App) { +fn draw_processes(f: &mut Frame, area: Rect, app: &App) { let chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(70), Constraint::Percentage(30)]) @@ -334,10 +334,10 @@ fn draw_processes(f: &mut Frame, area: Rect, app: &App) { f.render_stateful_widget(table, chunks[0], &mut state); // Process details panel - draw_process_details::(f, chunks[1], app); + draw_process_details(f, chunks[1], app); } -fn draw_process_details(f: &mut Frame, area: Rect, app: &App) { +fn draw_process_details(f: &mut Frame, area: Rect, app: &App) { let details = if let Some(ref process) = app.selected_process { format!( "PID: {}\nPPID: {}\nName: {}\nPath: {}\nThreads: {}", @@ -364,7 +364,7 @@ fn draw_process_details(f: &mut Frame, area: Rect, app: &App) { f.render_widget(paragraph, area); } -fn draw_detections(f: &mut Frame, area: Rect, app: &App) { +fn draw_detections(f: &mut Frame, area: Rect, app: &App) { let items: Vec = app .detections .iter() @@ -420,7 +420,7 @@ fn draw_detections(f: &mut Frame, area: Rect, app: &App) { f.render_stateful_widget(list, area, &mut state); } -fn draw_memory(f: &mut Frame, area: Rect, app: &App) { +fn draw_memory(f: &mut Frame, area: Rect, app: &App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(8), Constraint::Min(0)]) @@ -459,7 +459,7 @@ fn draw_memory(f: &mut Frame, area: Rect, app: &App) { f.render_widget(memory_info, chunks[1]); } -fn draw_logs(f: &mut Frame, area: Rect, app: &App) { +fn draw_logs(f: &mut Frame, area: Rect, app: &App) { let items: Vec = app .logs .iter()