1use anyhow::Error;
2use clap::Parser;
3use clap::Subcommand;
4
5use fehler::throws;
6
7mod command;
8
9use crate::command::FuzzCommand;
10
11#[derive(Parser)]
12#[command(
13 name = "Trident",
14 about = "Trident is Rust based fuzzer for Solana programs written using Anchor framework."
15)]
16struct Cli {
17 #[clap(subcommand)]
18 command: Command,
19}
20
21#[derive(Subcommand)]
22enum Command {
23 #[command(about = "Show the HowTo message.")]
24 How,
25 #[command(
26 about = "Initialize Trident in the current Anchor workspace.",
27 override_usage = "\nTrident will skip initialization if Trident.toml already exists."
28 )]
29 Init {
30 #[arg(
31 short,
32 long,
33 required = false,
34 help = "Force Trident initialization. Trident dependencies will be updated based on the version of Trident CLI."
35 )]
36 force: bool,
37 #[arg(
38 short,
39 long,
40 required = false,
41 help = "Skip building the program before initializing Trident."
42 )]
43 skip_build: bool,
44 #[arg(
45 short,
46 long,
47 required = false,
48 help = "Specify the name of the program for which fuzz test will be generated.",
49 value_name = "FILE"
50 )]
51 program_name: Option<String>,
52 #[arg(
53 short,
54 long,
55 required = false,
56 help = "Name of the fuzz test to initialize.",
57 value_name = "NAME"
58 )]
59 test_name: Option<String>,
60 },
61 #[command(
62 about = "Run fuzz subcommands.",
63 override_usage = "With fuzz subcommands you can add new fuzz test \
64 template or you can run fuzz test on already initialzied one.\
65 \n\n\x1b[1m\x1b[4mEXAMPLE:\x1b[0m\
66 \n trident add\
67 \n trident fuzz run fuzz_0\
68 \n trident fuzz debug \x1b[92m<FUZZ_TARGET>\x1b[0m \x1b[92m<SEED>\x1b[0m"
69 )]
70 Fuzz {
71 #[clap(subcommand)]
72 subcmd: FuzzCommand,
73 },
74 #[command(about = "Clean build target, additionally perform `anchor clean`")]
75 Clean,
76}
77
78#[throws]
79pub async fn start() {
80 let cli = Cli::parse();
81
82 match cli.command {
83 Command::How => command::howto()?,
84 Command::Fuzz { subcmd } => command::fuzz(subcmd).await?,
85 Command::Init {
86 force,
87 skip_build,
88 program_name,
89 test_name,
90 } => command::init(force, skip_build, program_name, test_name).await?,
91 Command::Clean => command::clean().await?,
92 }
93}