syncable_cli/
cli.rs

1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "sync-ctl")]
6#[command(version = env!("CARGO_PKG_VERSION"))]
7#[command(about = "Generate Infrastructure as Code from your codebase")]
8#[command(long_about = "A powerful CLI tool that analyzes your codebase and automatically generates optimized Infrastructure as Code configurations including Dockerfiles, Docker Compose files, and Terraform configurations.")]
9pub struct Cli {
10    #[command(subcommand)]
11    pub command: Commands,
12
13    /// Path to configuration file
14    #[arg(short, long, global = true, value_name = "FILE")]
15    pub config: Option<PathBuf>,
16
17    /// Enable verbose logging (-v for info, -vv for debug, -vvv for trace)
18    #[arg(short, long, global = true, action = clap::ArgAction::Count)]
19    pub verbose: u8,
20
21    /// Suppress all output except errors
22    #[arg(short, long, global = true)]
23    pub quiet: bool,
24
25    /// Output in JSON format where applicable
26    #[arg(long, global = true)]
27    pub json: bool,
28
29    /// Clear the update check cache and force a new check
30    #[arg(long, global = true)]
31    pub clear_update_cache: bool,
32}
33
34#[derive(Subcommand)]
35pub enum Commands {
36    /// Analyze a project and display detected components
37    Analyze {
38        /// Path to the project directory to analyze
39        #[arg(value_name = "PROJECT_PATH")]
40        path: PathBuf,
41
42        /// Output analysis results in JSON format
43        #[arg(short, long)]
44        json: bool,
45
46        /// Show detailed analysis information (legacy format)
47        #[arg(short, long, conflicts_with = "display")]
48        detailed: bool,
49
50        /// Display format for analysis results
51        #[arg(long, value_enum, default_value = "matrix")]
52        display: Option<DisplayFormat>,
53
54        /// Only analyze specific aspects (languages, frameworks, dependencies)
55        #[arg(long, value_delimiter = ',')]
56        only: Option<Vec<String>>,
57    },
58
59    /// Generate IaC files for a project
60    Generate {
61        /// Path to the project directory to analyze
62        #[arg(value_name = "PROJECT_PATH")]
63        path: PathBuf,
64
65        /// Output directory for generated files
66        #[arg(short, long, value_name = "OUTPUT_DIR")]
67        output: Option<PathBuf>,
68
69        /// Generate Dockerfile
70        #[arg(long)]
71        dockerfile: bool,
72
73        /// Generate Docker Compose file
74        #[arg(long)]
75        compose: bool,
76
77        /// Generate Terraform configuration
78        #[arg(long)]
79        terraform: bool,
80
81        /// Generate all supported IaC files
82        #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
83        all: bool,
84
85        /// Perform a dry run without creating files
86        #[arg(long)]
87        dry_run: bool,
88
89        /// Overwrite existing files
90        #[arg(long)]
91        force: bool,
92    },
93
94    /// Validate existing IaC files against best practices
95    Validate {
96        /// Path to the directory containing IaC files
97        #[arg(value_name = "PATH")]
98        path: PathBuf,
99
100        /// Types of files to validate
101        #[arg(long, value_delimiter = ',')]
102        types: Option<Vec<String>>,
103
104        /// Fix issues automatically where possible
105        #[arg(long)]
106        fix: bool,
107    },
108
109    /// Show supported languages and frameworks
110    Support {
111        /// Show only languages
112        #[arg(long)]
113        languages: bool,
114
115        /// Show only frameworks
116        #[arg(long)]
117        frameworks: bool,
118
119        /// Show detailed information
120        #[arg(short, long)]
121        detailed: bool,
122    },
123
124    /// Analyze project dependencies in detail
125    Dependencies {
126        /// Path to the project directory to analyze
127        #[arg(value_name = "PROJECT_PATH")]
128        path: PathBuf,
129
130        /// Show license information for dependencies
131        #[arg(long)]
132        licenses: bool,
133
134        /// Check for known vulnerabilities
135        #[arg(long)]
136        vulnerabilities: bool,
137
138        /// Show only production dependencies
139        #[arg(long, conflicts_with = "dev_only")]
140        prod_only: bool,
141
142        /// Show only development dependencies
143        #[arg(long, conflicts_with = "prod_only")]
144        dev_only: bool,
145
146        /// Output format
147        #[arg(long, value_enum, default_value = "table")]
148        format: OutputFormat,
149    },
150
151    /// Check dependencies for known vulnerabilities
152    Vulnerabilities {
153        /// Check vulnerabilities in a specific path
154        #[arg(default_value = ".")]
155        path: PathBuf,
156
157        /// Show only vulnerabilities with severity >= threshold
158        #[arg(long, value_enum)]
159        severity: Option<SeverityThreshold>,
160
161        /// Output format
162        #[arg(long, value_enum, default_value = "table")]
163        format: OutputFormat,
164
165        /// Export report to file
166        #[arg(long)]
167        output: Option<PathBuf>,
168    },
169
170    /// Perform comprehensive security analysis
171    Security {
172        /// Path to the project directory to analyze
173        #[arg(value_name = "PROJECT_PATH", default_value = ".")]
174        path: PathBuf,
175
176        /// Include low severity findings
177        #[arg(long)]
178        include_low: bool,
179
180        /// Skip secrets detection
181        #[arg(long)]
182        no_secrets: bool,
183
184        /// Skip code pattern analysis
185        #[arg(long)]
186        no_code_patterns: bool,
187
188        /// Skip infrastructure analysis (not implemented yet)
189        #[arg(long, hide = true)]
190        no_infrastructure: bool,
191
192        /// Skip compliance checks (not implemented yet)
193        #[arg(long, hide = true)]
194        no_compliance: bool,
195
196        /// Compliance frameworks to check (not implemented yet)
197        #[arg(long, value_delimiter = ',', hide = true)]
198        frameworks: Vec<String>,
199
200        /// Output format
201        #[arg(long, value_enum, default_value = "table")]
202        format: OutputFormat,
203
204        /// Export report to file
205        #[arg(long)]
206        output: Option<PathBuf>,
207
208        /// Exit with error code on security findings
209        #[arg(long)]
210        fail_on_findings: bool,
211    },
212
213    /// Manage vulnerability scanning tools
214    Tools {
215        #[command(subcommand)]
216        command: ToolsCommand,
217    },
218}
219
220#[derive(Subcommand)]
221pub enum ToolsCommand {
222    /// Check which vulnerability scanning tools are installed
223    Status {
224        /// Output format
225        #[arg(long, value_enum, default_value = "table")]
226        format: OutputFormat,
227
228        /// Check tools for specific languages only
229        #[arg(long, value_delimiter = ',')]
230        languages: Option<Vec<String>>,
231    },
232
233    /// Install missing vulnerability scanning tools
234    Install {
235        /// Install tools for specific languages only
236        #[arg(long, value_delimiter = ',')]
237        languages: Option<Vec<String>>,
238
239        /// Also install OWASP Dependency Check (large download)
240        #[arg(long)]
241        include_owasp: bool,
242
243        /// Perform a dry run to show what would be installed
244        #[arg(long)]
245        dry_run: bool,
246
247        /// Skip confirmation prompts
248        #[arg(short, long)]
249        yes: bool,
250    },
251
252    /// Verify that installed tools are working correctly
253    Verify {
254        /// Test tools for specific languages only
255        #[arg(long, value_delimiter = ',')]
256        languages: Option<Vec<String>>,
257
258        /// Show detailed verification output
259        #[arg(short, long)]
260        verbose: bool,
261    },
262
263    /// Show tool installation guides for manual setup
264    Guide {
265        /// Show guide for specific languages only
266        #[arg(long, value_delimiter = ',')]
267        languages: Option<Vec<String>>,
268
269        /// Show platform-specific instructions
270        #[arg(long)]
271        platform: Option<String>,
272    },
273}
274
275#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
276pub enum OutputFormat {
277    Table,
278    Json,
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
282pub enum DisplayFormat {
283    /// Compact matrix/dashboard view (modern, easy to scan)
284    Matrix,
285    /// Detailed vertical view (legacy format with all details)
286    Detailed,  
287    /// Brief summary only
288    Summary,
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
292pub enum SeverityThreshold {
293    Low,
294    Medium,
295    High,
296    Critical,
297}
298
299impl Cli {
300    /// Initialize logging based on verbosity level
301    pub fn init_logging(&self) {
302        if self.quiet {
303            return;
304        }
305
306        let level = match self.verbose {
307            0 => log::LevelFilter::Warn,
308            1 => log::LevelFilter::Info,
309            2 => log::LevelFilter::Debug,
310            _ => log::LevelFilter::Trace,
311        };
312
313        env_logger::Builder::from_default_env()
314            .filter_level(level)
315            .init();
316    }
317}