forge-guard 0.1.3

Pre-deployment smart contract auditing framework for Foundry
Documentation
//! `forge-guard report` — generate audit reports.

use crate::core::{AuditResult, ProjectConfig};
use crate::reports;

use super::ReportArgs;
use anyhow::{Context, Result};
use colored::*;

/// Generate audit reports from existing results or re-run.
pub fn run(args: &ReportArgs) -> Result<()> {
    let config = ProjectConfig::from_default_location();

    // Try to load existing audit result
    let result = if let Some(input_path) = &args.input {
        let content = std::fs::read_to_string(input_path).context("Failed to read input file")?;
        serde_json::from_str::<AuditResult>(&content)
            .context("Failed to parse audit result JSON")?
    } else {
        // Try loading from cache
        let cache_dir = config.project_root.join(".forge-guard-cache");
        let cache_file = cache_dir.join("last_audit.json");
        if cache_file.exists() {
            let content =
                std::fs::read_to_string(&cache_file).context("Failed to read cached audit")?;
            serde_json::from_str::<AuditResult>(&content)
                .context("Failed to parse cached audit result")?
        } else {
            anyhow::bail!(
                "No audit result found. Run `forge-guard audit` first or specify --input"
            );
        }
    };

    let output_dir = std::path::PathBuf::from(&config.report.output_dir);
    std::fs::create_dir_all(&output_dir)?;

    match args.format.to_lowercase().as_str() {
        "json" => {
            let output_path = args
                .output
                .clone()
                .unwrap_or_else(|| output_dir.join("audit.json"));
            reports::json::write_report(&result, &output_path)?;
            println!(
                "{} JSON report written to {}",
                "".green(),
                output_path.display()
            );
        }
        "markdown" | "md" => {
            let output_path = args
                .output
                .clone()
                .unwrap_or_else(|| output_dir.join("audit.md"));
            let md = reports::markdown::generate_report(&result)?;
            std::fs::write(&output_path, md)?;
            println!(
                "{} Markdown report written to {}",
                "".green(),
                output_path.display()
            );
        }
        other => {
            anyhow::bail!("Unsupported format: {}. Use 'json' or 'markdown'.", other);
        }
    }

    if args.shared.json {
        println!("{}", serde_json::to_string_pretty(&result)?);
    }

    Ok(())
}