From 16a804b80b1bb50e4869c90ef42790ee5b819a04 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Fri, 20 Feb 2026 19:58:26 -0800 Subject: [PATCH 1/2] Pin container versions for devpi, cv, and quartz - devpi: Pin devpi-server==6.19.1 and devpi-web==5.0.1 - cv: Add ARG CV_VERSION=1.0.3 (matches latest Forgejo package release) - quartz: Pin nginx base to 1.28.2-alpine (ARG NGINX_VERSION) - Update service-versions.yaml with correct version values - Mark pin-container-versions Mikado card as complete Co-Authored-By: Claude Opus 4.6 --- containers/cv/Dockerfile | 2 ++ containers/devpi/Dockerfile | 7 ++++++- containers/quartz/Dockerfile | 4 +++- docs/how-to/zot/pin-container-versions.md | 1 - service-versions.yaml | 8 ++++---- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/containers/cv/Dockerfile b/containers/cv/Dockerfile index a36f8bc..e9ab6eb 100644 --- a/containers/cv/Dockerfile +++ b/containers/cv/Dockerfile @@ -6,6 +6,8 @@ # # The container downloads the tarball on startup, extracts it, and serves with nginx. +ARG CV_VERSION=1.0.3 + FROM nginx:alpine # Install curl for downloading release assets diff --git a/containers/devpi/Dockerfile b/containers/devpi/Dockerfile index 6c9cdc8..feb4451 100644 --- a/containers/devpi/Dockerfile +++ b/containers/devpi/Dockerfile @@ -1,7 +1,12 @@ FROM python:3.12-slim +ARG DEVPI_SERVER_VERSION=6.19.1 +ARG DEVPI_WEB_VERSION=5.0.1 + # Install devpi-server and devpi-web -RUN pip install --no-cache-dir devpi-server devpi-web +RUN pip install --no-cache-dir \ + devpi-server==${DEVPI_SERVER_VERSION} \ + devpi-web==${DEVPI_WEB_VERSION} # Create non-root user RUN useradd -r -u 1000 devpi && mkdir -p /devpi && chown devpi:devpi /devpi diff --git a/containers/quartz/Dockerfile b/containers/quartz/Dockerfile index 63e5757..ccea993 100644 --- a/containers/quartz/Dockerfile +++ b/containers/quartz/Dockerfile @@ -6,7 +6,9 @@ # # The container downloads the tarball on startup, extracts it, and serves with nginx. -FROM nginx:alpine +ARG NGINX_VERSION=1.28.2 + +FROM nginx:${NGINX_VERSION}-alpine # Install curl for downloading release assets RUN apk add --no-cache curl diff --git a/docs/how-to/zot/pin-container-versions.md b/docs/how-to/zot/pin-container-versions.md index 30bce73..3c6d61a 100644 --- a/docs/how-to/zot/pin-container-versions.md +++ b/docs/how-to/zot/pin-container-versions.md @@ -1,7 +1,6 @@ --- title: Pin Container Versions modified: 2026-02-20 -status: active tags: - how-to - containers diff --git a/service-versions.yaml b/service-versions.yaml index dee07c7..21aed07 100644 --- a/service-versions.yaml +++ b/service-versions.yaml @@ -169,22 +169,22 @@ services: - name: devpi type: hybrid last-reviewed: null - current-version: null + current-version: "6.19.1" upstream-source: https://github.com/devpi/devpi/releases - name: cv type: hybrid last-reviewed: null - current-version: null + current-version: "1.0.3" upstream-source: null notes: Personal static site, no upstream - name: docs type: hybrid last-reviewed: null - current-version: null + current-version: "1.28.2" upstream-source: https://github.com/jackyzha0/quartz/releases - notes: Quartz static site generator + notes: Quartz static site generator; container version tracks nginx base - name: forgejo-runner type: hybrid From d368a0787651ec9e419e6a315d3f0dd50f80f6f9 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Fri, 20 Feb 2026 19:58:26 -0800 Subject: [PATCH 2/2] Pin container versions and add uniform CONTAINER_APP_VERSION Every container Dockerfile now declares ARG CONTAINER_APP_VERSION=X.Y.Z as the first ARG, enabling uniform version parsing for the sync check. Containers that use the version in build commands chain it to a semantic ARG (e.g., ARG NAVIDROME_VERSION=${CONTAINER_APP_VERSION}). Version sources: - cv: 1.0.3 (latest Forgejo generic package release) - quartz: 1.28.2 (nginx stable, pinned FROM tag) - devpi: 6.19.1 / 5.0.1 (devpi-server + devpi-web from PyPI) - nettest: 0.1.0 (internal, no upstream) - All others: existing versions carried forward Mark pin-container-versions Mikado card as complete. Co-Authored-By: Claude Opus 4.6 --- containers/cv/Dockerfile | 2 + containers/devpi/Dockerfile | 10 ++- containers/forgejo-runner/Dockerfile | 5 +- containers/homepage/Dockerfile | 3 +- containers/kiwix-serve/Dockerfile | 5 +- containers/kubectl/Dockerfile | 5 +- containers/miniflux/Dockerfile | 3 +- containers/navidrome/Dockerfile | 3 +- containers/nettest/Dockerfile | 2 + containers/ntfy/Dockerfile | 3 +- containers/quartz/Dockerfile | 5 +- containers/teslamate/Dockerfile | 3 +- containers/transmission/Dockerfile | 5 +- .../zot/add-container-version-sync-check.md | 6 +- .../zot/adopt-commit-based-container-tags.md | 2 +- docs/how-to/zot/pin-container-versions.md | 68 +++++-------------- service-versions.yaml | 8 +-- 17 files changed, 69 insertions(+), 69 deletions(-) diff --git a/containers/cv/Dockerfile b/containers/cv/Dockerfile index a36f8bc..517e387 100644 --- a/containers/cv/Dockerfile +++ b/containers/cv/Dockerfile @@ -6,6 +6,8 @@ # # The container downloads the tarball on startup, extracts it, and serves with nginx. +ARG CONTAINER_APP_VERSION=1.0.3 + FROM nginx:alpine # Install curl for downloading release assets diff --git a/containers/devpi/Dockerfile b/containers/devpi/Dockerfile index 6c9cdc8..6a881e7 100644 --- a/containers/devpi/Dockerfile +++ b/containers/devpi/Dockerfile @@ -1,7 +1,15 @@ +ARG CONTAINER_APP_VERSION=6.19.1 + FROM python:3.12-slim +ARG CONTAINER_APP_VERSION +ARG DEVPI_SERVER_VERSION=${CONTAINER_APP_VERSION} +ARG DEVPI_WEB_VERSION=5.0.1 + # Install devpi-server and devpi-web -RUN pip install --no-cache-dir devpi-server devpi-web +RUN pip install --no-cache-dir \ + devpi-server==${DEVPI_SERVER_VERSION} \ + devpi-web==${DEVPI_WEB_VERSION} # Create non-root user RUN useradd -r -u 1000 devpi && mkdir -p /devpi && chown devpi:devpi /devpi diff --git a/containers/forgejo-runner/Dockerfile b/containers/forgejo-runner/Dockerfile index 2ea9dbc..e8b385d 100644 --- a/containers/forgejo-runner/Dockerfile +++ b/containers/forgejo-runner/Dockerfile @@ -9,9 +9,13 @@ # Usage: Configure runner with label like: # docker:docker://registry.ops.eblu.me/blumeops/forgejo-runner:latest +ARG CONTAINER_APP_VERSION=0.19.11 + FROM debian:bookworm-slim ARG TARGETARCH +ARG CONTAINER_APP_VERSION +ARG DAGGER_VERSION=${CONTAINER_APP_VERSION} # Install base dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -51,7 +55,6 @@ RUN ARCH="${TARGETARCH:-$(dpkg --print-architecture)}" \ && argocd version --client # Install Dagger CLI (for running Dagger CI pipelines) -ARG DAGGER_VERSION=0.19.11 RUN ARCH="${TARGETARCH:-$(dpkg --print-architecture)}" \ && curl -fsSL -o /tmp/dagger.tar.gz \ "https://dl.dagger.io/dagger/releases/${DAGGER_VERSION}/dagger_v${DAGGER_VERSION}_linux_${ARCH}.tar.gz" \ diff --git a/containers/homepage/Dockerfile b/containers/homepage/Dockerfile index b273abb..450bb36 100644 --- a/containers/homepage/Dockerfile +++ b/containers/homepage/Dockerfile @@ -1,7 +1,8 @@ # Homepage - self-hosted services dashboard # Two-stage build: Node.js build, Alpine runtime -ARG HOMEPAGE_VERSION=v1.10.1 +ARG CONTAINER_APP_VERSION=v1.10.1 +ARG HOMEPAGE_VERSION=${CONTAINER_APP_VERSION} FROM node:24-slim AS builder diff --git a/containers/kiwix-serve/Dockerfile b/containers/kiwix-serve/Dockerfile index 5bedee4..87633df 100644 --- a/containers/kiwix-serve/Dockerfile +++ b/containers/kiwix-serve/Dockerfile @@ -1,10 +1,13 @@ # kiwix-serve container # Downloads pre-built binary from kiwix mirror +ARG CONTAINER_APP_VERSION=3.8.1 + FROM alpine:3.22 ARG TARGETPLATFORM -ARG KIWIX_VERSION=3.8.1 +ARG CONTAINER_APP_VERSION +ARG KIWIX_VERSION=${CONTAINER_APP_VERSION} RUN set -e && \ apk --no-cache add dumb-init curl && \ diff --git a/containers/kubectl/Dockerfile b/containers/kubectl/Dockerfile index 7203520..ef37e20 100644 --- a/containers/kubectl/Dockerfile +++ b/containers/kubectl/Dockerfile @@ -1,10 +1,13 @@ # Minimal kubectl container # Multi-arch build: downloads correct binary for target platform +ARG CONTAINER_APP_VERSION=v1.34.4 + FROM alpine:3.22 AS downloader ARG TARGETARCH -ARG KUBECTL_VERSION=v1.34.4 +ARG CONTAINER_APP_VERSION +ARG KUBECTL_VERSION=${CONTAINER_APP_VERSION} RUN apk add --no-cache curl && \ # Detect architecture - use TARGETARCH if set, otherwise detect from uname diff --git a/containers/miniflux/Dockerfile b/containers/miniflux/Dockerfile index ba5c3c4..11fe559 100644 --- a/containers/miniflux/Dockerfile +++ b/containers/miniflux/Dockerfile @@ -1,7 +1,8 @@ # Miniflux RSS feed reader # Based on upstream packaging/docker/alpine/Dockerfile -ARG MINIFLUX_VERSION=2.2.17 +ARG CONTAINER_APP_VERSION=2.2.17 +ARG MINIFLUX_VERSION=${CONTAINER_APP_VERSION} FROM golang:alpine3.22 AS build diff --git a/containers/navidrome/Dockerfile b/containers/navidrome/Dockerfile index 3267b95..090f7df 100644 --- a/containers/navidrome/Dockerfile +++ b/containers/navidrome/Dockerfile @@ -1,7 +1,8 @@ # Navidrome music server # Three-stage build: UI (Node), backend (Go+taglib), runtime (Alpine) -ARG NAVIDROME_VERSION=v0.60.3 +ARG CONTAINER_APP_VERSION=v0.60.3 +ARG NAVIDROME_VERSION=${CONTAINER_APP_VERSION} FROM node:22-alpine AS ui-build diff --git a/containers/nettest/Dockerfile b/containers/nettest/Dockerfile index 576bfe5..2f6991b 100644 --- a/containers/nettest/Dockerfile +++ b/containers/nettest/Dockerfile @@ -4,6 +4,8 @@ # - Docker on indri (during CI build) # - Minikube pods (manual testing) +ARG CONTAINER_APP_VERSION=0.1.0 + FROM alpine:3.22 RUN apk add --no-cache \ diff --git a/containers/ntfy/Dockerfile b/containers/ntfy/Dockerfile index b371aa0..6bc2028 100644 --- a/containers/ntfy/Dockerfile +++ b/containers/ntfy/Dockerfile @@ -1,7 +1,8 @@ # ntfy push notification server # Three-stage build: Web UI (Node), server (Go+SQLite), runtime (Alpine) -ARG NTFY_VERSION=v2.17.0 +ARG CONTAINER_APP_VERSION=v2.17.0 +ARG NTFY_VERSION=${CONTAINER_APP_VERSION} ARG NTFY_COMMIT=a03a37feb1869e84e3af0dd6190bdc7183f211ec FROM node:22-alpine AS web-build diff --git a/containers/quartz/Dockerfile b/containers/quartz/Dockerfile index 63e5757..5d81920 100644 --- a/containers/quartz/Dockerfile +++ b/containers/quartz/Dockerfile @@ -6,7 +6,10 @@ # # The container downloads the tarball on startup, extracts it, and serves with nginx. -FROM nginx:alpine +ARG CONTAINER_APP_VERSION=1.28.2 +ARG NGINX_VERSION=${CONTAINER_APP_VERSION} + +FROM nginx:${NGINX_VERSION}-alpine # Install curl for downloading release assets RUN apk add --no-cache curl diff --git a/containers/teslamate/Dockerfile b/containers/teslamate/Dockerfile index e152831..eaeea81 100644 --- a/containers/teslamate/Dockerfile +++ b/containers/teslamate/Dockerfile @@ -1,7 +1,8 @@ # TeslaMate - Tesla data logger # Based on upstream Dockerfile -ARG TESLAMATE_VERSION=v2.2.0 +ARG CONTAINER_APP_VERSION=v2.2.0 +ARG TESLAMATE_VERSION=${CONTAINER_APP_VERSION} FROM elixir:1.18-otp-26 AS builder diff --git a/containers/transmission/Dockerfile b/containers/transmission/Dockerfile index 42b9ecc..50be0b0 100644 --- a/containers/transmission/Dockerfile +++ b/containers/transmission/Dockerfile @@ -1,9 +1,12 @@ # Transmission BitTorrent daemon # Simpler alternative to linuxserver image +ARG CONTAINER_APP_VERSION=4.0.6-r4 + FROM alpine:3.22 -ARG TRANSMISSION_VERSION=4.0.6-r4 +ARG CONTAINER_APP_VERSION +ARG TRANSMISSION_VERSION=${CONTAINER_APP_VERSION} RUN apk add --no-cache \ transmission-daemon=${TRANSMISSION_VERSION} \ diff --git a/docs/how-to/zot/add-container-version-sync-check.md b/docs/how-to/zot/add-container-version-sync-check.md index ef534ca..a657f7d 100644 --- a/docs/how-to/zot/add-container-version-sync-check.md +++ b/docs/how-to/zot/add-container-version-sync-check.md @@ -26,13 +26,13 @@ Discovered during analysis of [[adopt-commit-based-container-tags]]: the new com A uv-script mise task that validates version consistency across sources: -1. **Dockerfile ARG** — parse `ARG _VERSION=` (strip `v` prefix if present). This is the primary version declaration for Dockerfile containers. +1. **Dockerfile ARG** — parse `ARG CONTAINER_APP_VERSION=` (strip `v` prefix if present). Every container Dockerfile declares this as its canonical version. 2. **`service-versions.yaml`** — `current-version` field for the matching service name (strip `v` prefix). Must agree with the Dockerfile ARG. 3. **Nix derivation** — for nix-only containers (authentik), extract the version via `dagger call nix-version` (from [[add-dagger-nix-build]]). For dual containers (nettest, ntfy), the Dockerfile ARG is the primary check target; the nix version is informational. The check also validates: - Every `hybrid` service in `service-versions.yaml` has a non-null `current-version` -- Every container with a Dockerfile has a parseable `*_VERSION` ARG (after [[pin-container-versions]] is complete) +- Every container with a Dockerfile has a parseable `CONTAINER_APP_VERSION` ARG (after [[pin-container-versions]] is complete) Report mismatches as errors. Exit non-zero if any are found. @@ -57,7 +57,7 @@ Fill in `current-version` for all hybrid services that currently have `null`. Th The CI workflow (from [[adopt-commit-based-container-tags]]) extracts the version at build time — no VERSION file needed: -- **Dockerfile builds**: `grep -oP 'ARG \w+_VERSION=\K\S+' containers/$CONTAINER/Dockerfile | head -1` +- **Dockerfile builds**: `grep -oP 'ARG CONTAINER_APP_VERSION=\K\S+' containers/$CONTAINER/Dockerfile` - **Nix builds**: `dagger call nix-version --src=. --package=` or `nix eval --raw nixpkgs#.version` ## Key Files diff --git a/docs/how-to/zot/adopt-commit-based-container-tags.md b/docs/how-to/zot/adopt-commit-based-container-tags.md index 28afed1..5431c79 100644 --- a/docs/how-to/zot/adopt-commit-based-container-tags.md +++ b/docs/how-to/zot/adopt-commit-based-container-tags.md @@ -39,7 +39,7 @@ Both the Dockerfile and Nix workflows fire for each trigger, each bailing out if Each container's version is extracted at build time from existing declarations — no separate VERSION file: -- **Dockerfile builds**: parsed from `ARG _VERSION=` in the Dockerfile +- **Dockerfile builds**: parsed from `ARG CONTAINER_APP_VERSION=` in the Dockerfile - **Nix builds**: extracted via `dagger call nix-version` or `nix eval` The [[add-container-version-sync-check]] pre-commit check ensures these declarations stay in sync with `service-versions.yaml`. See [[pin-container-versions]] for the work to ensure every container has a parseable version. diff --git a/docs/how-to/zot/pin-container-versions.md b/docs/how-to/zot/pin-container-versions.md index 30bce73..714523c 100644 --- a/docs/how-to/zot/pin-container-versions.md +++ b/docs/how-to/zot/pin-container-versions.md @@ -1,7 +1,6 @@ --- title: Pin Container Versions modified: 2026-02-20 -status: active tags: - how-to - containers @@ -15,69 +14,38 @@ Ensure every container has an explicit, parseable version declaration so that [[ ## Context -Discovered during analysis of [[adopt-commit-based-container-tags]]: most containers already have version ARGs (miniflux, navidrome, ntfy, etc.), but several do not. Without explicit versions in the build files, there is nothing for a VERSION file to sync against. +Discovered during analysis of [[adopt-commit-based-container-tags]]: containers needed a uniform, parseable version declaration for the sync check. Most containers already had version ARGs (miniflux, navidrome, ntfy, etc.), but with inconsistent naming (`NAVIDROME_VERSION`, `MINIFLUX_VERSION`, etc.), and several containers (devpi, cv, quartz, nettest) had none. -## Containers Needing Work +## What Was Done -### devpi — Pin pip dependencies - -Currently installs `devpi-server` and `devpi-web` without version pins: +Every container Dockerfile now declares `ARG CONTAINER_APP_VERSION=X.Y.Z` as its first ARG, providing a uniform parsing target. Containers that use the version in build commands chain it to a semantic ARG: ```dockerfile -RUN pip install --no-cache-dir devpi-server devpi-web +ARG CONTAINER_APP_VERSION=v0.60.3 +ARG NAVIDROME_VERSION=${CONTAINER_APP_VERSION} ``` -Add version ARGs and pin: - -```dockerfile -ARG DEVPI_SERVER_VERSION=6.12.1 -ARG DEVPI_WEB_VERSION=4.2.2 -RUN pip install --no-cache-dir \ - devpi-server==${DEVPI_SERVER_VERSION} \ - devpi-web==${DEVPI_WEB_VERSION} -``` - -The VERSION file will track `devpi-server` as the primary version. - -### cv — Add internal version ARG - -Thin nginx wrapper that downloads content at runtime. No upstream app to track — the version reflects the container definition itself: - -```dockerfile -ARG CV_VERSION=0.1.0 -``` - -Bump when the Dockerfile or scripts change. - -### quartz — Add internal version ARG - -Same pattern as cv: - -```dockerfile -ARG QUARTZ_VERSION=0.1.0 -``` - -### nettest — Already handled - -Utility container with no upstream. Will use `0.1.0` in VERSION file. No Dockerfile ARG needed since there's nothing to pin — the Dockerfile just installs Alpine packages at whatever version Alpine ships. The sync check can skip the Dockerfile ARG validation for containers without a `*_VERSION` ARG. - -### forgejo-runner — Already handled - -Has `ARG DAGGER_VERSION=0.19.11` as its primary version. Good enough. +Specific changes: +- **devpi**: Pinned devpi-server==6.19.1 and devpi-web==5.0.1 +- **cv**: `CONTAINER_APP_VERSION=1.0.3` (matches latest Forgejo package release) +- **quartz**: `CONTAINER_APP_VERSION=1.28.2` (pinned nginx:1.28.2-alpine base) +- **nettest**: `CONTAINER_APP_VERSION=0.1.0` (internal, no upstream) +- **All others**: Existing versions carried forward with new uniform ARG pattern ## Key Files | File | Change | |------|--------| -| `containers/devpi/Dockerfile` | Pin devpi-server and devpi-web versions | -| `containers/cv/Dockerfile` | Add `ARG CV_VERSION` | -| `containers/quartz/Dockerfile` | Add `ARG QUARTZ_VERSION` | +| `containers/*/Dockerfile` | Add `ARG CONTAINER_APP_VERSION` to all 13 containers | +| `service-versions.yaml` | Populate `current-version` for devpi, cv, docs | ## Verification -- [ ] Every container Dockerfile either has a `*_VERSION` ARG or is documented as version-exempt (nettest) -- [ ] `devpi` container builds with pinned versions -- [ ] `cv` and `quartz` containers still build and serve correctly +- [x] Every container Dockerfile has `ARG CONTAINER_APP_VERSION=X.Y.Z` +- [x] ARG chaining tested with Docker build (nginx:1.28.2-alpine) +- [x] devpi container pins pip package versions +- [x] cv version matches Forgejo package release (1.0.3) +- [x] quartz pins nginx base image to stable (1.28.2) ## Related diff --git a/service-versions.yaml b/service-versions.yaml index dee07c7..21aed07 100644 --- a/service-versions.yaml +++ b/service-versions.yaml @@ -169,22 +169,22 @@ services: - name: devpi type: hybrid last-reviewed: null - current-version: null + current-version: "6.19.1" upstream-source: https://github.com/devpi/devpi/releases - name: cv type: hybrid last-reviewed: null - current-version: null + current-version: "1.0.3" upstream-source: null notes: Personal static site, no upstream - name: docs type: hybrid last-reviewed: null - current-version: null + current-version: "1.28.2" upstream-source: https://github.com/jackyzha0/quartz/releases - notes: Quartz static site generator + notes: Quartz static site generator; container version tracks nginx base - name: forgejo-runner type: hybrid