mod audit;
mod benchmark;
mod chain;
mod ci;
mod deploy;
mod deploy_safe;
mod doctor;
mod fuzz;
mod gas;
mod invariant;
mod plugins;
mod report;
mod scan;
mod security;
mod simulate;
mod upgrade_check;
mod verify;
mod watch;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(
name = "forge-guard",
version,
about = "Pre-deployment smart contract auditing framework for Foundry",
long_about = "The most comprehensive pre-deployment smart contract auditing framework for Foundry.\n\nTransforms security auditing from an optional step into a mandatory pre-deployment process.\nBlocks unsafe deployments by default while providing detailed vulnerability reports.",
author
)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
impl Cli {
pub fn from_env() -> Self {
Self::parse()
}
pub fn run(&self) -> anyhow::Result<()> {
use anyhow::Context;
match &self.command {
Commands::Audit(args) => audit::run(args).context("Audit failed"),
Commands::Deploy(args) => deploy::run(args).context("Deploy failed"),
Commands::DeploySafe(args) => deploy_safe::run(args).context("Safe deploy failed"),
Commands::Fuzz(args) => fuzz::run(args).context("Fuzzing failed"),
Commands::Invariant(args) => invariant::run(args).context("Invariant test failed"),
Commands::Simulate(args) => simulate::run(args).context("Simulation failed"),
Commands::Gas(args) => gas::run(args).context("Gas analysis failed"),
Commands::Report(args) => report::run(args).context("Report generation failed"),
Commands::Verify(args) => verify::run(args).context("Verification failed"),
Commands::Doctor(args) => doctor::run(args).context("Doctor analysis failed"),
Commands::Watch(args) => watch::run(args).context("Watch failed"),
Commands::Ci(args) => ci::run(args).context("CI generation failed"),
Commands::Benchmark(args) => benchmark::run(args).context("Benchmark failed"),
Commands::Scan(args) => scan::run(args).context("Scan failed"),
Commands::UpgradeCheck(args) => {
upgrade_check::run(args).context("Upgrade check failed")
}
Commands::Plugins(args) => plugins::run(args).context("Plugin operation failed"),
Commands::Chain(args) => chain::run(args).context("Chain operation failed"),
Commands::Security(args) => security::run(args).context("Security operation failed"),
}
}
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Audit(AuditArgs),
Deploy(DeployArgs),
#[command(name = "deploy-safe")]
DeploySafe(DeploySafeArgs),
Fuzz(FuzzArgs),
Invariant(InvariantArgs),
Simulate(SimulateArgs),
Gas(GasArgs),
Report(ReportArgs),
Verify(VerifyArgs),
Doctor(DoctorArgs),
Watch(WatchArgs),
Ci(CiArgs),
Benchmark(BenchmarkArgs),
Scan(ScanArgs),
#[command(name = "upgrade-check")]
UpgradeCheck(UpgradeCheckArgs),
Plugins(PluginArgs),
Chain(ChainArgs),
Security(SecurityArgs),
}
#[derive(Debug, clap::Args)]
pub struct SharedFlags {
#[arg(long, global = true, default_value = "ethereum")]
pub chain: String,
#[arg(long, global = true, default_value = ".")]
pub project: PathBuf,
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub markdown: bool,
#[arg(long, global = true)]
pub strict: bool,
#[arg(long, global = true)]
pub offline: bool,
#[arg(long, global = true)]
pub production: bool,
#[arg(long, global = true)]
pub report: bool,
#[arg(long, global = true, default_value = "4")]
pub parallelism: usize,
}
#[derive(Debug, clap::Args)]
pub struct AuditArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, short)]
pub full: bool,
#[arg(long)]
pub quick: bool,
#[arg(long)]
pub summary: bool,
#[arg(long)]
pub ai: bool,
#[arg(long, default_value = "openai")]
pub ai_provider: String,
#[arg(long, default_value = "gpt-4")]
pub ai_model: String,
#[arg(long)]
pub ai_api_key: Option<String>,
#[arg(long)]
pub ollama_endpoint: Option<String>,
#[arg(long)]
pub ai_full: bool,
#[arg(long)]
pub exploit: bool,
#[arg(long)]
pub gas: bool,
#[arg(long)]
pub all_chains: bool,
#[arg(long, default_value = "src")]
pub sources: String,
#[arg(long)]
pub exclude: Option<String>,
}
#[derive(Debug, clap::Args)]
pub struct DeployArgs {
#[command(flatten)]
pub shared: SharedFlags,
pub contract: Option<String>,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub args: Option<String>,
#[arg(long)]
pub salt: Option<String>,
#[arg(long)]
pub verify: bool,
}
#[derive(Debug, clap::Args)]
pub struct DeploySafeArgs {
#[command(flatten)]
pub shared: SharedFlags,
pub contract: Option<String>,
#[arg(long)]
pub args: Option<String>,
#[arg(long)]
pub verify: bool,
}
#[derive(Debug, clap::Args)]
pub struct FuzzArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "10000")]
pub runs: u32,
#[arg(long)]
pub seed: Option<u64>,
#[arg(long)]
pub test: Option<String>,
pub contract: Option<String>,
}
#[derive(Debug, clap::Args)]
pub struct InvariantArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "1000")]
pub runs: u32,
#[arg(long, default_value = "100")]
pub depth: u32,
pub contract: Option<String>,
#[arg(long)]
pub fail_on_revert: bool,
}
#[derive(Debug, clap::Args)]
pub struct SimulateArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "100")]
pub blocks: u32,
#[arg(long)]
pub deployer: Option<String>,
#[arg(long)]
pub mev: bool,
pub contract: Option<String>,
}
#[derive(Debug, clap::Args)]
pub struct GasArgs {
#[command(flatten)]
pub shared: SharedFlags,
pub contract: Option<String>,
#[arg(long)]
pub diff: Option<String>,
#[arg(long)]
pub all: bool,
#[arg(long, default_value = "50000")]
pub warn_threshold: u64,
}
#[derive(Debug, clap::Args)]
pub struct ReportArgs {
#[command(flatten)]
pub shared: SharedFlags,
pub input: Option<PathBuf>,
#[arg(long, default_value = "markdown")]
pub format: String,
#[arg(long)]
pub output: Option<PathBuf>,
#[arg(long)]
pub exploit_paths: bool,
#[arg(long)]
pub summary: bool,
}
#[derive(Debug, clap::Args)]
pub struct VerifyArgs {
#[command(flatten)]
pub shared: SharedFlags,
pub address: Option<String>,
pub name: Option<String>,
#[arg(long)]
pub api_key: Option<String>,
#[arg(long)]
pub constructor_args: Option<String>,
#[arg(long)]
pub all: bool,
}
#[derive(Debug, clap::Args)]
pub struct DoctorArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long)]
pub fix: bool,
#[arg(long, short)]
pub verbose: bool,
#[arg(long)]
pub check: Option<String>,
}
#[derive(Debug, clap::Args)]
pub struct WatchArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "src")]
pub dirs: String,
#[arg(long, default_value = "500")]
pub debounce_ms: u64,
#[arg(long)]
pub exclude: Option<String>,
#[arg(long)]
pub full: bool,
}
#[derive(Debug, clap::Args)]
pub struct CiArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "github")]
pub platform: String,
#[arg(long, default_value = ".github/workflows")]
pub output: PathBuf,
#[arg(long)]
pub include_deploy: bool,
#[arg(long)]
pub overwrite: bool,
}
#[derive(Debug, clap::Args)]
pub struct BenchmarkArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "10")]
pub iterations: u32,
#[arg(long)]
pub compare: Option<PathBuf>,
#[arg(long)]
pub save: Option<PathBuf>,
#[arg(long)]
pub module: Option<String>,
#[arg(long, default_value = "3")]
pub warmup: u32,
}
#[derive(Debug, clap::Args)]
pub struct ScanArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[arg(long, default_value = "1")]
pub depth: u32,
#[arg(long)]
pub update: bool,
#[arg(long)]
pub vulnerable_only: bool,
#[arg(long)]
pub fail_fast: bool,
}
#[derive(Debug, clap::Args)]
pub struct UpgradeCheckArgs {
#[command(flatten)]
pub shared: SharedFlags,
pub proxy: Option<String>,
pub implementation: Option<String>,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub storage_collision: bool,
#[arg(long)]
pub uups: bool,
}
#[derive(Debug, clap::Args)]
pub struct PluginArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[command(subcommand)]
pub action: Option<PluginAction>,
}
#[derive(Debug, Subcommand)]
pub enum PluginAction {
List,
Install {
name: String,
source: Option<String>,
},
Remove { name: String },
Enable { name: String },
Disable { name: String },
New { name: String },
}
#[derive(Debug, clap::Args)]
pub struct ChainArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[command(subcommand)]
pub action: Option<ChainAction>,
}
#[derive(Debug, Subcommand)]
pub enum ChainAction {
List,
Info { chain: String },
Add {
name: String,
rpc_url: Option<String>,
chain_id: Option<u64>,
},
Remove { name: String },
Test {
chain: String,
rpc_url: Option<String>,
},
}
#[derive(Debug, clap::Args)]
pub struct SecurityArgs {
#[command(flatten)]
pub shared: SharedFlags,
#[command(subcommand)]
pub action: Option<SecurityAction>,
}
#[derive(Debug, Subcommand)]
pub enum SecurityAction {
Config,
Threshold { score: u8 },
Enable { check: String },
Disable { check: String },
List,
Info { check: String },
}