This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Base image digest ledger
|
||||
|
||||
Every external base image referenced by `deploy/*.Dockerfile` must be pinned
|
||||
by an immutable `@sha256:` digest before a production release
|
||||
(`docs/operations/DEPLOYMENT_UNRAID.md` §6 "immutable release/image digests
|
||||
recorded"; `docs/architecture/SECURITY_THREAT_MODEL.md` §5 "immutable image
|
||||
digest in production record").
|
||||
|
||||
The digests below were resolved with `docker buildx imagetools inspect` on
|
||||
2026-08-10. Do not hand-type a digest into this table or a Dockerfile without
|
||||
resolving it against the real registry first.
|
||||
|
||||
## Status
|
||||
|
||||
| Image | Used in | Status |
|
||||
|---|---|---|
|
||||
| `golang:1.26.6-alpine` | `agent.Dockerfile:1`, `api.Dockerfile:1`, `migrate.Dockerfile:1`, `worker.Dockerfile:1`, `smoke-fixture.Dockerfile:1` (build stage), `postgres.Dockerfile:4` (`gosu-builder` stage) | DONE — pinned `@sha256:3889b425f035be855a72fb4755265311293b6d414521f0a519d819df32222d83` |
|
||||
| `alpine:3.22` | `agent.Dockerfile:8`, `api.Dockerfile:8`, `migrate.Dockerfile:8`, `worker.Dockerfile:8` (runtime stage) | DONE — pinned `@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce` |
|
||||
| `node:24-bookworm-slim` | `web.Dockerfile:4` (build stage) | DONE — pinned `@sha256:3638d9a6fe4030bd716be989438248074489337ba3275657f93595428be4fc03` |
|
||||
| `nginx:1.29-alpine` | `web.Dockerfile:10` (runtime stage) | DONE — pinned `@sha256:5616878291a2eed594aee8db4dade5878cf7edcb475e59193904b198d9b830de` |
|
||||
| `postgres:17-alpine` | `postgres.Dockerfile:26` (runtime stage) | DONE — pinned `@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193` |
|
||||
|
||||
## Resolving a digest
|
||||
|
||||
Requires network access and Docker. From a trusted machine (not
|
||||
necessarily this repo's build host):
|
||||
|
||||
```sh
|
||||
# Option A: buildx imagetools (works without pulling the image locally)
|
||||
docker buildx imagetools inspect golang:1.26.6-alpine
|
||||
# Read the top-level "Digest:" line for the manifest list, or the
|
||||
# platform-specific line under the linux/amd64 entry if this project only
|
||||
# ever builds for one architecture (check TARGETARCH usage in the
|
||||
# Dockerfile before choosing).
|
||||
|
||||
# Option B: pull + inspect
|
||||
docker pull golang:1.26.6-alpine
|
||||
docker inspect --format='{{index .RepoDigests 0}}' golang:1.26.6-alpine
|
||||
```
|
||||
|
||||
Repeat for every external registry image. Docker's built-in `scratch` rootfs is
|
||||
not a registry image and therefore has no manifest digest to pin.
|
||||
|
||||
## Applying a resolved digest
|
||||
|
||||
1. Edit the Dockerfile's `FROM` line to `FROM <image>:<tag>@sha256:<digest>`
|
||||
(keep the tag alongside the digest for human readability — the digest is
|
||||
what actually pins the build).
|
||||
2. Update the row above from `TODO: unresolved` to `DONE — pinned
|
||||
@sha256:<digest>` plus the resolution date.
|
||||
3. Run `sh deploy/verify-image-digests.sh` and confirm it reports `OK`.
|
||||
4. Record the resolved digest set in the deployment evidence per
|
||||
`docs/operations/DEPLOYMENT_UNRAID.md` §8 step 16 ("record
|
||||
digests/migration/config checksum").
|
||||
|
||||
## Enforcement
|
||||
|
||||
`deploy/verify-image-digests.sh` scans every `deploy/*.Dockerfile`, skips
|
||||
internal multi-stage references (`FROM <earlier-stage-name>`) and the built-in
|
||||
empty `scratch` rootfs, and fails (non-zero exit) if any external registry
|
||||
`FROM` line lacks `@sha256:`. All current external images are pinned and the
|
||||
gate passes. Run it as
|
||||
part of `docs/operations/DEPLOYMENT_UNRAID.md` §8 step 1 ("validate clean
|
||||
build and images") before any production build, and wire it into whichever
|
||||
CI/Makefile target performs that step (`make build`, `make compose-up`) as a
|
||||
blocking pre-flight — this repo's `Makefile`/CI config is outside `deploy/`
|
||||
so it is not modified by this change; that wiring is a follow-up.
|
||||
Reference in New Issue
Block a user