An environment attaches secrets and an approval requirement to a job, which puts the gate in the platform rather than in a convention.
jobs:
deploy:
environment:
name: production
url: https://example.com
steps:
- run: ./deploy.sh
# configured on the repository, not in this file:
# required reviewers: two, from the ops team
# wait timer: 5 minutes
# deployment branches: main only
# secrets: scoped to this environment
Scoping the secrets to the environment is the part that does the security work: a job without environment: production cannot read the production credentials at all, so a workflow added by anybody cannot deploy by accident. The wait timer is more useful than it looks — five minutes between approval and execution is enough to cancel a deploy somebody immediately regretted. The branch restriction closes the last gap, which is approving a deploy from a branch nobody reviewed.