A small deployment failure pattern I keep seeing:
- A config file starts using a new environment variable or secret.
- The repo's
.env.exampleor.env.distis not updated. - The mismatch is discovered later, usually during a deploy job, local preview, worker boot, or production config check.
The bug is rarely dramatic in code review. It can be as small as one extra variable in CI/CD or Docker config.
Example 1: GitHub Actions secret drift
A workflow starts using a new secret:
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
But the env template only documents this:
NEXT_PUBLIC_APP_URL=https://example.com
DATABASE_URL=
Now STRIPE_SECRET_KEY has become an undocumented deployment requirement.
Run the demo fixture with Secret Coverage:
pnpm dlx @leviro-ai/secret-coverage scan --path examples/demos/github-actions-missing-secret --ci
In the repo itself, the equivalent dev command is:
pnpm scan -- --path examples/demos/github-actions-missing-secret --ci
Expected output:
# Secret Coverage Report
Readiness score: **73/100**
Critical: 1 · Warning: 0 · Info: 1
## Critical
- **STRIPE_SECRET_KEY** — STRIPE_SECRET_KEY is used in .github/workflows/deploy.yml but missing from an env template.
- Context: `.github/workflows/deploy.yml` · `missing-from-template`
- Fix: Add STRIPE_SECRET_KEY= to an env template and configure the value in your deployment environment.
Example 2: Docker Compose runtime drift
The same thing can happen outside CI. A Compose file starts expecting Redis:
services:
web:
environment:
APP_ENV: ${APP_ENV}
DATABASE_URL: ${DATABASE_URL}
REDIS_URL: ${REDIS_URL}
worker:
environment:
REDIS_URL: ${REDIS_URL}
But .env.example only documents:
APP_ENV=production
DATABASE_URL=
Now both the web service and worker depend on REDIS_URL, but the repository contract does not say so.
Run the demo fixture:
pnpm dlx @leviro-ai/secret-coverage scan --path examples/demos/docker-compose-missing-redis-url --ci
Expected output:
# Secret Coverage Report
Readiness score: **71/100**
Critical: 1 · Warning: 0 · Info: 2
## Critical
- **REDIS_URL** — REDIS_URL is used in docker-compose.yml but missing from an env template.
- Context: `docker-compose.yml` · `missing-from-template`
- Fix: Add REDIS_URL= to an env template and configure the value in your deployment environment.
That is deployment drift: deployment/runtime config expects something the repository's declared env contract does not describe.
The point is not to read or expose secret values. The check only compares metadata:
- variables documented by env templates;
- variables referenced by CI/CD, Docker, and config files;
- mismatches that should be fixed before deployment.
A minimal fix is to update the env template:
# GitHub Actions example
NEXT_PUBLIC_APP_URL=https://example.com
DATABASE_URL=
STRIPE_SECRET_KEY=
# Docker Compose example
APP_ENV=production
DATABASE_URL=
REDIS_URL=
Then configure the real values in GitHub Actions secrets, Docker/Compose runtime environment, or the deployment platform.
This is especially useful when AI-assisted PRs update application code and config quickly, because env contracts are easy to forget during review.
Secret Coverage is local-first and deterministic. It is not a vault and it does not need a cloud account for this check.
Links:
- npm: https://www.npmjs.com/package/@leviro-ai/secret-coverage
- GitHub: https://github.com/leviro-ai/secret-coverage
- GitHub Actions demo: https://github.com/leviro-ai/secret-coverage/tree/main/examples/demos/github-actions-missing-secret
- Docker Compose demo: https://github.com/leviro-ai/secret-coverage/tree/main/examples/demos/docker-compose-missing-redis-url
Top comments (2)
use varlock.dev - there is never a syncing issue, because your .env.example becomes a .env.schema and is actually involved in the loading process. Built-in validation, type safety, plugins to pull from various backends, and a lot more.
Thanks for sharing — Varlock looks like a good fit when a team wants the schema to be part of runtime env loading.
The angle I’m exploring here is a bit different: a local-first drift check for existing repos where CI/CD, Docker, and deployment config may already reference variables that the repo template forgot to document. So it’s less “replace env loading” and more “catch undocumented deployment assumptions before a deploy/PR review”.