FROM python:3.12-alpine3.23@sha256:31a768b01976652c222e318fe5bd6e7c252f056cbf489c88fa256f1bf0af58e3 ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 # PostgreSQL 17 client tools. ModelForge owns its own consistent logical backup and restore and # must never fall back to copying a live data directory, so pg_dump/pg_restore/psql ship with the # control plane and are pinned to the same major version as the server. Upgrade the signed Alpine # repository packages during the build so a digest-pinned base does not retain already-fixed CVEs. ARG POSTGRES_MAJOR=17 RUN set -eux; \ apk upgrade --no-cache; \ apk add --no-cache ca-certificates "postgresql${POSTGRES_MAJOR}-client" # Build identity. These are stamped in at build time so a running container can say exactly # where it came from; an argument that is never passed stays empty and is reported as null # rather than becoming a claimed commit. ARG MODELFORGE_VERSION=0.0.0 ARG MODELFORGE_COMMIT="" ARG MODELFORGE_BUILT_AT="" ENV MODELFORGE_BUILD_COMMIT=${MODELFORGE_COMMIT} ENV MODELFORGE_BUILD_TIMESTAMP=${MODELFORGE_BUILT_AT} LABEL org.opencontainers.image.title="ITWorx ModelForge control plane" LABEL org.opencontainers.image.description="Capability-first local AI ModelOps and GPU control plane" LABEL org.opencontainers.image.version="${MODELFORGE_VERSION}" LABEL org.opencontainers.image.revision="${MODELFORGE_COMMIT}" LABEL org.opencontainers.image.created="${MODELFORGE_BUILT_AT}" LABEL org.opencontainers.image.source="https://git.example.com/example/modelforge.git" LABEL org.opencontainers.image.vendor="ITWorx" LABEL org.opencontainers.image.licenses="AGPL-3.0-or-later" WORKDIR /app COPY pyproject.toml ./ COPY src ./src COPY alembic.ini ./ COPY alembic ./alembic # Upgrade the installer before it resolves anything: the pinned base image ships a pip # carrying archive-extraction advisories. pip never runs at runtime, but a release image # should not carry a known-vulnerable installer. RUN pip install --no-cache-dir --upgrade pip "setuptools>=78.1.1" "msgpack>=1.2.1" \ && pip install --no-cache-dir . \ && pip check \ && python -m pip uninstall --yes pip setuptools RUN addgroup -S modelforge && adduser -S -G modelforge -h /app modelforge \ && mkdir -p /data/state /data/hf-cache /data/artifacts /data/quarantine \ /data/backups /data/restore \ && chown -R modelforge:modelforge /app /data USER modelforge EXPOSE 8000 CMD ["uvicorn", "modelforge_api.main:app", "--host", "0.0.0.0", "--port", "8000"]