Skip to main content

envo/
cli.rs

1//! Command-line surface (clap derive).
2
3use std::path::PathBuf;
4
5use clap::{Args, Parser, Subcommand, ValueEnum};
6
7#[derive(Parser)]
8#[command(
9    name = "envo",
10    version,
11    about = "Typed .env manager: schema, profile inheritance, leak detection, encryption",
12    propagate_version = true
13)]
14pub struct Cli {
15    /// Project directory (defaults to the current directory)
16    #[arg(short = 'C', long, global = true, value_name = "DIR")]
17    pub dir: Option<PathBuf>,
18
19    /// Disable colored output
20    #[arg(long, global = true)]
21    pub no_color: bool,
22
23    #[command(subcommand)]
24    pub command: Command,
25}
26
27#[derive(Subcommand)]
28pub enum Command {
29    /// Create a starter .envo schema (and supporting files)
30    Init(InitArgs),
31    /// Validate the resolved environment against the schema
32    Check(CheckArgs),
33    /// Print the resolved variables and where each came from
34    List(ListArgs),
35    /// Resolve + validate, then run a command with the env injected
36    Run(RunArgs),
37    /// Export the resolved environment in a chosen format
38    Export(ExportArgs),
39    /// Encrypt a plaintext secrets file
40    Encrypt(CryptoArgs),
41    /// Decrypt an encrypted secrets file
42    Decrypt(CryptoArgs),
43    /// Scan files for leaked secrets
44    Scan(ScanArgs),
45    /// Manage the git pre-commit hook
46    Hook(HookArgs),
47}
48
49#[derive(Args)]
50pub struct InitArgs {
51    /// Overwrite existing .envo / .env files
52    #[arg(long)]
53    pub force: bool,
54}
55
56#[derive(Args)]
57pub struct CheckArgs {
58    /// Profile to layer in (loads .env.<profile>)
59    #[arg(short, long, value_name = "NAME")]
60    pub profile: Option<String>,
61    /// Treat variables outside the schema as errors
62    #[arg(long)]
63    pub strict: bool,
64    /// Ignore the current process environment when resolving
65    #[arg(long)]
66    pub no_process_env: bool,
67    /// Path to the encryption key file (for encrypted secrets)
68    #[arg(long, value_name = "FILE")]
69    pub key_file: Option<PathBuf>,
70}
71
72#[derive(Args)]
73pub struct ListArgs {
74    /// Profile to layer in
75    #[arg(short, long, value_name = "NAME")]
76    pub profile: Option<String>,
77    /// Reveal secret values instead of hiding them
78    #[arg(long)]
79    pub show_secrets: bool,
80    /// Output as JSON
81    #[arg(long)]
82    pub json: bool,
83    /// Include the current process environment
84    #[arg(long)]
85    pub process_env: bool,
86    /// Path to the encryption key file
87    #[arg(long, value_name = "FILE")]
88    pub key_file: Option<PathBuf>,
89}
90
91#[derive(Args)]
92pub struct RunArgs {
93    /// Profile to layer in
94    #[arg(short, long, value_name = "NAME")]
95    pub profile: Option<String>,
96    /// Skip validation before running
97    #[arg(long)]
98    pub no_validate: bool,
99    /// Path to the encryption key file
100    #[arg(long, value_name = "FILE")]
101    pub key_file: Option<PathBuf>,
102    /// Command to run (everything after `--`)
103    #[arg(
104        trailing_var_arg = true,
105        allow_hyphen_values = true,
106        required = true,
107        value_name = "CMD"
108    )]
109    pub cmd: Vec<String>,
110}
111
112#[derive(Args)]
113pub struct ExportArgs {
114    /// Profile to layer in
115    #[arg(short, long, value_name = "NAME")]
116    pub profile: Option<String>,
117    /// Output format
118    #[arg(long, value_enum, default_value_t = ExportFormat::Dotenv)]
119    pub format: ExportFormat,
120    /// Path to the encryption key file
121    #[arg(long, value_name = "FILE")]
122    pub key_file: Option<PathBuf>,
123}
124
125#[derive(Clone, Copy, ValueEnum)]
126pub enum ExportFormat {
127    Dotenv,
128    Shell,
129    Json,
130}
131
132#[derive(Args)]
133pub struct CryptoArgs {
134    /// Input file (defaults: encrypt=.env.secrets, decrypt=.env.secrets.enc)
135    #[arg(short, long, value_name = "FILE")]
136    pub input: Option<PathBuf>,
137    /// Output file (defaults to input with/without the .enc suffix)
138    #[arg(short, long, value_name = "FILE")]
139    pub output: Option<PathBuf>,
140    /// Path to the encryption key file
141    #[arg(long, value_name = "FILE")]
142    pub key_file: Option<PathBuf>,
143}
144
145#[derive(Args)]
146pub struct ScanArgs {
147    /// Scan only files staged for commit
148    #[arg(long)]
149    pub staged: bool,
150    /// Fail on medium-severity findings too
151    #[arg(long)]
152    pub strict: bool,
153    /// Files or directories to scan (defaults to tracked files)
154    #[arg(value_name = "PATH")]
155    pub paths: Vec<PathBuf>,
156}
157
158#[derive(Args)]
159pub struct HookArgs {
160    #[command(subcommand)]
161    pub action: HookAction,
162}
163
164#[derive(Subcommand)]
165pub enum HookAction {
166    /// Install the pre-commit hook
167    Install(HookInstallArgs),
168    /// Remove the pre-commit hook
169    Uninstall,
170}
171
172#[derive(Args)]
173pub struct HookInstallArgs {
174    /// Also run `envo check` in the hook
175    #[arg(long)]
176    pub with_check: bool,
177}