evnx CLI
A comprehensive CLI tool for managing .env files — validation, secret scanning, format conversion, and migration to cloud secret managers.
📚 Documentation | 🌐 Website
Why evnx?
I built this after accidentally pushing AWS credentials to GitHub in a test file during an Airflow refactor (20 DAGs, 300+ Scrapy spiders). The key was revoked immediately, other services went down, and I had to explain the incident to my development head. That conversation was more painful than any billing alert.
Three years later, I'm still paranoid about secrets management. This tool is the safety net I wish I'd had.
✨ Features
All features are production-ready and working in v0.1.0!
Core Commands (Always Available)
- ✅
init- Interactive project setup with templates for Python, Node.js, Rust, Go, PHP - ✅
add- Option to add variables to your .env file , custom, blueprint, services - ✅
validate- Comprehensive validation (checks for placeholders, weak secrets, misconfigurations) - ✅
scan- Secret detection using pattern matching and entropy analysis - ✅
diff- Compare.envand.env.example, show missing/extra variables - ✅
convert- Transform to 14+ formats (JSON, YAML, Docker, Kubernetes, AWS, GCP, Azure, GitHub Actions, and more) - ✅
sync- Keep.envand.env.examplein sync (bidirectional)
Extended Commands (With Features)
- ✅
migrate- Direct migration to secret managers (GitHub Actions, AWS Secrets Manager, Doppler, Infisical) - ✅
doctor- Diagnose common setup issues - ✅
template- Generate config files from templates with variable substitution - ✅
backup- Create AES-256-GCM encrypted backups - ✅
restore- Restore from encrypted backups
Build with all features:
# or
🚀 Quick Start
Installation
macOS / Linux
|
Windows
Prerequisites: Install Rust first.
# Clone the repository
git clone https://github.com/urwithajit9/evnx.git
cd evnx
# Build and install with core features
cargo install --path .
# Or build with all features
cargo install --path . --features full
# Verify installation
evnx --version
Note: Add %USERPROFILE%\.cargo\bin to your PATH if not already done during Rust installation.
Tested on: Windows 10/11 with PowerShell 5.1+
From crates.io
# Install with core features only
# Install with all features
Verify Installation
Basic Usage
# 1. Initialize a new project
# 2. Validate your configuration
# 3. Scan for accidentally committed secrets
# 4. Compare files
# 5. Convert to different formats
# 6. Keep files in sync
📖 Documentation
- Getting Started Guide - Complete walkthrough with examples
- Use Cases - Real-world scenarios
- CI/CD Integration - GitLab, GitHub Actions, Jenkins
- Architecture - System design and internals
- Contributing - How to contribute
🎯 Command Overview
evnx init
Interactive project setup - Generates .env.example with sensible defaults.
Supported stacks: Python, Node.js, Rust, Go, PHP Supported services: PostgreSQL, Redis, MongoDB, MySQL, RabbitMQ, Elasticsearch, AWS S3, Stripe, SendGrid, OpenAI, and more
evnx validate
Comprehensive validation - Catches misconfigurations before deployment.
Detects:
- ❌ Missing required variables
- ❌ Placeholder values (
YOUR_KEY_HERE,CHANGE_ME) - ❌ Boolean string trap (
DEBUG="False"is truthy!) - ❌ Weak
SECRET_KEY(too short, common patterns) - ❌
localhostin production - ❌ Suspicious port numbers
evnx scan
Secret detection - Find accidentally committed credentials.
Detects 8+ secret types:
- AWS Access Keys (
AKIA...) - Stripe API Keys (live & test)
- GitHub Personal Access Tokens
- OpenAI API Keys
- Anthropic API Keys
- Private Keys (RSA, EC, OpenSSH)
- High-entropy strings (potential secrets)
- Generic API keys
SARIF output integrates with GitHub Security tab!
evnx diff
File comparison - See what's different between environments.
evnx convert
Format conversion - Transform to 14+ output formats.
Advanced options:
Real-world example - Deploy to AWS:
| \
evnx sync
Bidirectional sync - Keep .env and .env.example aligned.
# Forward: .env → .env.example (document what you have)
# Reverse: .env.example → .env (generate from template)
Use cases:
- Generate
.envfrom.env.examplein CI/CD - Update
.env.examplewhen adding new variables - Maintain documentation
evnx migrate (Requires --features migrate)
Cloud migration - Move secrets directly to secret managers.
# GitHub Actions Secrets
# AWS Secrets Manager
# Doppler
Features:
- ✅ Conflict detection (skip or overwrite)
- ✅ Dry-run mode
- ✅ Progress tracking
- ✅ Encrypted uploads (GitHub uses libsodium)
evnx doctor
Health check - Diagnose common issues.
Checks:
- ✅
.envexists and has secure permissions - ✅
.envis in.gitignore - ✅
.env.exampleexists and is tracked by Git - ✅ Project structure detection (Python, Node.js, Rust, Docker)
evnx template
Template generation - Dynamic config file creation.
Supports filters:
# config.template.yml
database:
host:
port:
ssl:
name:
evnx backup/restore (Requires --features backup)
Encrypted backups - AES-256-GCM encryption with Argon2 key derivation.
# Create backup
# Restore
Security:
- AES-256-GCM encryption
- Argon2 password hashing
- No secrets in plaintext
⚠️ Known Issues
Array/List Value Parsing
evnx currently does not support array-like or list-like values in .env files. This affects Django and other frameworks that use python-dotenv's extended syntax.
Will fail:
# Arrays with brackets
CORS_ALLOWED=["https://example.com", "https://admin.example.com"]
# Multiline values
DATABASE_HOSTS="""
host1.example.com
host2.example.com
"""
# JSON values
CONFIG=
Workaround:
# Use comma-separated strings instead
CORS_ALLOWED=https://example.com,https://admin.example.com
# Or use base64-encoded JSON
CONFIG_JSON=eyJrZXkiOiJ2YWx1ZSJ9
# Parse in your application code
# Python example:
))
)))
Why this limitation?
evnx follows the strict .env format specification which defines values as simple strings. Django's python-dotenv uses extended parsing that's not compatible with the standard format used by most other tools.
Tracking: We're considering adding a --lenient or --extended flag for compatibility. Follow Issue #XX for updates.
Affects:
- Django projects using complex ALLOWED_HOSTS or CORS settings
- Projects with JSON/YAML embedded in .env values
- Multiline string values
Does NOT affect:
# These work fine
DATABASE_URL=postgres://localhost/db
API_KEYS=key1,key2,key3 # Simple comma-separated
ALLOWED_HOSTS=example.com DEBUG=True
PORT=3000
Windows-Specific Issues
- File permissions checking is limited on Windows (no Unix permissions)
- Path handling uses backslashes (handled internally)
- Some terminal color codes may not display correctly in older CMD (use PowerShell or Windows Terminal)
These are tracked and will be improved in future releases.
🔧 CI/CD Integration
GitHub Actions
name: Validate Environment
on:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install evnx
run: |
curl -sSL https://raw.githubusercontent.com/urwithajit9/evnx/main/install.sh | bash
- name: Validate configuration
run: evnx validate --strict --format github-actions
- name: Scan for secrets
run: evnx scan --format sarif > scan-results.sarif
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: scan-results.sarif
GitLab CI
validate-env:
stage: validate
image: alpine:latest
before_script:
- apk add --no-cache curl bash
- curl -sSL https://install.dotenv.space | bash
script:
- evnx validate --strict --format json
- evnx scan --format sarif > scan.sarif
artifacts:
reports:
sast: scan.sarif
Pre-commit Hook
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: dotenv-validate
name: Validate .env files
entry: evnx validate --strict
language: system
pass_filenames: false
- id: dotenv-scan
name: Scan for secrets
entry: evnx scan --exit-zero
language: system
pass_filenames: false
⚙️ Configuration
Store preferences in .evnx.toml:
[]
= ".env"
= ".env.example"
= false
[]
= true
= false
= "pretty"
[]
= true
= ["*.example", "*.sample", "*.template"]
= "pretty"
[]
= "json"
= false
[]
= "github-actions"
= "kubernetes"
= "terraform"
🏗️ Development
# Clone repository
# Build (core features only)
# Build with all features
# Run tests
# Run with features
# Lint and format
Feature Flags
# Cargo.toml features
[]
= []
= ["reqwest", "base64", "indicatif"]
= ["aes-gcm", "argon2", "rand"]
= ["migrate", "backup"]
Why feature flags?
- Smaller binary size for basic usage
- Optional dependencies (reqwest, crypto libraries)
- Faster compilation during development
🤝 Contributing
Contributions welcome! See CONTRIBUTING.md.
Areas where help is appreciated:
- Additional format converters
- Secret pattern improvements
- Windows support enhancements
- Extended
.envformat support (arrays, multiline values) - Documentation improvements
- Integration examples
- Translation (i18n)
📜 License
MIT License - see LICENSE
Credits
Built by Ajit Kumar after learning the hard way about secrets management.
Inspired by:
- Countless developers who've accidentally committed secrets
- The pain of production incidents caused by misconfiguration
- The desire for better developer tooling
Related Projects:
- python-dotenv - Python implementation
- dotenvy - Rust dotenv parser
- direnv - Environment switcher
- git-secrets - AWS secret scanning
🆘 Support
⭐ Show Your Support
If this tool saved you from a secrets incident or made your life easier, please:
- ⭐ Star the repository
- 🐦 Tweet about it
- 📝 Write a blog post
- 💬 Tell your teammates
Your support helps improve the tool for everyone!
Made with 🦀 Rust and ❤️ by developers who've been there