Nobody ships the patch loop
Part of a short series on the patch loop. The first post argued that engineers merge patches that arrive in the right shape and skip the ones that do not. This post goes looking for who sells that shape.
Intro
If the last post is right, the product is obvious: take the 593-row dashboard and turn it into the kind of PR people already merge in a day. Scan the built image, keep the findings somewhere, decide which ones are fixable, patch them, and open one pull request with the before-and-after proof on it. That is the loop.
So I went looking for it. I took one deliberately out-of-date container image, scanned it the same way every time with two scanners, and pointed every product that claimed to patch at it, trying seven of them hands-on and reading the rest closely. I kept the receipts so the numbers below are measured, not remembered.
Here is the short version: every product owns one piece of the loop, several own two, and not one owns the whole thing. The gap is always in the same place.
I. The loop, stated plainly
Five steps, in order:
- Observe. Scan the built image by digest, ideally with more than one scanner, because they disagree. On my test image Trivy and Grype shared 230 finding ids and disagreed on 180.
- Translate. Turn two scanners’ different vocabularies into one list of real findings, backport-aware, with the smallest version that actually fixes each one.
- Decide. For each finding, pick a disposition: patch the OS package, bump the app dependency, bump the base image, or mark it unfixable with a reason.
- Act. Patch the OS packages in place, bump the dependencies and tags by pull request, under one author, with smoke tests.
- Prove. Rescan the result, put the before-and-after table on the PR, attach a machine-readable statement of what you could not fix.
Now watch where each product falls off.
II. The patchers: they patch, they don’t PR
Copa is the real one for OS packages. Hand it the image and a Trivy report and it patches the fixable operating-system packages in place, no rebuild: on my image, Debian went from 473 OS findings to 339, with zero fixable ones left over, and it even emitted an OpenVEX document listing the 92 fixes. That is a genuine Act step, for free, Apache-licensed.
And then it stops. It does not touch application dependencies: 104 Go findings and 16 Python ones sat untouched. It does not bump a base tag. It does not open a pull request, keep any state, or rescan. It produces a patched image and hands it back. Copa is one arm of Act, and only one arm.
The dependency bots are the other arm. Renovate opened four [SECURITY] pull requests on my test repo, citing CVE and GHSA ids, including a Go x/net bump. Dependabot found 21 alerts and opened PRs for x/net, requests, urllib3, and would even bump a dated Debian base tag. Both are excellent at the thing Copa cannot do, and useless at the thing Copa does: neither reads a scan of your built image, neither touches the OS packages inside it. They work from the manifests in your repo, not from the digest you ship.
So the two halves of Act exist, for free, and do not know about each other. Nobody runs both arms and reconciles them.
III. The base-image vendors: they swap the floor, not the furniture
The hardened-image companies attack the problem from underneath: replace your base image with one that starts clean.
Chainguard took my image’s base layer from 593 Trivy findings to 39 on a rebuild, zero of them OS packages. Docker Hardened Images ship signed, with an SBOM, a VEX document, and SLSA 3 provenance. These are real, and for the OS layer they are the strongest answer there is.
But they are a different product than the loop, in two ways. First, they do not touch your application dependencies: after swapping to a hardened base, my rebuild still carried 16 Python and 23 Go findings, because those are your code’s dependencies, not the base’s. Second, they do not open a pull request against your repository; they hand you a new image to adopt, and keeping your FROM line current after that is back to being your unowned, unrewarded job. There is also a cost gap worth naming: the hardened runtime image I measured from one vendor was not zero on a third-party scanner (55 on Trivy, 110 on Grype, none fixable), because a vendor’s VEX moves different scanners by different amounts. The floor is cleaner. The furniture is still yours, and the proof still has to be argued per scanner.
IV. The ledgers: they decide, then stop
There is a whole category that does the Translate and Decide and Memory steps beautifully and then does not act at all. Dependency-Track keeps a project per image version, analysis states with justifications, VEX in and out, KEV and EPSS enrichment, policy violations, time series. DefectDojo does findings, risk acceptance and SLAs. DevGuard does risk scoring and tickets. GUAC builds a graph over all your SBOMs and attestations.
These are the memory and the judgement the loop needs, and I lean on one of them in the design. But not one has an actions step. None of them opens a pull request, produces a patched digest, or records “this change took the image from digest X to digest Y and closed 185 findings.” They know everything and change nothing. That is by design; they are the system of record, not the hand. The hand is still missing.
V. The AI ones: they act, but not the same way twice
The newest category uses a language model to generate the fix. AISLE produces source-level fix PRs with human approval. Cast AI generates Dockerfile edits, tests them for build success and fewer findings, and opens a PR. Both are doing the Act step the ledgers skip, which is real progress.
My problem with them for this particular loop is determinism. A patch PR is a thing you have to trust enough to merge without reading every line, and you earn that trust by the tool doing the same safe thing every time: the smallest fixing version, the same disposition for the same finding, a proof you can check. A model that writes a plausible Dockerfile edit is doing something genuinely harder than this loop needs, and paying for it in reproducibility. Every step in the loop above is deterministic and checkable. I did not want to trade that away to close a CVE.
Conclusion
Line them up and the gap is always in the same place. Copa patches the OS and does not PR. The bots PR the dependencies and cannot read a scan or touch the OS. The base vendors swap the floor and leave your dependencies and never open a PR. The ledgers decide and stop. The AI ones act but will not tell you the same thing twice. Observe exists twice over, Act exists in halves that do not talk, and the connective steps, Translate, Decide, Prove, the ones that turn a pile of findings into a single mergeable PR, are owned by nobody.
That is a strange result, because none of the missing pieces is exotic. They are glue. The last post in this series is what that glue would actually look like, which open-source parts you would bolt it to, and the one honest limit nobody can engineer away.