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        /// Security scan mode (lightning, fast, balanced, thorough, paranoid)
177        #[arg(long, value_enum, default_value = "thorough")]
178        mode: SecurityScanMode,
179
180        /// Include low severity findings
181        #[arg(long)]
182        include_low: bool,
183
184        /// Skip secrets detection
185        #[arg(long)]
186        no_secrets: bool,
187
188        /// Skip code pattern analysis
189        #[arg(long)]
190        no_code_patterns: bool,
191
192        /// Skip infrastructure analysis (not implemented yet)
193        #[arg(long, hide = true)]
194        no_infrastructure: bool,
195
196        /// Skip compliance checks (not implemented yet)
197        #[arg(long, hide = true)]
198        no_compliance: bool,
199
200        /// Compliance frameworks to check (not implemented yet)
201        #[arg(long, value_delimiter = ',', hide = true)]
202        frameworks: Vec<String>,
203
204        /// Output format
205        #[arg(long, value_enum, default_value = "table")]
206        format: OutputFormat,
207
208        /// Export report to file
209        #[arg(long)]
210        output: Option<PathBuf>,
211
212        /// Exit with error code on security findings
213        #[arg(long)]
214        fail_on_findings: bool,
215    },
216
217    /// Manage vulnerability scanning tools
218    Tools {
219        #[command(subcommand)]
220        command: ToolsCommand,
221    },
222}
223
224#[derive(Subcommand)]
225pub enum ToolsCommand {
226    /// Check which vulnerability scanning tools are installed
227    Status {
228        /// Output format
229        #[arg(long, value_enum, default_value = "table")]
230        format: OutputFormat,
231
232        /// Check tools for specific languages only
233        #[arg(long, value_delimiter = ',')]
234        languages: Option<Vec<String>>,
235    },
236
237    /// Install missing vulnerability scanning tools
238    Install {
239        /// Install tools for specific languages only
240        #[arg(long, value_delimiter = ',')]
241        languages: Option<Vec<String>>,
242
243        /// Also install OWASP Dependency Check (large download)
244        #[arg(long)]
245        include_owasp: bool,
246
247        /// Perform a dry run to show what would be installed
248        #[arg(long)]
249        dry_run: bool,
250
251        /// Skip confirmation prompts
252        #[arg(short, long)]
253        yes: bool,
254    },
255
256    /// Verify that installed tools are working correctly
257    Verify {
258        /// Test tools for specific languages only
259        #[arg(long, value_delimiter = ',')]
260        languages: Option<Vec<String>>,
261
262        /// Show detailed verification output
263        #[arg(short, long)]
264        verbose: bool,
265    },
266
267    /// Show tool installation guides for manual setup
268    Guide {
269        /// Show guide for specific languages only
270        #[arg(long, value_delimiter = ',')]
271        languages: Option<Vec<String>>,
272
273        /// Show platform-specific instructions
274        #[arg(long)]
275        platform: Option<String>,
276    },
277}
278
279#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
280pub enum OutputFormat {
281    Table,
282    Json,
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
286pub enum DisplayFormat {
287    /// Compact matrix/dashboard view (modern, easy to scan)
288    Matrix,
289    /// Detailed vertical view (legacy format with all details)
290    Detailed,  
291    /// Brief summary only
292    Summary,
293}
294
295#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
296pub enum SeverityThreshold {
297    Low,
298    Medium,
299    High,
300    Critical,
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
304pub enum SecurityScanMode {
305    /// Lightning fast scan - critical files only (.env, configs)
306    Lightning,
307    /// Fast scan - smart sampling with priority patterns
308    Fast,
309    /// Balanced scan - good coverage with performance optimizations (recommended)
310    Balanced,
311    /// Thorough scan - comprehensive analysis of all files
312    Thorough,
313    /// Paranoid scan - most comprehensive including low-severity findings
314    Paranoid,
315}
316
317impl Cli {
318    /// Initialize logging based on verbosity level
319    pub fn init_logging(&self) {
320        if self.quiet {
321            return;
322        }
323
324        let level = match self.verbose {
325            0 => log::LevelFilter::Warn,
326            1 => log::LevelFilter::Info,
327            2 => log::LevelFilter::Debug,
328            _ => log::LevelFilter::Trace,
329        };
330
331        env_logger::Builder::from_default_env()
332            .filter_level(level)
333            .init();
334    }
335}