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 production environment 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.
  • deploy declares needs: validate.
  • gitleaks runs 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.