Skip to content

tweakyourpc/envsentinel

Repository files navigation

EnvSentinel

envsentinel is a contract-driven CLI that prevents .env drift across local development, CI, and production deployments.

Why this exists

Teams lose time and reliability when environment variables are undocumented, silently renamed, or incorrectly typed. Typical failure modes:

  • New teammate copies an old .env and misses required variables.
  • CI passes while production crashes because a value is malformed.
  • .env.example goes stale and stops reflecting real requirements.

EnvSentinel treats environment configuration as a versioned contract:

  • Validate one or more .env files against a JSON schema contract.
  • Fail fast in CI with clear, actionable diagnostics.
  • Generate .env.example directly from the contract to avoid drift.
  • Bootstrap a starter contract from an existing .env.

Core commands

  • envsentinel init: scaffold a contract from an existing .env
  • envsentinel check: validate .env files against that contract (--json, --junit, --env-glob, --env-dir, --exclude-env-glob)
  • envsentinel example: generate .env.example from the contract

Install

From PyPI (after first release):

pipx install envsentinel

Or:

python -m pip install envsentinel

From source:

python -m pip install .

For editable development:

python -m pip install -e .

Quick start

  1. Create a contract from your current .env:
envsentinel init --from-env .env --schema envsentinel.json
  1. Refine envsentinel.json rules (required, type, pattern, choices, bounds).

  2. Validate in local dev and CI:

envsentinel check --schema envsentinel.json --env .env

CI-friendly JUnit report:

envsentinel check --schema envsentinel.json --env .env --junit reports/envsentinel.junit.xml

Validate a set of env files with glob patterns:

envsentinel check --schema envsentinel.json --env-glob ".env.*" --exclude-env-glob ".env.example"

Recursively discover env files inside directories:

envsentinel check --schema envsentinel.json --env-dir services --env-dir apps
  1. Regenerate .env.example from the contract:
envsentinel example --schema envsentinel.json --output .env.example --force

Contract format

Contract file is JSON:

{
  "version": 1,
  "allow_unknown": false,
  "variables": {
    "APP_ENV": {
      "required": true,
      "type": "string",
      "choices": ["dev", "stage", "prod"],
      "description": "Deployment environment"
    },
    "PORT": {
      "required": true,
      "type": "int",
      "min": 1,
      "max": 65535,
      "default": 8000
    },
    "DATABASE_URL": {
      "required": true,
      "type": "url",
      "sensitive": true
    }
  }
}

Supported field semantics:

  • required (bool): if missing and no default, validation fails.
  • type (string|int|float|bool|url|email): value type constraint.
  • choices (list[str]): must match one of the listed values.
  • pattern (regex): full-match regex constraint.
  • min, max (number):
    • numeric bounds for int and float
    • length bounds for string (must be integer bounds for string)
  • default: used for generated example output and documentation.
  • sensitive (bool): when true, defaults must be empty or null; generated starter contracts never persist raw secret defaults.
  • allow_unknown (bool): whether keys outside variables are allowed.

Parser guarantees:

  • Duplicate keys in .env are rejected with file/line diagnostics.
  • Invalid dotenv syntax fails fast with source line context.

CI integration

Use the included GitHub Actions workflow (.github/workflows/ci.yml) as a baseline. In your project, add a validation step:

envsentinel check --schema envsentinel.json --env .env

For monorepos or environment matrices:

envsentinel check --schema envsentinel.json --env services/api/.env --env services/worker/.env

Or discover files by pattern:

envsentinel check --schema envsentinel.json --env-glob "services/*/.env"

Or recursively scan directories for .env and .env.* files:

envsentinel check --schema envsentinel.json --env-dir services

Pre-commit integration

EnvSentinel is most useful when it runs before bad configuration changes are committed.

Quick local setup

  1. Install both tools in your project environment:
python -m pip install -e .
python -m pip install pre-commit
  1. Copy the example config:
cp .pre-commit-config.example.yaml .pre-commit-config.yaml
  1. Install git hooks:
pre-commit install
  1. Validate immediately:
pre-commit run --all-files

Using EnvSentinel as a hook repo

This repository ships a .pre-commit-hooks.yaml manifest. Once you publish tagged releases, consumers can reference it directly:

repos:
  - repo: https://github.com/<your-org>/envsentinel
    rev: v0.1.0
    hooks:
      - id: envsentinel-check
        args: ["--schema", "envsentinel.json", "--env", ".env"]

Example workflow in a deploy pipeline

  1. Contract changes are reviewed in pull requests.
  2. CI runs envsentinel check against environment templates.
  3. .env.example is regenerated from contract and committed.
  4. Deploy jobs validate runtime-loaded env files before rollout.

This catches configuration regressions before runtime.

Development

Run tests:

python -m unittest discover -s tests -v

Install development tooling:

python -m pip install -e ".[dev]"

Publishing

This repository includes a PyPI publish workflow at .github/workflows/publish.yml.

One-time setup

  1. Create the project on PyPI.
  2. Configure a PyPI Trusted Publisher for this GitHub repository.
  3. Ensure your default branch CI is green.

Release flow

  1. Bump version in pyproject.toml.
  2. Run local checks:
python -m pip install -e ".[dev]"
python -m unittest discover -s tests -v
python -m build
python -m twine check dist/*
  1. Commit, tag, and push:
git tag v0.1.0
git push origin v0.1.0

Pushing a v* tag triggers the publish workflow and uploads dist/* to PyPI.

Technical decisions

  • Zero external runtime dependencies: keeps install friction low.
  • Typed rule model: schema validation catches contract mistakes early.
  • Human + JSON output modes: supports both local debugging and machine parsing.
  • Parser strictness: invalid dotenv syntax fails fast with file/line context.

Roadmap

  • YAML contract support.
  • Optional secret-manager backends for default resolution.
  • Contract drift check against deployed environments.

License

MIT

Contributing

See CONTRIBUTING.md.

Bug reports and PRs welcome — please open an issue first for large changes.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages