Agent Wranglers

Containers Required

Pin each base image by digest

Name every base image by version and digest, never by a moving tag such as latest. Choose the smallest image that runs the app.

How to do it

A tag can point to a new image tomorrow, and a digest cannot. Write FROM node:24.18.1-alpine@sha256:…. Let a bot such as Dependabot or Renovate open a pull request when a new digest appears. Prefer slim, Alpine or distroless images, because every extra package is one more thing to patch. Base images lag behind security fixes, so install the operating system's updates in the build, such as apk upgrade --no-cache, and let the scan confirm it.

Example

# Bad: a moving tag
FROM node:latest

# Good: version and digest, with an argument other files can read
ARG NODE_IMAGE=node:24.18.1-alpine@sha256:f70403e87646dc51b45295f4b8b70cdad0b63d2297c4c9899119b03f7af7a6b3
FROM ${NODE_IMAGE}
# Fails when an image is named without a digest. Stage names and ${ARG} references pass.
! grep -nE '^(FROM|ARG [A-Z_]*IMAGE=)' Dockerfile | grep -vE '@sha256:[0-9a-f]{64}|FROM \$\{[A-Z_]+\}|^[0-9]+:FROM [a-z0-9_-]+( AS |$)'

How to check

Every FROM line, or the ARG it reads, holds @sha256: and 64 hex characters, as the grep below confirms in CI. docker image inspect shows the same image ID in CI and production.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers operations playbook: https://agentwranglers.se/playbook/operations/containers/pinned-base-images.