Environments, Approvals, and Change Management
What This Concept Is
A pipeline does not just "deploy." It promotes an artifact through a sequence of environments -- dev, staging, production, plus sometimes canary, preview, or regional variants. Each environment has its own configuration, its own protections, and its own audit trail.
- Environment -- a named target in the pipeline with scoped secrets, URL, and deploy target. In GitHub Actions:
environment: production. In GitLab:environment: name: production. - Protection rules / approvals -- conditions that must be met before a job targeting that environment runs: required reviewers, wait timers, branch filters, required status checks.
- Change management -- the organizational process that wraps a production change: change ticket, approval, rollout window, rollback plan, communication.
Done well, these combine into an audit trail that satisfies both engineering and compliance without turning into deploy theater.
Why It Matters Here
Production is the environment where errors become revenue loss, incidents, or regulatory findings. But approvals and change management often become bureaucratic ritual that slows delivery without adding safety -- the "change advisory board meets Thursdays" pattern. The goal is to make safe changes fast and make risky changes visible.
Pipeline-native environments and approvals let you encode the minimum necessary ceremony as code:
- staging deploy: no approval, automatic
- production deploy of a small change: one reviewer, sub-minute approval
- production deploy of a high-risk change: two reviewers, defined window, rollback plan attached
- production DB migration: explicit separate approval from a DBA
Every step is logged, diffable, and auditable. DORA's empirical finding on external change-approval boards (CABs) is the single most-cited data point here: heavy external approval correlates negatively with delivery speed and does not improve stability -- the opposite of CAB's stated goal.
Concrete Example: Environment with Approval in GitHub Actions
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # no approval, just scoped secrets
steps:
- run: ./deploy.sh --env staging
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production # configured with required reviewers
url: https://api.acme.com
steps:
- run: ./deploy.sh --env production
In the repository settings for the production environment:
- Required reviewers: the on-call engineer group
- Wait timer: 0 minutes
- Deployment branches: only
main - Environment secrets: scoped AWS role (OIDC), not exposed to other environments
The deploy-production job pauses at start; a reviewer approves via the UI or API; the job runs with the environment's secrets. The approval event becomes part of the workflow log, searchable and exportable.
Concrete Example: GitLab Manual Job for Production
deploy_production:
stage: deploy
environment:
name: production
url: https://api.acme.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual # requires human to click "play"
script:
- ./deploy.sh --env production
when: manual is GitLab's equivalent of a required approval. Combined with protected branches and protected environments, it restricts who can click play.
Break-Glass, ChatOps, and Policy-as-Code
Three patterns that mature teams layer on top of the basic approval model:
- Break-glass procedure. A defined, recorded path to bypass approvals in an incident: e.g. labeling the workflow run with
break-glass:INC-1234, which triggers a separate audit channel and a mandatory post-incident review. Production access that is "impossible" at 3am is worse than access that is "logged at 3am." - ChatOps deploys. The
/deploy api v2.3.0 to prodcommand in a Slack channel becomes the approval and the audit trail and the comms channel. Everyone who needs to know sees it; the bot records who invoked it. Used heavily at GitHub, Heroku, and Shopify. - Policy-as-code for environments. Tools like OPA (Open Policy Agent) or Kyverno check a policy file against the deploy event: "only tagged commits can reach prod," "prod deploys must have a signed artifact," "prod deploys to
eu-west-1require a GDPR-trained approver." The policy lives in git alongside the code.
Each of these makes the recording of the change richer and the path less reliant on a single UI click.
Common Confusion / Misconception
"More approvers means safer deploys." Up to one, yes. Beyond one, approvers rubber-stamp and accountability dissolves. If three reviewers are needed, the real signal is that the change is too large -- split it. The DORA research is explicit here: external change-approval boards correlate negatively with delivery performance, and do not improve stability.
"Approval blocks scale linearly with risk." More useful: categorize changes by risk, then scale the friction. A config-only feature-flag flip needs no approval. A schema migration needs a named DB reviewer.
"Change tickets are just bureaucracy." They can be, if they are separate from the PR. If the change ticket is the PR -- auto-generated from the merge, linked to the deployment, with rollback notes in the description -- it becomes the single audit artifact, and engineers keep it current because it is on the path they already walk.
"Our production environment has one secret: ADMIN_TOKEN." That is not an environment, that is a shared key. A real environment configuration includes: OIDC role ARN, deploy target URL, required approvers, observability namespace, rollback tool endpoint.
"Break-glass access means bypassing approvals." It means recorded bypassing. A break-glass procedure should trigger an audit event, an automatic incident channel, and a post-incident review -- but it should exist. Production access that is "impossible" during an incident is worse than access that is "logged."
"Preview environments are just test." They are test environments with their own secrets, policies, and cost. A PR-per-environment model (e.g. Vercel preview deploys, ephemeral K8s namespaces) needs its own quota, teardown policy, and secret scoping -- it is not free by being short-lived.
How To Use It
For each service:
- List environments. At minimum: local, CI, staging, production. For multi-region: one production per region.
- Define per-environment configuration: secrets, role ARNs, URLs, approval requirements.
- Encode environments in the pipeline. No hidden UI-only configuration.
- Scale approvals by risk, not by habit. One approver is a good default.
- Attach a machine-readable rollout record to each production deploy: artifact digest, deployer identity, approver identity, timestamp, rollback command. (Concept 15 covers emitting this as a deploy marker.)
- Document break-glass: who can invoke, how it is logged, how it is reviewed afterward.
- If compliance demands SOX / SOC2 / ISO27001 evidence, the combination of pipeline YAML + environment protection + signed artifacts + deploy markers is usually a stronger story than a manual CAB, because every step is structured and queryable.
Check Yourself
- Why does adding a third required reviewer usually reduce delivery safety?
- What information belongs in a "production environment" configuration beyond a secret?
- How does a break-glass procedure differ from "bypassing" approvals?
- Name one thing a good change ticket contains that
git logdoes not. - What does policy-as-code (OPA/Kyverno) check that a GitHub "required reviewers" rule cannot?
Mini Drill or Application
Pick a production deploy you remember. Fill in:
- exact artifact digest deployed
- who approved
- what was the rollback command
- where is the deploy record visible today (UI, log, nowhere?)
- if you were asked in six months "what changed at that moment?" could you reconstruct it in < 5 minutes?
Any "no" or "not sure" is a specific gap in your change-management artifact.
Read This Only If Stuck
- Pro Git: Server-side hooks -- policy enforcement before merge
- Pro Git: Enforcing commit format / ACL via hooks
- Pro Git: Testing it out -- policy enforcement in practice
See also (external)
- GitHub Actions -- Managing environments for deployment -- environments, reviewers, wait timers
- GitHub Actions -- Deployment branches and tags -- restricting which refs deploy where
- GitLab -- Protected environments -- approvals and branch restrictions
- DORA -- Change approval processes -- empirical findings on CAB effectiveness
- Open Policy Agent (OPA) -- policy-as-code for deploy gates
- GitHub Blog -- ChatOps at GitHub -- canonical ChatOps deploy pattern