CI/CD & Deployment
The pipeline is the only way code reaches production, and that is the point. An automated, gated, repeatable pipeline turns deployment from a risky manual event into a routine, reversible, auditable step. It is also where our security and quality gates are actually enforced. A change that skips the pipeline skips everything that keeps production safe.
Continuous integration keeps the codebase always ready to release by building and testing every change automatically. Continuous delivery makes shipping boring through automation, gates, and the ability to roll back. For a regulated platform the pipeline does two jobs. It is the engineering productivity engine, and it is the control point where secret scanning, dependency and vulnerability checks, SAST, and tests must pass before anything merges or deploys.
The rules follow from that. All production changes go through the pipeline. Failing gates stop the work rather than being waved through. Nothing is deployed or changed by hand outside the pipeline. The Finperiti context, ARM zip-deploy with security gaps, is a reminder that how you deploy is part of your security posture, not separate from it.
Build and gate every change
- DoBuild once and promote the same artifact through environments. Never rebuild per environment or hand-craft what goes to prod.
- DoRun the full automated suite on every change (tests, secret scanning, dependency/vulnerability scan, and SAST) before merge.
- DoKeep main always ready to release: small, frequent, reviewed changes that integrate continuously rather than big risky merges.
- DoMake builds reproducible with pinned dependencies, so what passed CI is exactly what ships (see Dependency & Supply-Chain Security).
- AlwaysTreat a failing security or quality gate as a stop to be fixed. Never bypass, skip, or override it to ship.
- NeverMerge or release code that has not passed the automated security and quality checks.
Deploy safely and reversibly
- DoDeploy only through the pipeline, with the gates enforced and an audit trail of what was deployed, by whom, and when.
- DoMake deployments reversible: health checks plus a fast, tested rollback (or roll-forward), so a bad release means minutes of impact, not hours.
- DoKeep deploys backward-compatible during rollout (expand/contract for schema and contracts) so old and new versions run side by side safely (see Schema Versioning).
- ConsiderProgressive delivery (staged, canary, or blue/green) so a bad change is caught on a slice of traffic before it reaches everyone.
- AlwaysRun database migrations through the pipeline as part of the deploy, reviewed and reversible in intent, not by hand.
- NeverDeploy to production by hand or outside the pipeline, or change the production environment directly without change control and an audit trail.
# vuln scan failed; "ship it, we'll fix later"
az webapp deploy --src-path ./out.zip # straight to prod, no pipeline
A failing gate is waved through, and a hand deploy skips every check and leaves no audit trail. This is exactly how known-vulnerable, unreviewed code reaches production.
ci: build → test → secret-scan → dep-scan → SAST (all must pass)
cd: deploy to staging → smoke tests → canary 10% → full rollout
health checks gate each step; rollback is one click
Nothing ships without passing the gates. The deploy is staged and watched, and a bad release rolls back fast. All of it is recorded.
Self-review checklist
- AskIs this change going through the pipeline with all gates enforced?
- AskIf this release is bad, how fast can I roll back, and have I tested that?
- AskWill the old and new versions run together safely during rollout?
- AskAm I tempted to bypass a gate or deploy by hand, and why is that not happening?