Documentation

envaudit

A fast, zero-dependency Rust CLI for detecting .env drift, validating environment files against .env.example, and scanning for accidentally committed secrets.


Installation

From crates.io

Install the latest release using Cargo. Requires Rust 1.70 or newer.

terminal
$ cargo install envaudit

Building from source

Clone the repository and build with Cargo. Useful for contributing or running unreleased changes.

terminal
$ git clone https://github.com/phonotechnologies/envaudit
$ cd envaudit
$ cargo build --release
$ ./target/release/envaudit --version

The compiled binary is at target/release/envaudit. Add it to your PATH.


Command Reference

envaudit exposes three subcommands. Each command exits with a non-zero code when issues are found, making it suitable as a CI gate.

terminal
$ envaudit --help
Usage: envaudit [COMMAND]
Commands:
scanDetect drift across multiple .env files
checkValidate .env against .env.example
secretsScan for accidentally committed secrets
helpPrint this message or help for a subcommand

envaudit scan

Compares all discovered .env files in the current directory tree and reports keys that are present in some files but missing from others. Useful for catching configuration drift between environments.

usage
$ envaudit scan [OPTIONS] [PATH]
Options:
--format<FORMAT>Output format: text (default) or json
--path<PATH>Root directory to scan (defaults to current directory)
--quietSuppress output, use exit code only
example output
$ envaudit scan
Scanning environment files...
Drift Report
MISSING in .env.production:
DATABASE_POOL_SIZE (present in .env.local)
FEATURE_FLAG_BETA (present in .env.staging)
EXTRA in .env.staging:
LEGACY_API_ENDPOINT (not in other envs)
2 drift issues found.

envaudit check

Validates a .env file against a .env.example template. Reports keys that are required (present in .env.example) but missing from .env, and keys in .env that are not documented in .env.example.

usage
$ envaudit check [OPTIONS]
Options:
--env<FILE>Path to .env file (defaults to ./.env)
--example<FILE>Path to .env.example (defaults to ./.env.example)
--format<FORMAT>Output format: text (default) or json
--strictFail on undocumented keys (default: warn only)
example output
$ envaudit check --env .env.production --example .env.example
Validating .env.production against .env.example...
Validation Report
MISSING required keys:
STRIPE_SECRET_KEY (required, not set)
SENDGRID_API_KEY (required, not set)
UNDOCUMENTED keys:
MY_LOCAL_DEBUG=true (not in .env.example)
2 missing keys, 1 undocumented.

envaudit secrets

Scans .env files for patterns that look like real secrets. Intended to catch cases where developers have committed actual credentials instead of placeholder values. Useful as a pre-commit hook or CI gate.

usage
$ envaudit secrets [OPTIONS] [PATH]
Options:
--path<PATH>Directory or file to scan
--format<FORMAT>Output format: text (default) or json
--include-exampleAlso scan .env.example files
example output
$ envaudit secrets --include-example
Scanning for committed secrets...
Secret Scan Report
DETECTED in .env.example:
Line 14: STRIPE_KEY=sk_live_a1b2c3... [stripe-secret-key]
Line 22: AWS_SECRET=AKIA... [aws-access-key]
2 secrets detected.
Replace with placeholder values immediately.

JSON Output

All three commands support --format json. This is the recommended format for CI pipelines, scripts, and integrations. The structure is consistent across commands.

scan --format json

json
{
  "command": "scan",
  "ok": false,
  "issues": [
    {
      "type": "missing",
      "key": "DATABASE_POOL_SIZE",
      "present_in": [".env.local", ".env.staging"],
      "missing_from": [".env.production"]
    },
    {
      "type": "extra",
      "key": "LEGACY_API_ENDPOINT",
      "present_in": [".env.staging"],
      "missing_from": [".env.local", ".env.production"]
    }
  ],
  "files_scanned": [".env.local", ".env.staging", ".env.production"],
  "issue_count": 2
}

check --format json

json
{
  "command": "check",
  "ok": false,
  "env_file": ".env",
  "example_file": ".env.example",
  "missing": [
    { "key": "STRIPE_SECRET_KEY", "required": true },
    { "key": "SENDGRID_API_KEY",  "required": true }
  ],
  "undocumented": [
    { "key": "MY_LOCAL_DEBUG", "value_preview": "true" }
  ],
  "issue_count": 3
}

secrets --format json

json
{
  "command": "secrets",
  "ok": false,
  "detections": [
    {
      "file": ".env.example",
      "line": 14,
      "key": "STRIPE_KEY",
      "pattern": "stripe-secret-key",
      "value_preview": "sk_live_a1b2..."
    },
    {
      "file": ".env.example",
      "line": 22,
      "key": "AWS_SECRET",
      "pattern": "aws-access-key",
      "value_preview": "AKIA..."
    }
  ],
  "files_scanned": [".env.example"],
  "detection_count": 2
}

CI tip: Use --format json | jq to filter and post-process results. Combine with the exit code to fail the build cleanly.


Exit Codes

envaudit uses standard POSIX exit codes. This makes it straightforward to use as a gate in CI pipelines, pre-commit hooks, and shell scripts.

CodeMeaning
0No issues found. All checks passed.
1Issues detected (drift, missing keys, or secrets found).
2Invalid arguments or missing required flags.
3File not found or could not be read.
CI example (GitHub Actions)
- name: Check .env drift
  run: envaudit scan --quiet
  # Fails the step if exit code != 0

- name: Validate .env against template
  run: |
    envaudit check --format json > env-report.json
    cat env-report.json | jq '.ok'

Something missing or incorrect? Open an issue on GitHub.