Skip to content
→ All work

Case study 26 / 26

dotenv-doctor

Validates .env files against the committed .env.example — catching the configuration mistakes that only surface after a deploy.

Status
Released
Period
2026
Domain
tools · security
Language
Python
Last push
30 AUG 2026
License
MIT
Source of claims
README.md, src/dotenv_doctor/checks.py, src/dotenv_doctor/report.py, .github/workflows/ci.yml

A dependency-free Python CLI that treats .env.example as a contract: missing keys, unfilled placeholders, weak secrets, duplicate assignments, stray whitespace and real credentials committed to the example file are all reported — as text, JSON or GitHub annotations.

01/The problem

.env.example is a promise — these are the variables this service needs — and nothing enforces it. The file drifts, and every failure looks the same: a service that boots locally and dies in staging.

02/The system

A dependency-free Python CLI that treats .env.example as a contract: missing keys, unfilled placeholders, weak secrets, duplicate assignments, stray whitespace and real credentials committed to the example file are all reported — as text, JSON or GitHub annotations.

Module boundaries4 components
  • cli.py to parser.py
  • parser.py to checks.py
  • checks.py to report.py

03/Implementation

  1. 01Example-contract checking: keys missing from the real file are errors, undocumented keys are warnings.
  2. 02Placeholder detection against ~25 template values, matched against the whole value so a real secret containing “changeme” is not flagged.
  3. 03Weak-secret detection for credential-shaped keys only, combining length with Shannon entropy.
  4. 04Nine live-credential shapes — AWS, GitHub, Slack, Stripe, OpenAI, Anthropic, Google, PEM private keys, JWTs — reported as errors when found in the example file.
  5. 05A parser for the awkward cases: export prefixes, inline comments, single vs double quoting with escapes, values containing =, and multi-line quoted values.
  6. 06Text, JSON and GitHub Actions output; exit codes 0 clean, 1 findings, 2 usage error.

04/Engineering

Four modules, one responsibility each

parser → checks → report → cli. Checks are pure functions over parsed data, so every rule is tested without touching a filesystem, and a new output format can never change a rule.

The intersection, not a shell

The parser implements only what mainstream loaders agree on (python-dotenv, docker-compose, foreman, direnv). Anything ambiguous becomes a parse issue rather than a guess.

False positives are bugs

Entropy is a weak signal used only alongside the key name — PORT=3000 is short and low-entropy, and is correctly left alone.

05/Interface

No product screenshots are published for this project. The visual above is a code-driven representation of how it behaves, built from the repository source — not a screenshot.

06/Tech stack

  • Python 3.10+
  • Zero runtime dependencies
  • pytest
  • mypy (strict)
  • ruff
  • GitHub Actions

07/Result

Verified outcomes

  • Released under MIT with CI, a strictly typed codebase, and tests for the parser, every rule and the CLI end to end.
  • Usable as a CI gate: --format github annotates findings inline on pull requests.

08/Links

Next case study

DataJewellers →