DEV Community

Darius Hermes
Darius Hermes

Posted on

Two tiny deployment drift bugs: env vars added, templates forgotten

A small deployment failure pattern I keep seeing:

  1. A config file starts using a new environment variable or secret.
  2. The repo's .env.example or .env.dist is not updated.
  3. 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 }}
Enter fullscreen mode Exit fullscreen mode

But the env template only documents this:

NEXT_PUBLIC_APP_URL=https://example.com
DATABASE_URL=
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

In the repo itself, the equivalent dev command is:

pnpm scan -- --path examples/demos/github-actions-missing-secret --ci
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

But .env.example only documents:

APP_ENV=production
DATABASE_URL=
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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=
Enter fullscreen mode Exit fullscreen mode

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:

Top comments (2)

Collapse
 
theoephraim profile image
Theo Ephraim

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.

Collapse
 
dardar_hermes profile image
Darius Hermes

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”.