Validate config in GitHub Actions before deploy
The cheapest place to catch a missing DATABASE_URL is a GitHub Actions job; the most expensive is a crash-looping pod. This page adds a validation gate that runs before deploy, extending CI/CD Config Validation.
Problem 1: deploying first, discovering config errors second
# ANTI-PATTERN: no validation step — the bad config is found in production
jobs:
deploy:
steps:
- run: ./deploy.sh # boots the app for the first time in prod
The first time the settings model runs against production variables is in production.
Problem 2: validating against the wrong environment
# ANTI-PATTERN: validates with dev secrets, deploys to prod
- run: python -m ci.validate_config
env: { DATABASE_URL: $ } # not the deploy target
Passing dev secrets proves nothing about the environment you are about to deploy to.
Secure implementation
# .github/workflows/deploy.yml
jobs:
validate:
runs-on: ubuntu-latest
environment: production # pull this environment's protected secrets
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- run: gitleaks detect --no-banner
- run: python -m ci.validate_config
env:
DATABASE_URL: $
API_KEY: $
deploy:
needs: validate # deploy only if validation passed
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
The validate job uses GitHub Environments so it reads the production secrets, and deploy declares needs: validate so a failed model construction blocks the rollout.
Gotchas & version-specific behaviour
- Use
environment:to scope secrets to the deploy target, not repo-wide secrets. needs:is what gates deploy on validation — without it the jobs run independently.- Mark required reviewers on the
productionenvironment for a manual gate if needed. - Keep
extra="forbid"so a stray repo secret injected as an env var fails the job.
Production parity checklist
- The validate job reads the same environment’s secrets the deploy will use.
deploydeclaresneeds: validate.gitleaksruns before validation.- Secrets are masked; validation prints key names only.
- The job runs on the Python version used in production.
Conclusion
Gate deploy behind a validate job that constructs the model with the target environment’s secrets, and a bad config never reaches a pod. For the GitLab equivalent, see GitLab CI Config Validation Stage.