Skip to content

CI/CD & Automation

My Builds Were Reproducible, So My Deployments Stopped

Ten microservices on EKS, images landing in the registry on every push, and a controller whose entire job is to notice new images and roll the pods. It noticed nothing. No errors, no warnings, just a log line reporting that it had considered ten images and updated zero of them.

The cause turned out to be a feature working correctly in one tool making another tool's core assumption false.

Building Only What Changed, and the Permissions Ceiling Nobody Warns You About

Ten services in one repository. Most commits touch one of them. Rebuilding all ten on every push is the default and it is wrong, so the pipeline detects which service directories changed and fans out one job per service.

Two things about that turned out to be harder than the idea: computing "what changed" correctly across every way a workflow can be triggered, and discovering that a reusable workflow cannot ask for permissions its caller did not grant.

The Jenkinsfile Rewrite Was Mostly Deletions

I rewrote a working Jenkins pipeline. The version that replaced it is longer, and the changes that mattered most were the two blocks I removed.

Both of them did the same thing: they asked the Jenkins server to supply something the pipeline needed. Taking them out is what made the file portable, and it is the single change I would make first to any Jenkinsfile I inherited.

The Same Pipeline on Two CI Engines: Jenkins and GitHub Actions

I implemented an identical DevSecOps pipeline twice for three applications, once as a Jenkinsfile and once as a GitHub Actions workflow. Same stages, same tools, same artifacts. Jenkins consistently needed about 40 percent more code. This is where that difference comes from, which of the divergences actually mattered, and the one place the two implementations had quietly stopped being identical without either file looking wrong.

Trivy Could Not Find the Image I Had Just Built

The build step succeeded. The next step scanned the image it had just produced and reported that no such image existed. Both steps were correct: the image was real, and it was not anywhere Trivy knew how to look. This is what load: true actually does, and why a scanner that fails to find an image is a more dangerous failure than one that finds vulnerabilities.

Twelve Fixes to a Pipeline That Was Already Passing

None of these were reported by anything. The pipeline was green before each fix and green after it. What changed is what the green meant: a coverage graph that was measuring infrastructure failures as test regressions, a success banner claiming images were published when nothing had been pushed, and a tag that would have deployed the four-character string null if one stage had ever been skipped.

Building a Multi-Arch Container CI Pipeline with Hard-Fail Security Gates

DebugBox ships 3 container image variants across 2 architectures to 2 registries, producing 22 tags per release. The pipeline that handles this has three properties I consider non-negotiable: no image ships without a security scan, no manual step is required to cut a release, and local development runs the same checks as CI.

This post covers the full pipeline architecture: how the base image lifecycle was separated from the variants, why SHA digest pinning replaced :latest, and how Trivy gates are configured to block releases on real vulnerabilities.