CI policy gates that stop bad deploys
Fail the pipeline on purpose—before production becomes the first reviewer
A green build that still ships a public S3 bucket or a missing migration is not CI—it is optimism. Policy gates turn “we usually remember” into “the pipeline refuses.” That is the whole point.
Separate verify from release
Keep a fast verify lane (lint, typecheck, unit tests) and a stricter release lane (integration, policy-as-code, signed images). Mixing them into one sluggish job teaches teams to skip CI when they are late.
Required checks on the default branch should be few and meaningful. Vanity checks that flake teach people to click “bypass.”
GitHub Actions: plan + policy before apply
Loading code…Policy that names the failure
Write policies for decisions you have already made: no public object stores, encryption required, forbidden IAM wildcards on production roles. Fail with a message a human can act on—not a raw Rego stack dump.
Deny public S3 in plan JSON
Loading code…Human gates stay human
Production applies should still require an environment protection rule or an explicit approval. Policy catches known bad patterns; humans catch novel ones. Neither replaces the other.
Log who approved, what digest shipped, and which commit produced it. Audits are cheaper when the pipeline already recorded the story.
Start with three gates
If you have nothing yet: (1) tests must pass, (2) infrastructure plan must pass policy, (3) production deploy needs approval. Expand only when a real incident shows a missing check—not when a blog post lists twenty tools.
Final thoughts
Good CI is a series of deliberate refusals. Make the pipeline the first reviewer for known risks, keep approvals for production judgment, and resist decorating the workflow with checks nobody trusts.
Related Articles
Observability for small product teams
Traces, metrics, and alerts sized for a team that still ships features every week
Private EKS + RDS: what production-ready means
Network boundaries, egress paths, and the checks that turn a cluster into a system you can sleep on
Ready to build something this considered?