use std::path::Path;
use syncable_cli::analyzer::{SecurityAnalysisConfig, SecurityAnalyzer, analyze_project};
fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let project_path = std::env::args().nth(1).unwrap_or_else(|| ".".to_string());
println!("đ Analyzing security for project: {}", project_path);
let project_analysis = analyze_project(Path::new(&project_path))?;
println!("đ Project Analysis Summary:");
println!(
" Languages: {:?}",
project_analysis
.languages
.iter()
.map(|l| &l.name)
.collect::<Vec<_>>()
);
println!(
" Technologies: {:?}",
project_analysis
.technologies
.iter()
.map(|t| &t.name)
.collect::<Vec<_>>()
);
println!(
" Environment Variables: {}",
project_analysis.environment_variables.len()
);
let security_config = SecurityAnalysisConfig {
include_low_severity: true, check_secrets: true,
check_code_patterns: true,
check_infrastructure: true,
check_compliance: true,
frameworks_to_check: vec!["SOC2".to_string(), "GDPR".to_string(), "OWASP".to_string()],
ignore_patterns: vec![
"node_modules".to_string(),
".git".to_string(),
"target".to_string(),
],
skip_gitignored_files: true,
downgrade_gitignored_severity: false,
};
let mut security_analyzer = SecurityAnalyzer::with_config(security_config)?;
println!("\nđĄī¸ Running comprehensive security analysis...");
let security_report = security_analyzer.analyze_security(&project_analysis)?;
println!("\nđ Security Analysis Report");
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââ");
println!(
"đ Overall Security Score: {:.1}/100",
security_report.overall_score
);
println!("â ī¸ Risk Level: {:?}", security_report.risk_level);
println!("đ Total Findings: {}", security_report.total_findings);
if !security_report.findings_by_severity.is_empty() {
println!("\nđ Findings by Severity:");
for (severity, count) in &security_report.findings_by_severity {
let emoji = match severity {
syncable_cli::analyzer::SecuritySeverity::Critical => "đ¨",
syncable_cli::analyzer::SecuritySeverity::High => "â ī¸ ",
syncable_cli::analyzer::SecuritySeverity::Medium => "âĄ",
syncable_cli::analyzer::SecuritySeverity::Low => "âšī¸ ",
syncable_cli::analyzer::SecuritySeverity::Info => "đĄ",
};
println!(" {} {:?}: {}", emoji, severity, count);
}
}
if !security_report.findings_by_category.is_empty() {
println!("\nđī¸ Findings by Category:");
for (category, count) in &security_report.findings_by_category {
let emoji = match category {
syncable_cli::analyzer::SecurityCategory::SecretsExposure => "đ",
syncable_cli::analyzer::SecurityCategory::InsecureConfiguration => "âī¸ ",
syncable_cli::analyzer::SecurityCategory::CodeSecurityPattern => "đģ",
syncable_cli::analyzer::SecurityCategory::InfrastructureSecurity => "đī¸ ",
syncable_cli::analyzer::SecurityCategory::AuthenticationSecurity => "đ",
syncable_cli::analyzer::SecurityCategory::DataProtection => "đĄī¸ ",
syncable_cli::analyzer::SecurityCategory::NetworkSecurity => "đ",
syncable_cli::analyzer::SecurityCategory::Compliance => "đ",
};
println!(" {} {:?}: {}", emoji, category, count);
}
}
if !security_report.findings.is_empty() {
println!("\nđ Detailed Security Findings:");
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââ");
for (i, finding) in security_report.findings.iter().enumerate() {
let severity_emoji = match finding.severity {
syncable_cli::analyzer::SecuritySeverity::Critical => "đ¨",
syncable_cli::analyzer::SecuritySeverity::High => "â ī¸ ",
syncable_cli::analyzer::SecuritySeverity::Medium => "âĄ",
syncable_cli::analyzer::SecuritySeverity::Low => "âšī¸ ",
syncable_cli::analyzer::SecuritySeverity::Info => "đĄ",
};
println!(
"\n{}. {} [{}] {}",
i + 1,
severity_emoji,
finding.id,
finding.title
);
println!(" đ {}", finding.description);
if let Some(file) = &finding.file_path {
print!(" đ File: {}", file.display());
if let Some(line) = finding.line_number {
print!(" (line {})", line);
}
println!();
}
if let Some(evidence) = &finding.evidence {
println!(" đ Evidence: {}", evidence);
}
if !finding.remediation.is_empty() {
println!(" đ§ Remediation:");
for remediation in &finding.remediation {
println!(" âĸ {}", remediation);
}
}
if let Some(cwe) = &finding.cwe_id {
println!(" đˇī¸ CWE: {}", cwe);
}
}
}
if !security_report.recommendations.is_empty() {
println!("\nđĄ Security Recommendations:");
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââ");
for (i, recommendation) in security_report.recommendations.iter().enumerate() {
println!("{}. {}", i + 1, recommendation);
}
}
if !security_report.compliance_status.is_empty() {
println!("\nđ Compliance Status:");
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââ");
for (framework, status) in &security_report.compliance_status {
println!("đī¸ {}: {:.1}% coverage", framework, status.coverage);
if !status.missing_controls.is_empty() {
println!(
" Missing controls: {}",
status.missing_controls.join(", ")
);
}
}
}
println!("\nâ
Security analysis completed!");
if security_report
.findings_by_severity
.contains_key(&syncable_cli::analyzer::SecuritySeverity::Critical)
{
println!("â Critical security issues found. Please address immediately.");
std::process::exit(1);
} else if security_report
.findings_by_severity
.contains_key(&syncable_cli::analyzer::SecuritySeverity::High)
{
println!("â ī¸ High severity security issues found. Review recommended.");
std::process::exit(2);
}
Ok(())
}