aur_scanner_plugin/
lib.rs1use aur_scanner_core::{ScanConfig, ScanResult, Scanner, Severity};
6use colored::Colorize;
7use std::io::{self, Write};
8use std::path::Path;
9
10pub struct AurScannerPlugin {
12 scanner: Scanner,
13 interactive: bool,
14}
15
16impl AurScannerPlugin {
17 pub fn new(config: ScanConfig) -> Result<Self, aur_scanner_core::ScanError> {
19 Ok(Self {
20 scanner: Scanner::new(config)?,
21 interactive: true,
22 })
23 }
24
25 pub fn with_defaults() -> Result<Self, aur_scanner_core::ScanError> {
27 Self::new(ScanConfig::default())
28 }
29
30 pub fn set_interactive(&mut self, interactive: bool) {
32 self.interactive = interactive;
33 }
34
35 pub async fn pre_build_scan(
37 &self,
38 package_dir: &Path,
39 ) -> Result<ScanResult, aur_scanner_core::ScanError> {
40 self.scanner.scan_directory(package_dir).await
41 }
42
43 pub fn handle_results(&self, result: &ScanResult) -> bool {
47 if result.findings.is_empty() {
48 println!(
49 "{} No security issues found in {}",
50 "OK:".green().bold(),
51 result.package_name
52 );
53 return true;
54 }
55
56 println!();
57 println!(
58 "{} Security Scan Results for {}",
59 "SCAN:".cyan().bold(),
60 result.package_name.bold()
61 );
62 println!("{}", "=".repeat(60));
63
64 for finding in &result.findings {
65 let severity_str = match finding.severity {
66 Severity::Critical => "[CRITICAL]".red().bold().to_string(),
67 Severity::High => "[HIGH]".yellow().bold().to_string(),
68 Severity::Medium => "[MEDIUM]".cyan().to_string(),
69 Severity::Low => "[LOW]".to_string(),
70 Severity::Info => "[INFO]".dimmed().to_string(),
71 };
72
73 println!();
74 println!("{} {} {}", severity_str, finding.id.bold(), finding.title);
75 println!(" {}", finding.description);
76 println!(" {}", finding.recommendation.green());
77 }
78
79 println!();
80 println!("{}", "=".repeat(60));
81
82 if result.has_critical() {
84 println!(
85 "{} Critical security issues detected!",
86 "ERROR:".red().bold()
87 );
88
89 if self.interactive {
90 print!("Continue anyway? (type 'yes' to confirm): ");
91 io::stdout().flush().unwrap();
92
93 let mut response = String::new();
94 io::stdin().read_line(&mut response).unwrap();
95
96 if response.trim().to_lowercase() != "yes" {
97 println!("Installation aborted.");
98 return false;
99 }
100 } else {
101 println!("Aborting due to critical issues (non-interactive mode).");
102 return false;
103 }
104 } else if result.has_severity_or_above(Severity::High) {
105 println!(
106 "{} High severity issues detected.",
107 "WARNING:".yellow().bold()
108 );
109
110 if self.interactive {
111 print!("Continue with installation? [y/N]: ");
112 io::stdout().flush().unwrap();
113
114 let mut response = String::new();
115 io::stdin().read_line(&mut response).unwrap();
116
117 if !matches!(
118 response.trim().to_lowercase().as_str(),
119 "y" | "yes"
120 ) {
121 println!("Installation aborted.");
122 return false;
123 }
124 }
125 } else if self.interactive {
126 print!("Continue with installation? [Y/n]: ");
127 io::stdout().flush().unwrap();
128
129 let mut response = String::new();
130 io::stdin().read_line(&mut response).unwrap();
131
132 if matches!(response.trim().to_lowercase().as_str(), "n" | "no") {
133 println!("Installation aborted.");
134 return false;
135 }
136 }
137
138 true
139 }
140}