In two weeks, a CI/CD and infrastructure-as-code rebuild should leave you with four things that work end to end. A gate that runs before every push. Infrastructure described in code, with encrypted state. A plan step that stops destructive changes. And releases cut by tag and deployed by image digest. Our CI/CD and IaC package does this for USD 4,000 in two weeks.
“We’ll set up a pipeline” tells you nothing, so here are the actual commands. It’s the setup we run on the platforms we build, an AI marketing platform’s among them. For a portfolio-analytics SaaS platform, the promotion pipeline we built checks the same thing at the end: that what runs is what was released.
How do you know your CI/CD is working?
Use DORA’s metrics, which split delivery into throughput (change lead time, deployment frequency, failed deployment recovery time) and instability (change fail rate, deployment rework rate). DORA’s guide says speed and stability “are not tradeoffs”, so a rebuild that makes you deploy faster and break more hasn’t worked. If you want this built for you, the CI/CD and IaC package is our fixed-scope version of it.
Whether you measure these today is a fair question to ask yourself before you start. Plenty of teams think they do and don’t, and improving a number nobody trusts is wasted effort. How to measure DORA metrics goes through it from raw pipeline data.
What does the push gate do?
The cheapest place to catch a broken build is the developer’s machine, before anything leaves it. Ours runs four checks in parallel before every push: secrets scanning, typecheck, lint and build. If one fails, the push doesn’t happen.
A minimal version for a Node project:
#!/usr/bin/env bash
# scripts/push-gate.sh, run as: scripts/push-gate.sh && git push
set -euo pipefail
gitleaks git --redact --log-opts="origin/main..HEAD" &
pnpm typecheck & pnpm lint & pnpm build &
for job in $(jobs -p); do wait "$job"; done
wait on each job propagates its exit code, so one red check fails the whole gate. In some repos we add architecture boundary checks and a dead-code budget to the same script. It runs in seconds, locally, and the same rules apply to everyone. A rule that only some people’s machines enforce isn’t a rule.
How do you keep infrastructure-as-code state safe?
The state file maps your code to real resources, and it often holds sensitive values. Losing it hurts. Leaking it is worse. We use OpenTofu with encrypted state, and the documented setup is a few lines:
terraform {
encryption {
key_provider "pbkdf2" "main" {
passphrase = var.state_passphrase
}
method "aes_gcm" "main" {
keys = key_provider.pbkdf2.main
}
state {
method = method.aes_gcm.main
enforced = true
}
plan {
method = method.aes_gcm.main
enforced = true
}
}
}
Two warnings from the OpenTofu docs are worth repeating. With encryption on, state and plan files “become unrecoverable without the appropriate encryption key”. And on an existing project you need a temporary unencrypted fallback method to migrate. In production I’d use a cloud key management service rather than a passphrase, and the key never goes in the repository.
What is a destructive-change brake?
A plan that deletes a database looks exactly like a plan that adds a tag, unless something reads it. Ours does. OpenTofu’s JSON plan lists every resource change with its actions, and the docs suggest scanning that list for "delete", which catches deletes and replacements alike:
tofu plan -out=plan.bin
deletes=$(tofu show -json plan.bin \
| jq '[.resource_changes[] | select(.change.actions | index("delete"))] | length')
if [ "$deletes" -gt 0 ]; then
echo "Plan deletes or replaces $deletes resource(s); needs explicit approval." >&2
exit 1
fi
Resources that hold data also get prevent_destroy in their lifecycle. Removing one then takes a deliberate commit.
What does “release by tag, deploy by digest” mean?
A release is an annotated SemVer tag on the main branch: git tag -a v1.4.0 -m "..." && git push origin v1.4.0. The tag starts the pipeline, which builds the image, runs migrations if the repo has them, and deploys.
The deploy goes by the image’s content hash, registry/app@sha256:…. A mutable tag like latest can point at different bytes tomorrow. A digest names exactly one set of bytes, so you can prove that what runs in production is what you built and tested:
docker buildx build --push -t "$IMAGE:$TAG" --metadata-file meta.json .
DIGEST=$(jq -r '."containerimage.digest"' meta.json)
gcloud run deploy app --image="$IMAGE@$DIGEST" --region="$REGION"
Afterwards the pipeline reads back the digest the platform is really running and compares it with the one it built. If they differ, the release isn’t done. That’s how every production deploy of an AI marketing platform we built was verified across its 89 releases in 10 days. It’s also how the first release of a portfolio-analytics SaaS platform through its new pipeline was checked against its 12 running images.
What happens in the two weeks?
The exact plan is agreed on day one, but the order is usually the same.
Week 1 is reading and gating. We inventory what exists: repositories, pipelines, cloud accounts, manual steps, secrets. We stand up the local push gate. Then we bring existing infrastructure under code, importing what already runs instead of recreating it, with encrypted remote state.
Week 2 is the release path. We add the plan brake and prevent_destroy on anything that holds data, then build the tag-driven pipeline: build, migrate, deploy by digest, read back. Then we cut a real release through it and roll one back.
The exit criterion is a real change going from commit to production through the new path while you watch. A pipeline that has never shipped anything isn’t delivered.
Do I need to change my CI tool?
Usually not. The age of the CI server matters little, Jenkins included. Ask whether the pipeline definitions live in the repository, whether a run is reproducible, and whether the deploy step is tied to an immutable artifact. If all three are yes, switching tools is optional. If any is no, a new tool won’t fix it.
The tools are rarely the hard part. The hard part is the decisions nobody wants to make: who can approve a destructive plan, what blocks a release, how a rollback works, and who has actually tested it. Two weeks is enough when the scope is one product and its environments. With many products on different stacks, start with a Discovery, or treat the first product as the template for the rest. If you’re also weighing the tool underneath, OpenTofu vs Terraform covers the license question.
Describe your current release in one sentence. If it contains the words “someone runs”, this package is for you. Start the CI/CD & IaC package: USD 4,000, 2 weeks, or check every other package on the pricing page.
Sources, accessed 2026-10-06: DORA, software delivery performance metrics, OpenTofu docs, State and Plan Encryption.
