1use crate::error::{CoreError, CoreResult, ErrorContext};
13use crate::testing::{TestConfig, TestResult};
14use std::time::{Duration, Instant};
15
16#[derive(Debug, Clone)]
18pub struct SecurityTestConfig {
19 pub max_input_size: usize,
21 pub malicious_patterns: usize,
23 pub test_bounds_checking: bool,
25 pub test_integer_overflow: bool,
27 pub test_memory_safety: bool,
29 pub test_dos_simulation: bool,
31 pub test_timeout: Duration,
33}
34
35impl Default for SecurityTestConfig {
36 fn default() -> Self {
37 Self {
38 max_input_size: 1024 * 1024, malicious_patterns: 1000,
40 test_bounds_checking: true,
41 test_integer_overflow: true,
42 test_memory_safety: true,
43 test_dos_simulation: true,
44 test_timeout: Duration::from_secs(10),
45 }
46 }
47}
48
49impl SecurityTestConfig {
50 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn with_max_input_size(mut self, size: usize) -> Self {
57 self.max_input_size = size;
58 self
59 }
60
61 pub fn with_malicious_patterns(mut self, patterns: usize) -> Self {
63 self.malicious_patterns = patterns;
64 self
65 }
66
67 pub fn with_bounds_checking(mut self, enabled: bool) -> Self {
69 self.test_bounds_checking = enabled;
70 self
71 }
72
73 pub fn with_integer_overflow(mut self, enabled: bool) -> Self {
75 self.test_integer_overflow = enabled;
76 self
77 }
78
79 pub fn with_memory_safety(mut self, enabled: bool) -> Self {
81 self.test_memory_safety = enabled;
82 self
83 }
84
85 pub fn with_dos_simulation(mut self, enabled: bool) -> Self {
87 self.test_dos_simulation = enabled;
88 self
89 }
90
91 pub fn with_test_timeout(mut self, timeout: Duration) -> Self {
93 self.test_timeout = timeout;
94 self
95 }
96}
97
98#[derive(Debug, Clone)]
100pub struct SecurityTestResult {
101 pub test_name: String,
103 pub tests_executed: usize,
105 pub vulnerabilities_found: usize,
107 pub duration: Duration,
109 pub security_issues: Vec<SecurityIssue>,
111 pub security_level: SecurityLevel,
113}
114
115#[derive(Debug, Clone)]
117pub struct SecurityIssue {
118 pub severity: SecuritySeverity,
120 pub category: SecurityCategory,
122 pub description: String,
124 pub trigger_input: String,
126 pub mitigation: Option<String>,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum SecuritySeverity {
133 Critical,
135 High,
137 Medium,
139 Low,
141 Info,
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147pub enum SecurityCategory {
148 BufferOverflow,
150 IntegerOverflow,
152 OutOfBounds,
154 MemorySafety,
156 InputValidation,
158 DenialOfService,
160 InformationDisclosure,
162 DependencyVuln,
164 ConfigSecurity,
166 ThirdPartyIntegration,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub enum SecurityLevel {
173 Insecure,
175 Vulnerable,
177 Weak,
179 Secure,
181 Hardened,
183}
184
185pub struct InputValidationTester {
187 config: SecurityTestConfig,
188}
189
190impl InputValidationTester {
191 pub fn new(config: SecurityTestConfig) -> Self {
193 Self { config }
194 }
195
196 pub fn test_malicious_inputs<F>(&self, testfunction: F) -> CoreResult<SecurityTestResult>
198 where
199 F: Fn(&[u8]) -> CoreResult<()>,
200 {
201 let start_time = Instant::now();
202 let mut result = SecurityTestResult {
203 test_name: "malicious_input_validation".to_string(),
204 tests_executed: 0,
205 vulnerabilities_found: 0,
206 duration: Duration::from_secs(0),
207 security_issues: Vec::new(),
208 security_level: SecurityLevel::Secure,
209 };
210
211 let patterns = self.generate_malicious_patterns();
213
214 for (i, pattern) in patterns.iter().enumerate() {
215 result.tests_executed += 1;
216
217 let test_start = Instant::now();
219 let test_result =
220 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| testfunction(pattern)));
221
222 let test_duration = test_start.elapsed();
223
224 match test_result {
225 Ok(Ok(())) => {
226 }
228 Ok(Err(_)) => {
229 }
231 Err(_) => {
232 result.vulnerabilities_found += 1;
234 result.security_issues.push(SecurityIssue {
235 severity: SecuritySeverity::High,
236 category: SecurityCategory::InputValidation,
237 description: "Function panicked on malicious input".to_string(),
238 trigger_input: format!("{:?}", (i, pattern)),
239 mitigation: Some(
240 "Add proper input validation and error handling".to_string(),
241 ),
242 });
243 }
244 }
245
246 if test_duration > self.config.test_timeout {
248 result.vulnerabilities_found += 1;
249 result.security_issues.push(SecurityIssue {
250 severity: SecuritySeverity::Medium,
251 category: SecurityCategory::DenialOfService,
252 description: format!("{:?}", test_duration),
253 trigger_input: format!("{:?}", (i, pattern)),
254 mitigation: Some("Add input size limits and timeouts".to_string()),
255 });
256 }
257 }
258
259 result.duration = start_time.elapsed();
260 result.security_level = self.assess_security_level(&result.security_issues);
261
262 Ok(result)
263 }
264
265 pub fn test_bounds_checking<F>(&self, testfunction: F) -> CoreResult<SecurityTestResult>
267 where
268 F: Fn(usize, usize) -> CoreResult<()>,
269 {
270 let start_time = Instant::now();
271 let mut result = SecurityTestResult {
272 test_name: "bounds_checking".to_string(),
273 tests_executed: 0,
274 vulnerabilities_found: 0,
275 duration: Duration::from_secs(0),
276 security_issues: Vec::new(),
277 security_level: SecurityLevel::Secure,
278 };
279
280 let test_cases = vec![
282 (0, 0), (0, 1), (1, 0), (usize::MAX, 1), (1, usize::MAX), (usize::MAX, usize::MAX), (usize::MAX - 1, 2), ];
290
291 for (start, length) in test_cases {
292 result.tests_executed += 1;
293
294 let test_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
295 testfunction(start, length)
296 }));
297
298 match test_result {
299 Ok(Ok(())) => {
300 if start.saturating_add(length) < start {
302 result.vulnerabilities_found += 1;
304 result.security_issues.push(SecurityIssue {
305 severity: SecuritySeverity::High,
306 category: SecurityCategory::IntegerOverflow,
307 description: "Integer overflow not detected".to_string(),
308 trigger_input: format!("{:?}", (start, length)),
309 mitigation: Some(
310 "Add overflow checks in bounds validation".to_string(),
311 ),
312 });
313 }
314 }
315 Ok(Err(_)) => {
316 }
318 Err(_) => {
319 result.vulnerabilities_found += 1;
321 result.security_issues.push(SecurityIssue {
322 severity: SecuritySeverity::Critical,
323 category: SecurityCategory::OutOfBounds,
324 description: "Function panicked on bounds check".to_string(),
325 trigger_input: format!("{:?}", (start, length)),
326 mitigation: Some("Implement safe bounds checking".to_string()),
327 });
328 }
329 }
330 }
331
332 result.duration = start_time.elapsed();
333 result.security_level = self.assess_security_level(&result.security_issues);
334
335 Ok(result)
336 }
337
338 #[allow(clippy::vec_init_then_push)]
340 fn generate_malicious_patterns(&self) -> Vec<Vec<u8>> {
341 let mut patterns = Vec::new();
342
343 patterns.push(vec![]);
345
346 patterns.push(vec![0xAA; self.config.max_input_size]);
348
349 patterns.push(vec![0x00; 100]);
351
352 patterns.push(vec![0xFF; 100]);
354
355 for size in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] {
357 if size <= self.config.max_input_size {
358 patterns.push(vec![0x41; size]); patterns.push(vec![0x90; size]); }
361 }
362
363 patterns.push(b"%s%s%s%s%s%s%s%s%s%s".to_vec());
365 patterns.push(b"%x%x%x%x%x%x%x%x%x%x".to_vec());
366 patterns.push(b"%n%n%n%n%n%n%n%n%n%n".to_vec());
367
368 patterns.push(b"' OR '1'='1".to_vec());
370 patterns.push(b"'; DROP TABLE users; --".to_vec());
371
372 patterns.push(b"../../../etc/passwd".to_vec());
374 patterns.push(b"..\\..\\..\\windows\\system32\\config\\sam".to_vec());
375
376 patterns.push(vec![0xC0, 0x80]); patterns.push(vec![0xED, 0xA0, 0x80]); patterns.push(vec![0xFF, 0xFE]); patterns.truncate(self.config.malicious_patterns);
383 patterns
384 }
385
386 fn assess_security_level(&self, issues: &[SecurityIssue]) -> SecurityLevel {
388 let critical_count = issues
389 .iter()
390 .filter(|i| i.severity == SecuritySeverity::Critical)
391 .count();
392 let high_count = issues
393 .iter()
394 .filter(|i| i.severity == SecuritySeverity::High)
395 .count();
396 let medium_count = issues
397 .iter()
398 .filter(|i| i.severity == SecuritySeverity::Medium)
399 .count();
400
401 if critical_count > 0 {
402 SecurityLevel::Insecure
403 } else if high_count > 2 {
404 SecurityLevel::Vulnerable
405 } else if high_count > 0 || medium_count > 5 {
406 SecurityLevel::Weak
407 } else if medium_count > 0 {
408 SecurityLevel::Secure
409 } else {
410 SecurityLevel::Hardened
411 }
412 }
413}
414
415pub struct MemorySafetyTester {
417 #[allow(dead_code)]
418 config: SecurityTestConfig,
419}
420
421impl MemorySafetyTester {
422 pub fn new(config: SecurityTestConfig) -> Self {
424 Self { config }
425 }
426
427 pub fn test_memory_leaks<F>(&self, testfunction: F) -> CoreResult<SecurityTestResult>
429 where
430 F: Fn() -> CoreResult<()>,
431 {
432 let start_time = Instant::now();
433 let mut result = SecurityTestResult {
434 test_name: "memory_leak_detection".to_string(),
435 tests_executed: 0,
436 vulnerabilities_found: 0,
437 duration: Duration::from_secs(0),
438 security_issues: Vec::new(),
439 security_level: SecurityLevel::Secure,
440 };
441
442 let initial_memory = self.get_memory_usage();
444
445 for i in 0..100 {
447 result.tests_executed += 1;
448
449 match testfunction() {
450 Ok(()) => {}
451 Err(_) => {
452 }
454 }
455
456 if i % 10 == 0 {
458 if let Ok(current_memory) = self.get_memory_usage() {
459 if let Ok(initial) = initial_memory {
460 let memory_growth = current_memory.saturating_sub(initial);
461
462 if memory_growth > 10 * 1024 * 1024 {
464 result.vulnerabilities_found += 1;
466 result.security_issues.push(SecurityIssue {
467 severity: SecuritySeverity::Medium,
468 category: SecurityCategory::MemorySafety,
469 description: format!(
470 "Potential memory leak detected: {} MB growth",
471 memory_growth / (1024 * 1024)
472 ),
473 trigger_input: format!("After {} iterations", i),
474 mitigation: Some(
475 "Review memory management and cleanup".to_string(),
476 ),
477 });
478 break; }
480 }
481 }
482 }
483 }
484
485 result.duration = start_time.elapsed();
486 result.security_level = self.assess_security_level(&result.security_issues);
487
488 Ok(result)
489 }
490
491 pub fn test_use_after_free(&self) -> CoreResult<SecurityTestResult> {
493 let start_time = Instant::now();
494 let result = SecurityTestResult {
495 test_name: "use_after_free_detection".to_string(),
496 tests_executed: 1,
497 vulnerabilities_found: 0,
498 duration: start_time.elapsed(),
499 security_issues: vec![SecurityIssue {
500 severity: SecuritySeverity::Info,
501 category: SecurityCategory::MemorySafety,
502 description: "Rust's ownership system prevents use-after-free vulnerabilities"
503 .to_string(),
504 trigger_input: "N/A".to_string(),
505 mitigation: Some("Continue using Rust's safe memory management".to_string()),
506 }],
507 security_level: SecurityLevel::Hardened,
508 };
509
510 Ok(result)
511 }
512
513 fn get_memory_usage(&self) -> CoreResult<usize> {
515 #[cfg(target_os = "linux")]
516 {
517 use std::fs;
518 let status = fs::read_to_string("/proc/self/status").map_err(|e| {
519 CoreError::IoError(ErrorContext::new(format!(
520 "Failed to read memory status: {}",
521 e
522 )))
523 })?;
524
525 for line in status.lines() {
526 if line.starts_with("VmRSS:") {
527 let parts: Vec<&str> = line.split_whitespace().collect();
528 if parts.len() >= 2 {
529 let kb: usize = parts[1].parse().map_err(|e| {
530 CoreError::ValidationError(crate::error::ErrorContext::new(format!(
531 "Failed to parse memory: {}",
532 e
533 )))
534 })?;
535 return Ok(kb * 1024);
536 }
537 }
538 }
539 }
540
541 Ok(0)
543 }
544
545 fn assess_security_level(&self, issues: &[SecurityIssue]) -> SecurityLevel {
547 let critical_count = issues
548 .iter()
549 .filter(|i| i.severity == SecuritySeverity::Critical)
550 .count();
551 let high_count = issues
552 .iter()
553 .filter(|i| i.severity == SecuritySeverity::High)
554 .count();
555 let medium_count = issues
556 .iter()
557 .filter(|i| i.severity == SecuritySeverity::Medium)
558 .count();
559
560 if critical_count > 0 {
561 SecurityLevel::Insecure
562 } else if high_count > 0 {
563 SecurityLevel::Vulnerable
564 } else if medium_count > 2 {
565 SecurityLevel::Weak
566 } else if medium_count > 0 {
567 SecurityLevel::Secure
568 } else {
569 SecurityLevel::Hardened
570 }
571 }
572}
573
574pub struct VulnerabilityAssessment {
576 config: SecurityTestConfig,
577}
578
579impl VulnerabilityAssessment {
580 pub fn new(config: SecurityTestConfig) -> Self {
582 Self { config }
583 }
584
585 pub fn perform_security_audit(&self) -> CoreResult<SecurityAuditReport> {
587 let start_time = Instant::now();
588
589 let mut report = SecurityAuditReport {
590 audit_timestamp: std::time::SystemTime::now(),
591 total_tests: 0,
592 passed_tests: 0,
593 failed_tests: 0,
594 vulnerabilities: Vec::new(),
595 recommendations: Vec::new(),
596 overall_score: 0.0,
597 security_level: SecurityLevel::Secure,
598 duration: Duration::from_secs(0),
599 };
600
601 self.scan_dependencies(&mut report)?;
603
604 self.analyzecode_security(&mut report)?;
606
607 self.check_configuration_security(&mut report)?;
609
610 self.assess_third_party_security(&mut report)?;
612
613 report.duration = start_time.elapsed();
614 report.overall_score = self.calculate_security_score(&report);
615 report.security_level = self.determine_security_level(report.overall_score);
616
617 Ok(report)
618 }
619
620 fn scan_dependencies(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
622 report.total_tests += 1;
623
624 let vulnerable_deps = self.check_vulnerable_dependencies()?;
626
627 if vulnerable_deps.is_empty() {
628 report.passed_tests += 1;
629 } else {
630 report.failed_tests += 1;
631 for dep in vulnerable_deps {
632 report.vulnerabilities.push(SecurityVulnerability {
633 id: dep.name.to_string(),
634 severity: SecuritySeverity::High,
635 category: SecurityCategory::DependencyVuln,
636 title: dep.name.to_string(),
637 description: dep.description,
638 affected_component: dep.name.clone(),
639 cve_id: dep.cve_id,
640 mitigation: format!("{}, {}", dep.name, dep.fixed_version),
641 });
642 }
643 }
644
645 Ok(())
646 }
647
648 fn analyzecode_security(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
650 report.total_tests += 1;
651
652 let security_issues = self.perform_static_analysis()?;
654
655 if security_issues.is_empty() {
656 report.passed_tests += 1;
657 } else {
658 report.failed_tests += 1;
659 for issue in security_issues {
660 report.vulnerabilities.push(issue);
661 }
662 }
663
664 Ok(())
665 }
666
667 fn check_configuration_security(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
669 report.total_tests += 1;
670
671 let config_issues = self.audit_configuration()?;
672
673 if config_issues.is_empty() {
674 report.passed_tests += 1;
675 report
676 .recommendations
677 .push("Configuration security: PASS".to_string());
678 } else {
679 report.failed_tests += 1;
680 for issue in config_issues {
681 report.vulnerabilities.push(issue);
682 }
683 }
684
685 Ok(())
686 }
687
688 fn assess_third_party_security(&self, report: &mut SecurityAuditReport) -> CoreResult<()> {
690 report.total_tests += 1;
691
692 let integration_issues = self.check_third_party_integrations()?;
694
695 if integration_issues.is_empty() {
696 report.passed_tests += 1;
697 report
698 .recommendations
699 .push("Third-party integrations: SECURE".to_string());
700 } else {
701 report.failed_tests += 1;
702 for issue in integration_issues {
703 report.vulnerabilities.push(issue);
704 }
705 }
706
707 Ok(())
708 }
709
710 fn check_vulnerable_dependencies(&self) -> CoreResult<Vec<VulnerableDependency>> {
712 Ok(vec![])
715 }
716
717 fn perform_static_analysis(&self) -> CoreResult<Vec<SecurityVulnerability>> {
719 let vulnerabilities = vec![SecurityVulnerability {
724 id: "SAFE-001".to_string(),
725 severity: SecuritySeverity::Info,
726 category: SecurityCategory::MemorySafety,
727 title: "Memory Safety Analysis".to_string(),
728 description: "Rust's type system prevents most memory safety vulnerabilities"
729 .to_string(),
730 affected_component: "core".to_string(),
731 cve_id: None,
732 mitigation: "Continue using Rust's safe abstractions".to_string(),
733 }];
734
735 Ok(vulnerabilities)
736 }
737
738 fn audit_configuration(&self) -> CoreResult<Vec<SecurityVulnerability>> {
740 let issues = Vec::new();
741
742 Ok(issues)
747 }
748
749 fn check_third_party_integrations(&self) -> CoreResult<Vec<SecurityVulnerability>> {
751 let issues = Vec::new();
752
753 Ok(issues)
759 }
760
761 fn calculate_security_score(&self, report: &SecurityAuditReport) -> f64 {
763 if report.total_tests == 0 {
764 return 0.0;
765 }
766
767 let base_score = (report.passed_tests as f64 / report.total_tests as f64) * 100.0;
768
769 let mut penalty = 0.0;
771 for vuln in &report.vulnerabilities {
772 match vuln.severity {
773 SecuritySeverity::Critical => penalty += 25.0,
774 SecuritySeverity::High => penalty += 15.0,
775 SecuritySeverity::Medium => penalty += 8.0,
776 SecuritySeverity::Low => penalty += 3.0,
777 SecuritySeverity::Info => penalty += 0.0,
778 }
779 }
780
781 (base_score - penalty).max(0.0)
782 }
783
784 fn determine_security_level(&self, score: f64) -> SecurityLevel {
786 match score {
787 s if s >= 95.0 => SecurityLevel::Hardened,
788 s if s >= 85.0 => SecurityLevel::Secure,
789 s if s >= 70.0 => SecurityLevel::Weak,
790 s if s >= 50.0 => SecurityLevel::Vulnerable,
791 _ => SecurityLevel::Insecure,
792 }
793 }
794}
795
796#[derive(Debug, Clone)]
798pub struct SecurityAuditReport {
799 pub audit_timestamp: std::time::SystemTime,
801 pub total_tests: usize,
803 pub passed_tests: usize,
805 pub failed_tests: usize,
807 pub vulnerabilities: Vec<SecurityVulnerability>,
809 pub recommendations: Vec<String>,
811 pub overall_score: f64,
813 pub security_level: SecurityLevel,
815 pub duration: Duration,
817}
818
819#[derive(Debug, Clone)]
821pub struct SecurityVulnerability {
822 pub id: String,
824 pub severity: SecuritySeverity,
826 pub category: SecurityCategory,
828 pub title: String,
830 pub description: String,
832 pub affected_component: String,
834 pub cve_id: Option<String>,
836 pub mitigation: String,
838}
839
840#[derive(Debug, Clone)]
842pub struct VulnerableDependency {
843 pub name: String,
845 pub current_version: String,
847 pub fixed_version: String,
849 pub description: String,
851 pub cve_id: Option<String>,
853}
854
855pub struct SecurityTestUtils;
857
858impl SecurityTestUtils {
859 pub fn create_security_test_suite(name: &str, config: TestConfig) -> crate::testing::TestSuite {
861 let mut suite = crate::testing::TestSuite::new(name, config);
862 let security_config = SecurityTestConfig::default()
863 .with_malicious_patterns(100)
864 .with_max_input_size(1024);
865
866 let security_config_1 = security_config.clone();
868 suite.add_test("malicious_input_validation", move |_runner| {
869 let tester = InputValidationTester::new(security_config_1.clone());
870
871 let result = tester.test_malicious_inputs(|input| {
872 if input.len() > 1000 {
874 Err(CoreError::ValidationError(crate::error::ErrorContext::new(
875 "Input too large",
876 )))
877 } else if input.is_empty() {
878 Err(CoreError::ValidationError(crate::error::ErrorContext::new(
879 "Input cannot be empty",
880 )))
881 } else {
882 Ok(())
883 }
884 })?;
885
886 if result.security_level == SecurityLevel::Insecure {
888 return Ok(TestResult::failure(
889 result.duration,
890 result.tests_executed,
891 format!(
892 "Critical security vulnerabilities found: {}",
893 result.vulnerabilities_found
894 ),
895 ));
896 }
897
898 Ok(TestResult::success(result.duration, result.tests_executed))
899 });
900
901 let security_config_2 = security_config.clone();
903 suite.add_test("bounds_checking", move |_runner| {
904 let tester = InputValidationTester::new(security_config_2.clone());
905
906 let result = tester.test_bounds_checking(|start, length| {
907 let end = start.checked_add(length).ok_or_else(|| {
909 CoreError::ValidationError(crate::error::ErrorContext::new(
910 "Integer overflow in bounds calculation",
911 ))
912 })?;
913
914 if end > 1000 {
915 Err(CoreError::ValidationError(crate::error::ErrorContext::new(
916 "Bounds exceed maximum allowed",
917 )))
918 } else {
919 Ok(())
920 }
921 })?;
922
923 if result.security_level == SecurityLevel::Insecure
924 || result.security_level == SecurityLevel::Vulnerable
925 {
926 return Ok(TestResult::failure(
927 result.duration,
928 result.tests_executed,
929 format!(
930 "Bounds checking vulnerabilities found: {}",
931 result.vulnerabilities_found
932 ),
933 ));
934 }
935
936 Ok(TestResult::success(result.duration, result.tests_executed))
937 });
938
939 let security_config_3 = security_config.clone();
941 suite.add_test("memory_safety", move |_runner| {
942 let tester = MemorySafetyTester::new(security_config_3.clone());
943
944 let result = tester.test_memory_leaks(|| {
945 let data = vec![0u8; 1000];
947 Ok(())
948 })?;
949
950 if result.vulnerabilities_found > 0 {
951 return Ok(TestResult::failure(
952 result.duration,
953 result.tests_executed,
954 format!(
955 "Memory safety issues found: {}",
956 result.vulnerabilities_found
957 ),
958 ));
959 }
960
961 Ok(TestResult::success(result.duration, result.tests_executed))
962 });
963
964 let security_config_clone2 = security_config.clone();
966 suite.add_test("use_after_free", move |_runner| {
967 let tester = MemorySafetyTester::new(security_config_clone2.clone());
968 let result = tester.test_use_after_free()?;
969
970 Ok(TestResult::success(result.duration, result.tests_executed))
972 });
973
974 let security_config_clone3 = security_config.clone();
976 suite.add_test("vulnerability_assessment", move |_runner| {
977 let assessment = VulnerabilityAssessment::new(security_config_clone3.clone());
978 let report = assessment.perform_security_audit()?;
979
980 if report.security_level == SecurityLevel::Insecure
981 || report.security_level == SecurityLevel::Vulnerable
982 {
983 return Ok(TestResult::failure(
984 report.duration,
985 report.total_tests,
986 format!(
987 "Security audit failed: {} vulnerabilities found, score: {:.1}",
988 report.vulnerabilities.len(),
989 report.overall_score
990 ),
991 ));
992 }
993
994 Ok(TestResult::success(report.duration, report.total_tests))
995 });
996
997 suite
998 }
999}
1000
1001#[cfg(test)]
1002mod tests {
1003 use super::*;
1004
1005 #[test]
1006 fn test_security_config() {
1007 let config = SecurityTestConfig::new()
1008 .with_max_input_size(2048)
1009 .with_malicious_patterns(500)
1010 .with_bounds_checking(true)
1011 .with_memory_safety(false);
1012
1013 assert_eq!(config.max_input_size, 2048);
1014 assert_eq!(config.malicious_patterns, 500);
1015 assert!(config.test_bounds_checking);
1016 assert!(!config.test_memory_safety);
1017 }
1018
1019 #[test]
1020 fn test_security_severity() {
1021 assert_eq!(SecuritySeverity::Critical, SecuritySeverity::Critical);
1022 assert_ne!(SecuritySeverity::Critical, SecuritySeverity::High);
1023 }
1024
1025 #[test]
1026 fn test_security_level_assessment() {
1027 let tester = InputValidationTester::new(SecurityTestConfig::default());
1028
1029 let level = tester.assess_security_level(&[]);
1031 assert_eq!(level, SecurityLevel::Hardened);
1032
1033 let critical_issue = SecurityIssue {
1035 severity: SecuritySeverity::Critical,
1036 category: SecurityCategory::BufferOverflow,
1037 description: "Test issue".to_string(),
1038 trigger_input: "test".to_string(),
1039 mitigation: None,
1040 };
1041 let level = tester.assess_security_level(&[critical_issue]);
1042 assert_eq!(level, SecurityLevel::Insecure);
1043 }
1044
1045 #[test]
1046 fn test_malicious_pattern_generation() {
1047 let tester =
1048 InputValidationTester::new(SecurityTestConfig::default().with_malicious_patterns(10));
1049 let patterns = tester.generate_malicious_patterns();
1050
1051 assert_eq!(patterns.len(), 10);
1052 assert!(patterns.iter().any(|p| p.is_empty())); }
1054
1055 #[test]
1056 fn test_vulnerability_assessment() {
1057 let assessment = VulnerabilityAssessment::new(SecurityTestConfig::default());
1058 let report = assessment
1059 .perform_security_audit()
1060 .expect("Operation failed");
1061
1062 assert!(report.total_tests > 0);
1063 assert!(report.passed_tests > 0);
1064 assert!(report.overall_score >= 0.0);
1065 assert!(report.overall_score <= 100.0);
1066 }
1067
1068 #[test]
1069 fn test_security_score_calculation() {
1070 let assessment = VulnerabilityAssessment::new(SecurityTestConfig::default());
1071
1072 let report = SecurityAuditReport {
1074 audit_timestamp: std::time::SystemTime::now(),
1075 total_tests: 10,
1076 passed_tests: 10,
1077 failed_tests: 0,
1078 vulnerabilities: vec![],
1079 recommendations: vec![],
1080 overall_score: 0.0,
1081 security_level: SecurityLevel::Secure,
1082 duration: Duration::from_secs(1),
1083 };
1084
1085 let score = assessment.calculate_security_score(&report);
1086 assert_eq!(score, 100.0);
1087
1088 let report_with_critical = SecurityAuditReport {
1090 audit_timestamp: std::time::SystemTime::now(),
1091 total_tests: 10,
1092 passed_tests: 9,
1093 failed_tests: 1,
1094 vulnerabilities: vec![SecurityVulnerability {
1095 id: "TEST-001".to_string(),
1096 severity: SecuritySeverity::Critical,
1097 category: SecurityCategory::MemorySafety,
1098 title: "Test vulnerability".to_string(),
1099 description: "Test description".to_string(),
1100 affected_component: "test".to_string(),
1101 cve_id: None,
1102 mitigation: "Test mitigation".to_string(),
1103 }],
1104 recommendations: vec![],
1105 overall_score: 0.0,
1106 security_level: SecurityLevel::Secure,
1107 duration: Duration::from_secs(1),
1108 };
1109
1110 let score_with_critical = assessment.calculate_security_score(&report_with_critical);
1111 assert!(score_with_critical < 100.0);
1112 assert!(score_with_critical >= 0.0);
1113 }
1114
1115 #[test]
1116 fn test_security_level_determination() {
1117 let assessment = VulnerabilityAssessment::new(SecurityTestConfig::default());
1118
1119 assert_eq!(
1120 assessment.determine_security_level(100.0),
1121 SecurityLevel::Hardened
1122 );
1123 assert_eq!(
1124 assessment.determine_security_level(90.0),
1125 SecurityLevel::Secure
1126 );
1127 assert_eq!(
1128 assessment.determine_security_level(75.0),
1129 SecurityLevel::Weak
1130 );
1131 assert_eq!(
1132 assessment.determine_security_level(60.0),
1133 SecurityLevel::Vulnerable
1134 );
1135 assert_eq!(
1136 assessment.determine_security_level(30.0),
1137 SecurityLevel::Insecure
1138 );
1139 }
1140}