DEV Community

John Loper
John Loper

Posted on

Pin It or Bin It

How to Stop Shipping Garbage Before It Ships You

If your build still pulls ubuntu:latest, you’re not “cloud-native.” You’re running a randomizer in production.


Why Pinning Matters

Every tag that isn’t a digest is a liability.
:latest is not convenience; it’s negligence.

What you write What happens next
FROM node:latest You rebuild on Tuesday and ship a new kernel vulnerability.
pip install flask You pull in a supply-chain bomb before lunch.
terraform init You silently upgrade the AWS provider, then wonder why IAM exploded.

If you don’t pin it, you can’t attest it.
If you can’t attest it, you can’t trust it.


The Tools of the Trade

OPA (Open Policy Agent)

A fast, embeddable policy engine.
It doesn’t care what file you feed it — only that you speak JSON.

Conftest

A CLI built on top of OPA.
It handles the boring bits:

  • parses Dockerfiles, YAML, Terraform, JSON
  • feeds them into OPA
  • exits 1 on fail, 0 on pass That’s all you need for CI or pre-commit hooks.

Install it:

# macOS / Linux
brew install conftest@0.56.0
# or
curl -L https://github.com/open-policy-agent/conftest/releases/latest/download/conftest_$(uname -s)_$(uname -m).tar.gz \
  | tar -xz -C /usr/local/bin
Enter fullscreen mode Exit fullscreen mode

Run it:

conftest test Dockerfile --parser dockerfile
Enter fullscreen mode Exit fullscreen mode

It will parse your Dockerfile into JSON, run your Rego rules, and tell you exactly why your laziness failed policy.


Crane

Part of Google’s go-containerregistry toolkit.
It’s the BOFH’s Swiss army knife for container registries.

Use it to fetch digests, manifests, and metadata — fast, no daemon, no Docker socket.

Install it:

brew install go-containerregistry
# or
go install github.com/google/go-containerregistry/cmd/crane@0.20.02
Enter fullscreen mode Exit fullscreen mode

Pin any image:

img=python:3.12
echo "$img@$(crane digest "$img")"
Enter fullscreen mode Exit fullscreen mode

Result:

python:3.12@sha256:deadbeefbadc0ffee123456789...
Enter fullscreen mode Exit fullscreen mode

Now you know exactly which bits are running in prod.
No excuses, no surprises.


🪓 Policy as Code: The OPA Way

Create policies/dockerfile/pinning.rego:

package policies.dockerfile.pinning

deny[msg] {
  some s
  f := s.Commands[_]
  f.Name == "from"
  not contains(f.Value, "@sha256:")
  msg := sprintf("FROM %q missing digest", [f.Value])
}

deny[msg] {
  f := input.Stages[_].Commands[_]
  f.Name == "user"
  trim(f.Value) == "root"
  msg := "Dockerfile must set non-root USER"
}
Enter fullscreen mode Exit fullscreen mode

Test it manually:

conftest test Dockerfile --parser dockerfile --output table
Enter fullscreen mode Exit fullscreen mode

Expected output:

FAIL - Dockerfile - FROM "ubuntu:latest" missing digest
Enter fullscreen mode Exit fullscreen mode

🧷 Make It Automatic: Pre-commit Hook

.git/hooks/pre-commit:

#!/usr/bin/env sh
set -eu
conftest pull ghcr.io/your-org/precommit:1 >/dev/null || true
files=$(git diff --cached --name-only | grep -Ei '(Dockerfile|\.ya?ml)$' || true)
[ -z "$files" ] && exit 0
conftest test --parser=dockerfile --output table $files
Enter fullscreen mode Exit fullscreen mode

Try to commit a floating Dockerfile and watch it fail:

FAIL - Dockerfile - FROM "nginx:latest" missing digest
✖ OPA pre-commit checks failed.
Enter fullscreen mode Exit fullscreen mode

Success: laziness stopped at the gate.


The Philosophy

  • Small tools. crane for digests. conftest for checks. jq and yq for glue.
  • Zero GUIs. If it doesn’t fit in a pipeline, it doesn’t belong.
  • Fast failure. The only “UX” a BOFH cares about is exit 1.
  • Determinism > decoration. Pretty dashboards are for people who don’t read logs.

TL;DR

  1. Pin everythingimage@sha256:digest.
  2. Write Rego policies once; run everywhere.
  3. Use Conftest in pre-commit and CI.
  4. Use Crane to fetch digests and enforce reproducibility.
  5. Automate the yelling so you can focus on real problems.

Top comments (0)