Compare commits

...
Author SHA1 Message Date
RaresKeY 9d0d3720f4 fix(deps): require Pillow 13 with compatible FastEmbed (#6845) 2026-10-25 13:45:49 +01:00
Tim FandLéo a0c93f38ef chore: harden and update supporting services (#6788)
* 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 <leograndcontact@gmail.com>
2026-10-24 17:44:07 +02:00
6 changed files with 45 additions and 10 deletions
+2 -2
View File
@@ -48,8 +48,8 @@ just composed.
| Service | Image | Purpose | License | | 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 | | [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 | | [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` | Push notifications (self-hosted reminders) | Apache-2.0 / GPL-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 ## Bundled front-end libraries
+2 -2
View File
@@ -127,7 +127,7 @@ services:
- ${RENDER_GID:-render} - ${RENDER_GID:-render}
chromadb: chromadb:
image: docker.io/chromadb/chroma:latest image: docker.io/chromadb/chroma:1.5.9@sha256:1e0b73a187a28757c572acba508c46f48c9e8b0acaf5c20e6d95cdedce1acdf6
ports: ports:
- "${CHROMADB_BIND:-127.0.0.1}:8100:8000" - "${CHROMADB_BIND:-127.0.0.1}:8100:8000"
volumes: volumes:
@@ -196,7 +196,7 @@ services:
restart: unless-stopped restart: unless-stopped
ntfy: ntfy:
image: docker.io/binwiederhier/ntfy image: docker.io/binwiederhier/ntfy:v2.32.0@sha256:59250e1d8be2ee2186c4560322f625faef22ace380331f05b63f8842dbd62602
command: serve command: serve
ports: ports:
- "${NTFY_BIND:-127.0.0.1}:8091:80" - "${NTFY_BIND:-127.0.0.1}:8091:80"
+2 -2
View File
@@ -130,7 +130,7 @@ services:
capabilities: [gpu] capabilities: [gpu]
chromadb: chromadb:
image: docker.io/chromadb/chroma:latest image: docker.io/chromadb/chroma:1.5.9@sha256:1e0b73a187a28757c572acba508c46f48c9e8b0acaf5c20e6d95cdedce1acdf6
ports: ports:
- "${CHROMADB_BIND:-127.0.0.1}:8100:8000" - "${CHROMADB_BIND:-127.0.0.1}:8100:8000"
volumes: volumes:
@@ -199,7 +199,7 @@ services:
restart: unless-stopped restart: unless-stopped
ntfy: ntfy:
image: docker.io/binwiederhier/ntfy image: docker.io/binwiederhier/ntfy:v2.32.0@sha256:59250e1d8be2ee2186c4560322f625faef22ace380331f05b63f8842dbd62602
command: serve command: serve
ports: ports:
- "${NTFY_BIND:-127.0.0.1}:8091:80" - "${NTFY_BIND:-127.0.0.1}:8091:80"
+2 -2
View File
@@ -108,7 +108,7 @@ services:
restart: unless-stopped restart: unless-stopped
chromadb: chromadb:
image: docker.io/chromadb/chroma:latest image: docker.io/chromadb/chroma:1.5.9@sha256:1e0b73a187a28757c572acba508c46f48c9e8b0acaf5c20e6d95cdedce1acdf6
ports: ports:
- "${CHROMADB_BIND:-127.0.0.1}:8100:8000" - "${CHROMADB_BIND:-127.0.0.1}:8100:8000"
volumes: volumes:
@@ -177,7 +177,7 @@ services:
restart: unless-stopped restart: unless-stopped
ntfy: ntfy:
image: docker.io/binwiederhier/ntfy image: docker.io/binwiederhier/ntfy:v2.32.0@sha256:59250e1d8be2ee2186c4560322f625faef22ace380331f05b63f8842dbd62602
command: serve command: serve
ports: ports:
- "${NTFY_BIND:-127.0.0.1}:8091:80" - "${NTFY_BIND:-127.0.0.1}:8091:80"
+3 -2
View File
@@ -11,7 +11,8 @@ pydantic-settings>=2.14.1
SQLAlchemy SQLAlchemy
pypdf pypdf
pypdfium2 pypdfium2
Pillow # Pillow 13 fixes known image-processing advisories; keep local embeddings compatible.
Pillow>=13.0.0
faster-whisper faster-whisper
pdfplumber pdfplumber
beautifulsoup4 beautifulsoup4
@@ -25,7 +26,7 @@ numpy
chromadb-client chromadb-client
# gRPC vendors independent roots; 1.84.1 removes the incident trust anchors. # gRPC vendors independent roots; 1.84.1 removes the incident trust anchors.
grpcio>=1.84.1 grpcio>=1.84.1
fastembed fastembed>=0.9.1
youtube-transcript-api youtube-transcript-api
yt-dlp yt-dlp
# Markdown rendering for research reports (src/visual_report.py). # Markdown rendering for research reports (src/visual_report.py).
+34
View File
@@ -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<tag>[\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 <repo>:<tag>@sha256:<digest>, got {image!r}"
assert match.group("tag") != "latest", f"{name}: pin a release tag, not latest"