mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-30 09:42:21 +01:00
* fix(docker): require the patched Debian Brotli decoder Refresh the signed Debian native Brotli package in a shared build-stage base and fail builds below the security backport floor. Verify the actual selected library, native fix marker, valid decoding, and distro Node linkage before accepting the runtime. * fix(docker): guard HTTPS trust and accept Bookworm Brotli Check the inherited system CA store before the shared base makes its first HTTPS package request. Accept the exact fixed Debian 12 marker alongside Debian 13 while retaining package floors, decoder ownership, and valid decoding controls. * fix(docker): preserve Brotli gate diagnostics
174 lines
8.5 KiB
Docker
174 lines
8.5 KiB
Docker
# Both stages need the fixed native decoder, including curl in the builder and
|
|
# distro Node in the runtime. A cached Python base may predate the Debian fix.
|
|
FROM python:3.14.9-slim AS brotli-base
|
|
COPY scripts/check_brotli.py /usr/local/bin/check-brotli.py
|
|
COPY scripts/check_ca_trust.py /usr/local/bin/check-ca-trust.py
|
|
# Check inherited trust before the first HTTPS package request, retaining Debian's
|
|
# signed archive verification. Refresh only the explicit native dependency.
|
|
RUN python /usr/local/bin/check-ca-trust.py --system \
|
|
&& sed -i 's|http://deb.debian.org/|https://deb.debian.org/|g' /etc/apt/sources.list.d/debian.sources \
|
|
&& apt-get update && apt-get install -y --no-install-recommends libbrotli1 \
|
|
&& python /usr/local/bin/check-brotli.py \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# ---- builder: patch + build wheels for Real-ESRGAN's broken-on-3.14 deps ----
|
|
# basicsr/gfpgan/facexlib read their version via exec()+locals()['__version__'],
|
|
# which raises KeyError on Python 3.13+ (PEP 667). Build patched wheels here so
|
|
# the final image / Cookbook never has to compile the broken sdists. See
|
|
# docker/build-realesrgan-wheels.sh for the full rationale.
|
|
FROM brotli-base AS realesrgan-wheels
|
|
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
COPY scripts/check_ca_trust.py /usr/local/bin/check-ca-trust.py
|
|
RUN python /usr/local/bin/check-ca-trust.py --system
|
|
COPY requirements-bootstrap.txt /tmp/requirements-bootstrap.txt
|
|
RUN python -m pip install --no-cache-dir --require-hashes --only-binary=:all: --no-deps -r /tmp/requirements-bootstrap.txt \
|
|
&& python /usr/local/bin/check-ca-trust.py --python
|
|
COPY docker/build-realesrgan-wheels.sh /usr/local/bin/build-realesrgan-wheels.sh
|
|
RUN bash /usr/local/bin/build-realesrgan-wheels.sh /wheels
|
|
|
|
FROM brotli-base
|
|
|
|
# System deps. tmux is required by Cookbook for background downloads/serves.
|
|
# openssh-client is required for Cookbook remote server tests, setup, probes,
|
|
# downloads, and serves from Docker installs.
|
|
# git/cmake are required when Cookbook builds llama.cpp on first llama.cpp
|
|
# launch inside Docker.
|
|
# nodejs/npm provide npx for the built-in Browser MCP server.
|
|
# chromium provides the actual browser binary used by that MCP server.
|
|
# fontconfig + Noto CJK provide real fallback glyphs for multilingual pages;
|
|
# Chromium otherwise renders Chinese/Japanese/Korean labels as empty boxes.
|
|
# iproute2/iputils-ping/net-tools/dnsutils/nmap give Docker-hosted agents the
|
|
# basic network inspection toolkit expected by local LAN/debugging tasks.
|
|
# gosu lets the entrypoint drop privileges cleanly so signals still reach
|
|
# uvicorn directly (no extra shell layer like `su`/`sudo` would add).
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
cmake \
|
|
curl \
|
|
ca-certificates \
|
|
git \
|
|
nodejs \
|
|
npm \
|
|
chromium \
|
|
fontconfig \
|
|
fonts-noto-cjk \
|
|
tmux \
|
|
openssh-client \
|
|
iproute2 \
|
|
iputils-ping \
|
|
net-tools \
|
|
dnsutils \
|
|
nmap \
|
|
gosu \
|
|
libgl1 \
|
|
libglib2.0-0t64 \
|
|
libxcb1 \
|
|
libmagic1 \
|
|
&& python /usr/local/bin/check-brotli.py --node /usr/bin/node \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Refresh both Python trust bundles before installing application dependencies.
|
|
# System roots also serve web fetches, webhooks, curl, and Node's OpenSSL mode.
|
|
COPY scripts/check_ca_trust.py /usr/local/bin/check-ca-trust.py
|
|
RUN python /usr/local/bin/check-ca-trust.py --system
|
|
COPY requirements-bootstrap.txt /tmp/requirements-bootstrap.txt
|
|
RUN python -m pip install --no-cache-dir --require-hashes --only-binary=:all: --no-deps -r /tmp/requirements-bootstrap.txt \
|
|
&& python /usr/local/bin/check-ca-trust.py --python
|
|
ENV NODE_OPTIONS=--use-openssl-ca \
|
|
GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt
|
|
|
|
# Chromium has a separate root store. Distrust the compromised intermediate
|
|
# public keys explicitly, including cross-signs, without waiting for CRL updates.
|
|
COPY docker/chromium-emudhra.json /etc/chromium/policies/managed/odysseus-emudhra.json
|
|
|
|
# Private browser automation wrapper used by the native `private_browser` tool.
|
|
# Chromium is installed above, so agent-browser can drive the existing browser
|
|
# binary without paying `npx` startup/install overhead on each tool call.
|
|
RUN npm install -g agent-browser@0.35.0 --omit=dev --loglevel=error
|
|
|
|
# libgl1/libglib2.0-0t64/libxcb1 are runtime shared libs (libGL.so.1,
|
|
# libglib-2.0/libgthread, libxcb.so.1) that opencv-python (cv2) loads. The
|
|
# slim base omits them, so the Cookbook "install realesrgan" path imports cv2
|
|
# and dies with `libxcb.so.1: cannot open shared object file` despite a clean
|
|
# pip install. Using full opencv-python (not -headless) because basicsr/gfpgan/
|
|
# facexlib/realesrgan all depend on the `opencv-python` distribution by name.
|
|
#
|
|
# libmagic1 is the shared lib (libmagic.so.1) that python-magic dlopens for
|
|
# content-based MIME sniffing in src/upload_handler.py. We install both here
|
|
# (libmagic1 + the python-magic wrapper, below) rather than in requirements.txt
|
|
# because python-magic resolves libmagic at import time: where the lib is
|
|
# absent the import can block or raise, so keeping it image-only avoids
|
|
# regressing pip/venv installs on hosts without libmagic. Debian always has the
|
|
# lib here, so the import is instant and detection actually works.
|
|
|
|
# Docker CLI (client only — daemon stays on the host via the
|
|
# /var/run/docker.sock mount). The Debian `docker.io` package ships
|
|
# dockerd but not the client binary on slim, so grab the static client
|
|
# tarball from download.docker.com instead.
|
|
# 29.9.2 includes Go 1.26.10's eMudhra intermediate-key distrust.
|
|
ARG DOCKER_CLI_VERSION=29.9.2
|
|
RUN ARCH="$(dpkg --print-architecture)" \
|
|
&& case "$ARCH" in \
|
|
amd64) DARCH=x86_64 ;; \
|
|
arm64) DARCH=aarch64 ;; \
|
|
*) echo "unsupported arch $ARCH"; exit 1 ;; \
|
|
esac \
|
|
&& curl -fsSL "https://download.docker.com/linux/static/stable/${DARCH}/docker-${DOCKER_CLI_VERSION}.tgz" \
|
|
-o /tmp/docker.tgz \
|
|
&& tar -xzf /tmp/docker.tgz -C /tmp \
|
|
&& install -m 0755 /tmp/docker/docker /usr/local/bin/docker \
|
|
&& rm -rf /tmp/docker /tmp/docker.tgz
|
|
|
|
WORKDIR /app
|
|
|
|
# Install Python deps first (layer cache). Optional extras (PyMuPDF AGPL, etc.)
|
|
# are opt-in so the default image stays MIT-core; see requirements-optional.txt.
|
|
ARG INSTALL_OPTIONAL=false
|
|
COPY requirements.txt requirements-optional.txt ./
|
|
RUN pip install --no-cache-dir -r requirements.txt \
|
|
&& if [ "$INSTALL_OPTIONAL" = "true" ]; then pip install --no-cache-dir -r requirements-optional.txt; fi
|
|
|
|
# python-magic powers content-based MIME sniffing in src/upload_handler.py.
|
|
# Image-only (not in requirements.txt) because it needs the libmagic1 system
|
|
# lib installed above; see the apt note near the top of this stage.
|
|
RUN pip install --no-cache-dir python-magic==0.4.27
|
|
|
|
# Pre-install the patched basicsr/gfpgan/facexlib wheels built in the
|
|
# realesrgan-wheels stage (--no-deps keeps the image lean — torch & friends are
|
|
# pulled only when realesrgan is actually installed). With these dists already
|
|
# satisfied, the Cookbook's plain `pip install realesrgan` resolves them from
|
|
# wheels instead of rebuilding the sdists that fail on Python 3.14.
|
|
COPY --from=realesrgan-wheels /wheels/ /tmp/odysseus-wheels/
|
|
RUN pip install --no-cache-dir --no-deps /tmp/odysseus-wheels/*.whl \
|
|
&& rm -rf /tmp/odysseus-wheels
|
|
|
|
# Check gRPC's effective defaults after all Python dependencies are installed.
|
|
# The application minimum fixes its bundled roots; the checked override also
|
|
# keeps the effective Docker selection consistent with system trust.
|
|
RUN python /usr/local/bin/check-ca-trust.py --system --python --grpc \
|
|
&& python /usr/local/bin/check-brotli.py --node /usr/bin/node
|
|
|
|
# Copy app code
|
|
COPY . .
|
|
# Require the redistribution notices in the image build context.
|
|
COPY licenses/ ./licenses/
|
|
COPY THIRD_PARTY_PROVENANCE.json ACKNOWLEDGMENTS.md ./
|
|
|
|
# Create data directory (mount a volume here for persistence)
|
|
RUN mkdir -p data logs services/cache/search
|
|
|
|
# Entrypoint that drops to PUID/PGID (default 1000:1000) and repairs
|
|
# ownership on the bind-mounted /app/data and /app/logs. Without this,
|
|
# the container runs as root and writes root-owned files into host
|
|
# bind mounts — any later non-root run (or a host user trying to
|
|
# update them) silently fails on EPERM, breaking skill extraction,
|
|
# prefs persistence, mail attachments, etc.
|
|
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
|
|
|
EXPOSE 7000
|
|
|
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
|
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7000"]
|