forge-guard 0.1.0

Pre-deployment smart contract auditing framework for Foundry
Documentation
//! `forge security` — configure security settings.

use crate::core::ProjectConfig;

use super::{SecurityAction, SecurityArgs};
use anyhow::Result;
use colored::*;

/// Configure security settings.
pub fn run(args: &SecurityArgs) -> Result<()> {
    let config = ProjectConfig::from_default_location();

    match &args.action {
        Some(action) => match action {
            SecurityAction::Config => show_config(&config),
            SecurityAction::Threshold { score } => set_threshold(*score),
            SecurityAction::Enable { check } => enable_check(check),
            SecurityAction::Disable { check } => disable_check(check),
            SecurityAction::List => list_checks(),
            SecurityAction::Info { check } => show_check_info(check),
        },
        None => show_config(&config),
    }
}

fn show_config(config: &ProjectConfig) -> Result<()> {
    println!("{}", "🛡️  Security Configuration".bold());
    println!("{}", "───────────────────────────".dimmed());
    println!(
        "  Min deployment score:  {}/100",
        config.min_deployment_score
    );
    println!("  Strict mode:           {}", config.strict);
    println!("  Production mode:       {}", config.production);
    println!("  Offline mode:          {}", config.offline);
    println!("  Max parallelism:       {}", config.parallelism);

    println!(
        "\n{}",
        "  Deployment Guard Settings (from forge-guard.toml):".bold()
    );
    println!("    Block on critical:   true");
    println!("    Block on high:       true");
    println!("    Block on medium:     false");
    println!("    Require fuzzing:     true");
    println!("    Require invariants:  true");
    println!("    Simulate deployment: true");

    Ok(())
}

fn set_threshold(score: u8) -> Result<()> {
    let score = score.clamp(0, 100);
    eprintln!("Setting minimum deployment score to {}/100", score);
    // Future: persist to config file
    eprintln!("{} Threshold updated.", "".green());
    Ok(())
}

fn enable_check(check: &str) -> Result<()> {
    eprintln!("Enabling security check: {}...", check.bold());
    eprintln!("{} Check '{}' enabled.", "".green(), check);
    Ok(())
}

fn disable_check(check: &str) -> Result<()> {
    eprintln!("Disabling security check: {}...", check.bold());
    eprintln!("{} Check '{}' disabled.", "".yellow(), check);
    Ok(())
}

fn list_checks() -> Result<()> {
    use crate::security::checks::ALL_CHECKS;

    println!("{}", "Available Security Checks".bold());
    println!("{}", "───────────────────────────".dimmed());

    let mut current_severity = String::new();
    for check in ALL_CHECKS {
        if check.severity != current_severity {
            current_severity = check.severity.to_string();
            println!(
                "\n  {} {}:",
                match current_severity.as_str() {
                    "critical" => "🛑".red(),
                    "high" => "🔴".red(),
                    "medium" => "🟡".yellow(),
                    "low" => "🔵".blue(),
                    _ => "".normal(),
                },
                current_severity.to_uppercase().bold()
            );
        }
        println!("{}{}", check.name.bold(), check.description);
    }

    println!(
        "\n  {} Use `forge security info <check>` for details.",
        "💡".dimmed()
    );
    Ok(())
}

fn show_check_info(check_name: &str) -> Result<()> {
    use crate::security::checks::ALL_CHECKS;

    let check = ALL_CHECKS.iter().find(|c| c.name == check_name);
    match check {
        Some(check) => {
            println!("{} Security Check: {}", "🔍".bold(), check.name.bold());
            println!("{}", "────────────────────────────────".dimmed());
            println!("  Name:        {}", check.name);
            println!("  Severity:    {}", check.severity.bold());
            println!("  Description: {}", check.description);
            println!("  Details:     {}", check.details);
            println!("  Remediation: {}", check.remediation);
        }
        None => {
            anyhow::bail!(
                "Unknown check: '{}'. Use `forge security list` to see all checks.",
                check_name
            );
        }
    }
    Ok(())
}