Initial commit: env-guard CLI tool with CI/CD
Some checks failed
CI / test (push) Failing after 9s
CI / binary (push) Has been skipped
CI / release (push) Has been skipped

This commit is contained in:
CI Bot
2026-02-06 10:01:25 +00:00
commit fc90e05ebb
18 changed files with 2670 additions and 0 deletions

165
src/main.rs Normal file
View File

@@ -0,0 +1,165 @@
use clap::{Command, Arg};
use anyhow::Result;
mod config;
mod env_parser;
mod validation;
mod secrets;
mod framework;
mod commands;
use commands::{scan, validate, generate, secrets_cmd, init, check};
fn main() -> Result<()> {
let matches = Command::new("env-guard")
.version("0.1.0")
.about("Automatically detect, validate, and secure environment variables")
.subcommand_required(false)
.arg_required_else_help(true)
.subcommand(
Command::new("scan")
.about("Scan .env files and compare against expected variables")
.arg(
Arg::new("path")
.short('p')
.long("path")
.value_name("PATH")
.help("Path to scan for .env files")
.default_value(".")
)
.arg(
Arg::new("schema")
.short('s')
.long("schema")
.value_name("FILE")
.help("Path to schema file (.env.schema.json)")
)
)
.subcommand(
Command::new("validate")
.about("Validate format of environment variable values")
.arg(
Arg::new("path")
.short('p')
.long("path")
.value_name("FILE")
.help("Path to .env file")
.default_value(".env")
)
.arg(
Arg::new("strict")
.short('S')
.long("strict")
.help("Enable strict validation")
.action(clap::ArgAction::SetTrue)
)
)
.subcommand(
Command::new("generate")
.about("Generate .env.example file from .env")
.arg(
Arg::new("path")
.short('p')
.long("path")
.value_name("FILE")
.help("Path to .env file")
.default_value(".env")
)
.arg(
Arg::new("output")
.short('o')
.long("output")
.value_name("FILE")
.help("Output file path")
.default_value(".env.example")
)
)
.subcommand(
Command::new("secrets")
.about("Scan source code for accidentally committed secrets")
.arg(
Arg::new("path")
.short('p')
.long("path")
.value_name("PATH")
.help("Path to scan for secrets")
.default_value(".")
)
.arg(
Arg::new("strict")
.short('S')
.long("strict")
.help("Enable strict secret detection")
.action(clap::ArgAction::SetTrue)
)
)
.subcommand(
Command::new("init")
.about("Initialize env-guard with framework detection")
.arg(
Arg::new("framework")
.short('f')
.long("framework")
.value_name("FRAMEWORK")
.help("Framework to use (nextjs, rails, django, node)")
)
.arg(
Arg::new("path")
.short('p')
.long("path")
.value_name("PATH")
.help("Path to project directory")
.default_value(".")
)
)
.subcommand(
Command::new("check")
.about("Check .env file for common issues")
.arg(
Arg::new("path")
.short('p')
.long("path")
.value_name("FILE")
.help("Path to .env file")
.default_value(".env")
)
)
.get_matches();
match matches.subcommand() {
Some(("scan", sub_matches)) => {
let path = sub_matches.get_one::<String>("path").map(|s| s.as_str()).unwrap_or(".");
let schema = sub_matches.get_one::<String>("schema").map(|s| s.as_str());
scan(path, schema)?;
}
Some(("validate", sub_matches)) => {
let path = sub_matches.get_one::<String>("path").map(|s| s.as_str()).unwrap_or(".env");
let strict = sub_matches.get_flag("strict");
validate(path, strict)?;
}
Some(("generate", sub_matches)) => {
let path = sub_matches.get_one::<String>("path").map(|s| s.as_str()).unwrap_or(".env");
let output = sub_matches.get_one::<String>("output").map(|s| s.as_str());
generate(path, output)?;
}
Some(("secrets", sub_matches)) => {
let path = sub_matches.get_one::<String>("path").map(|s| s.as_str()).unwrap_or(".");
let strict = sub_matches.get_flag("strict");
secrets_cmd(path, strict)?;
}
Some(("init", sub_matches)) => {
let framework = sub_matches.get_one::<String>("framework").map(|s| s.as_str());
let path = sub_matches.get_one::<String>("path").map(|s| s.as_str());
init(framework, path)?;
}
Some(("check", sub_matches)) => {
let path = sub_matches.get_one::<String>("path").map(|s| s.as_str()).unwrap_or(".env");
check(path)?;
}
_ => {
let _ = Command::new("env-guard").print_help();
}
}
Ok(())
}