From a0c93f38ef196aff5c2bdb90ba2c64419254d012 Mon Sep 17 00:00:00 2001 From: Tim F Date: Sat, 24 Oct 2026 17:44:07 +0200 Subject: [PATCH] chore: harden and update supporting services (#6788) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: harden and update supporting services * chore(compose): pin ChromaDB and ntfy images by tag and digest chromadb/chroma:latest and a bare binwiederhier/ntfy change underneath an existing install on the next pull, so two hosts on the same commit can run different sidecar builds. SearXNG is already pinned this way. Pin chroma 1.5.9 and ntfy v2.32.0 to the multi-arch index digests that :latest currently resolves to, so nothing changes at runtime today. The standalone GPU files carry the same references, as test_gpu_compose_standalone.py requires. Add a test that every sidecar image has a release tag and a digest. --------- Co-authored-by: Léo --- ACKNOWLEDGMENTS.md | 4 ++-- docker-compose.gpu-amd.yml | 4 ++-- docker-compose.gpu-nvidia.yml | 4 ++-- docker-compose.yml | 4 ++-- tests/test_compose_sidecar_pins.py | 34 ++++++++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 tests/test_compose_sidecar_pins.py diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 38e184764..294289b7f 100644 --- a/ACKNOWLEDGMENTS.md +++ b/ACKNOWLEDGMENTS.md @@ -48,8 +48,8 @@ just composed. | Service | Image | Purpose | License | |---|---|---|---| | [SearXNG](https://github.com/searxng/searxng) | `searxng/searxng:2026.9.25-12f8b6515` (pinned tag; see compose) | Default metasearch backend | AGPL-3.0 | -| [ChromaDB](https://github.com/chroma-core/chroma) | `chromadb/chroma:latest` | Vector store for memory / RAG | Apache-2.0 | -| [ntfy](https://github.com/binwiederhier/ntfy) | `binwiederhier/ntfy` | Push notifications (self-hosted reminders) | Apache-2.0 / GPL-2.0 | +| [ChromaDB](https://github.com/chroma-core/chroma) | `chromadb/chroma:1.5.9` (pinned digest; see compose) | Vector store for memory / RAG | Apache-2.0 | +| [ntfy](https://github.com/binwiederhier/ntfy) | `binwiederhier/ntfy:v2.32.0` (pinned digest; see compose) | Push notifications (self-hosted reminders) | Apache-2.0 / GPL-2.0 | ## Bundled front-end libraries diff --git a/docker-compose.gpu-amd.yml b/docker-compose.gpu-amd.yml index 0e2cdbcb8..5c85014d6 100644 --- a/docker-compose.gpu-amd.yml +++ b/docker-compose.gpu-amd.yml @@ -127,7 +127,7 @@ services: - ${RENDER_GID:-render} chromadb: - image: docker.io/chromadb/chroma:latest + image: docker.io/chromadb/chroma:1.5.9@sha256:1e0b73a187a28757c572acba508c46f48c9e8b0acaf5c20e6d95cdedce1acdf6 ports: - "${CHROMADB_BIND:-127.0.0.1}:8100:8000" volumes: @@ -196,7 +196,7 @@ services: restart: unless-stopped ntfy: - image: docker.io/binwiederhier/ntfy + image: docker.io/binwiederhier/ntfy:v2.32.0@sha256:59250e1d8be2ee2186c4560322f625faef22ace380331f05b63f8842dbd62602 command: serve ports: - "${NTFY_BIND:-127.0.0.1}:8091:80" diff --git a/docker-compose.gpu-nvidia.yml b/docker-compose.gpu-nvidia.yml index 5d997f28b..5c628fcfb 100644 --- a/docker-compose.gpu-nvidia.yml +++ b/docker-compose.gpu-nvidia.yml @@ -130,7 +130,7 @@ services: capabilities: [gpu] chromadb: - image: docker.io/chromadb/chroma:latest + image: docker.io/chromadb/chroma:1.5.9@sha256:1e0b73a187a28757c572acba508c46f48c9e8b0acaf5c20e6d95cdedce1acdf6 ports: - "${CHROMADB_BIND:-127.0.0.1}:8100:8000" volumes: @@ -199,7 +199,7 @@ services: restart: unless-stopped ntfy: - image: docker.io/binwiederhier/ntfy + image: docker.io/binwiederhier/ntfy:v2.32.0@sha256:59250e1d8be2ee2186c4560322f625faef22ace380331f05b63f8842dbd62602 command: serve ports: - "${NTFY_BIND:-127.0.0.1}:8091:80" diff --git a/docker-compose.yml b/docker-compose.yml index 808471520..2b90227a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -108,7 +108,7 @@ services: restart: unless-stopped chromadb: - image: docker.io/chromadb/chroma:latest + image: docker.io/chromadb/chroma:1.5.9@sha256:1e0b73a187a28757c572acba508c46f48c9e8b0acaf5c20e6d95cdedce1acdf6 ports: - "${CHROMADB_BIND:-127.0.0.1}:8100:8000" volumes: @@ -177,7 +177,7 @@ services: restart: unless-stopped ntfy: - image: docker.io/binwiederhier/ntfy + image: docker.io/binwiederhier/ntfy:v2.32.0@sha256:59250e1d8be2ee2186c4560322f625faef22ace380331f05b63f8842dbd62602 command: serve ports: - "${NTFY_BIND:-127.0.0.1}:8091:80" diff --git a/tests/test_compose_sidecar_pins.py b/tests/test_compose_sidecar_pins.py new file mode 100644 index 000000000..6ba9cb901 --- /dev/null +++ b/tests/test_compose_sidecar_pins.py @@ -0,0 +1,34 @@ +"""Sidecar images must be pinned to a versioned tag and an immutable digest. + +A bare or ``:latest`` reference changes underneath an existing install on the +next ``docker compose pull``/``up``, so two hosts on the same commit can run +different ChromaDB or ntfy builds. The ``odysseus`` service is excluded: it is +the project's own image, selected through ``ODYSSEUS_IMAGE``. The standalone +GPU files are held equal to these services by test_gpu_compose_standalone.py. +""" + +import re +from pathlib import Path + +import pytest +import yaml + +COMPOSE = Path(__file__).resolve().parents[1] / "docker-compose.yml" +PINNED = re.compile(r"^[\w.\-/]+:(?P[\w.\-]+)@sha256:[0-9a-f]{64}$") + + +def _sidecars(): + services = yaml.safe_load(COMPOSE.read_text(encoding="utf-8"))["services"] + return {name: svc["image"] for name, svc in services.items() if name != "odysseus"} + + +def test_expected_sidecars_present(): + assert {"chromadb", "searxng", "ntfy"} <= set(_sidecars()) + + +@pytest.mark.parametrize("name", sorted(_sidecars())) +def test_sidecar_image_has_version_tag_and_digest(name): + image = _sidecars()[name] + match = PINNED.match(image) + assert match, f"{name}: expected :@sha256:, got {image!r}" + assert match.group("tag") != "latest", f"{name}: pin a release tag, not latest"