Files
ThothII/docker/core.Dockerfile
T
Codex 82e2c91f42
Publish documentation / publish (push) Successful in 1m27s
feat: implement memory and evidence administration with guided repairs
Add PostgreSQL-backed memory, editable evidence with source review and activation, and human-approved archive repairs across the harness, API, and UI. Include migrations, deployment support, regression coverage, and validation documentation.

Refresh permissions from validated session roles so existing administrator logins can access newly deployed archive management features.
2026-09-10 10:31:34 +02:00

146 lines
7.7 KiB
Docker

# syntax=docker/dockerfile:1.7
# thothii-core: Fastify (Node 24.16) + harness Python 3.12 (tht CLI) + runtime Pi.
# Singolo container, entrypoint logico "server" (default).
ARG PI_VERSION=0.80.3
ARG IMAGE_VERSION=local
# ---- Pinned Node source for the runtime binary and npm ----
FROM node:24.16.0-bookworm@sha256:40ad9f3064e67d6860b4bc3fe1880b2953934fd6320ada990e45fe0efa6badd7 AS node-runtime
# ---- Pinned native storage helper used by the authenticated backend ----
FROM golang:1.26.5-bookworm@sha256:1ecb7edf62a0408027bd5729dfd6b1b8766e578e8df93995b225dfd0944eb651 AS tht-auth-storage-build
WORKDIR /src/tools/tht
COPY tools/tht/go.mod tools/tht/go.sum ./
RUN go mod download
COPY tools/tht ./
RUN CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o /out/tht-auth-storage ./cmd/tht
# ---- Stage 0: locked Pi runtime ----
FROM node:24.16.0-bookworm@sha256:40ad9f3064e67d6860b4bc3fe1880b2953934fd6320ada990e45fe0efa6badd7 AS pi-runtime-build
ARG PI_VERSION
ARG PI_RUNTIME_PACKAGE_VERSION
ARG PI_PACKAGE_NAME=@earendil-works/pi-coding-agent
WORKDIR /opt/pi-runtime
COPY docker/pi-runtime/package.json docker/pi-runtime/package-lock.json ./
RUN if [ -n "$PI_RUNTIME_PACKAGE_VERSION" ]; then \
node -e 'const fs=require("node:fs"); const [name,version]=process.argv.slice(1); const manifest=JSON.parse(fs.readFileSync("package.json","utf8")); manifest.dependencies[name]=version; fs.writeFileSync("package.json",JSON.stringify(manifest,null,2)+"\\n");' "$PI_PACKAGE_NAME" "$PI_RUNTIME_PACKAGE_VERSION"; \
npm install --package-lock-only --ignore-scripts --omit=dev "$PI_PACKAGE_NAME@$PI_RUNTIME_PACKAGE_VERSION"; \
fi \
&& npm ci --omit=dev \
&& test "$(./node_modules/.bin/pi --version)" = "$PI_VERSION"
# ---- Stage 1: backend TypeScript -> dist ----
FROM node:24.16.0-bookworm@sha256:40ad9f3064e67d6860b4bc3fe1880b2953934fd6320ada990e45fe0efa6badd7 AS backend-build
WORKDIR /src/backend
COPY backend/package*.json ./
RUN npm ci
COPY backend/ ./
RUN npm run build
# ---- Stage 2: runtime (Python 3.12 nativo + Node 24.16 copiato, stesso glibc bookworm) ----
FROM python:3.12-slim-bookworm@sha256:d50fb7611f86d04a3b0471b46d7557818d88983fc3136726336b2a4c657aa30b AS runtime
ARG PI_VERSION
ARG IMAGE_VERSION
ARG INSTALL_SENSITIVITY_NER=false
LABEL org.opencontainers.image.title="thothii-core" \
org.opencontainers.image.version="${IMAGE_VERSION}" \
org.opencontainers.image.description="ThothII core with its embedded Pi runtime" \
io.thothii.pi.version="${PI_VERSION}"
# Runtime tools
RUN set -eux; \
runtime_packages="curl ca-certificates ripgrep fd-find tini git openssh-client libseccomp2"; \
if ! command -v flock >/dev/null 2>&1; then \
runtime_packages="$runtime_packages util-linux"; \
fi; \
apt-get update; \
apt-get install -y --no-install-recommends $runtime_packages; \
rm -rf /var/lib/apt/lists/*; \
command -v flock >/dev/null 2>&1; \
ln -s /usr/bin/fdfind /usr/local/bin/fd
# Node 24.16 + npm copiati dall'immagine ufficiale (stesso Debian bookworm → binario compatibile)
COPY --from=node-runtime /usr/local/bin/node /usr/local/bin/node
COPY --from=node-runtime /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
# Utente non-root
RUN useradd --create-home --uid 10001 --shell /bin/bash thoth
# Docker copies these owned directories into newly-created named volumes, allowing the non-root
# runtime user to create application settings, sessions, registry snapshots, state, and locks.
RUN mkdir -p /home/thoth/.pi/agent /data/settings /data/sessions /data/workspace-registry /data/workspace-secrets \
/data/auth/sessions /data/auth/oidc \
&& chown -R thoth:thoth /home/thoth/.pi /data \
&& chmod 0700 /data/auth /data/auth/sessions /data/auth/oidc
COPY harness/ /app/harness/
# Pi scrive lock/settings in .pi: ownership thoth per sopravvivere al rebuild
RUN chown -R thoth:thoth /app/harness/.pi
# Harness: venv nativo (python 3.12) + tht installato (non-editable).
# tht carica workflow.yaml module-relative (Path(__file__).parent.parent); con il package
# in site-packages quel path non contiene workflow.yaml -> lo copiamo dopo l'install.
# (pip install -e non funziona: pip non riconosce /app/harness come editable req.)
# psycopg2-binary è wheel → niente gcc/libpq-dev.
RUN python -m venv /opt/venv \
&& /opt/venv/bin/pip install --no-cache-dir --upgrade pip \
&& (cd /app/harness && /opt/venv/bin/pip install --no-cache-dir .) \
&& cp /app/harness/workflow.yaml /opt/venv/lib/python3.12/site-packages/workflow.yaml
# Il workspace locale predefinito converge sul file canonico. Il CLI onora anche THT_CONFIG,
# quindi cambiare CWD non cambia l'identita' dello workspace.
RUN mkdir -p /app/harness/config \
&& cp --remove-destination /app/harness/workspaces/local.yaml /app/harness/config/tht.yaml
# PiProcessManager (backend) prepende harnessDir/.venv/bin al PATH del child Pi → symlink al venv reale
RUN ln -s /opt/venv /app/harness/.venv
# The optional NER dependency layer is independent of backend source and build artifacts so it can
# be reused when only TypeScript or worker code changes.
COPY backend/python/sensitivity-ner-requirements.txt /app/backend/python/sensitivity-ner-requirements.txt
RUN if [ "$INSTALL_SENSITIVITY_NER" = "true" ]; then \
python -m venv /opt/sensitivity-ner; \
/opt/sensitivity-ner/bin/pip install --no-cache-dir --upgrade pip; \
/opt/sensitivity-ner/bin/pip install --no-cache-dir -r /app/backend/python/sensitivity-ner-requirements.txt; \
elif [ "$INSTALL_SENSITIVITY_NER" != "false" ]; then \
echo "INSTALL_SENSITIVITY_NER must be true or false" >&2; exit 2; \
fi
# Backend: dist + node_modules (stesso Node major 24 + glibc bookworm → compatibili)
COPY --from=backend-build /src/backend/dist /app/backend/dist
COPY --from=backend-build /src/backend/node_modules /app/backend/node_modules
COPY backend/scripts/ssh-askpass.mjs /app/backend/scripts/ssh-askpass.mjs
COPY backend/python /app/backend/python
COPY backend/package*.json /app/backend/
RUN chmod 0755 /app/backend/scripts/ssh-askpass.mjs
# Runtime Pi is installed only from the committed lockfile. The image exposes its immutable
# executable directly, so no host Pi installation or writable global npm directory is needed.
COPY --from=pi-runtime-build /opt/pi-runtime/node_modules /opt/pi-runtime/node_modules
COPY --from=tht-auth-storage-build /out/tht-auth-storage /usr/local/bin/tht-auth-storage
RUN ln -s /opt/pi-runtime/node_modules/.bin/pi /usr/local/bin/pi \
&& test "$(pi --version)" = "$PI_VERSION" \
&& test -x /usr/local/bin/tht-auth-storage
ENV PATH="/opt/venv/bin:/usr/local/bin:$PATH" \
PI_VERSION="${PI_VERSION}" \
HOST=0.0.0.0 PORT=8787 \
THT_HARNESS_DIR=/app/harness \
THT_BIN=/opt/venv/bin/tht \
THT_AUTH_STORAGE_BIN=/usr/local/bin/tht-auth-storage \
PI_BIN=pi \
HOME=/home/thoth
COPY scripts/verify-line-endings.sh /usr/local/bin/verify-line-endings
COPY docker/core-entrypoint.sh docker/workspace-maintenance-entrypoint.sh docker/session-migrate.sh docker/catalog-migrate.sh docker/ensure-pi-trust.mjs docker/embedding-model-init.sh /app/docker/
COPY docker/smoke/core-smoke.sh /app/docker/smoke/core-smoke.sh
RUN /usr/local/bin/verify-line-endings /app/docker \
&& chmod +x /app/docker/core-entrypoint.sh /app/docker/workspace-maintenance-entrypoint.sh /app/docker/session-migrate.sh /app/docker/embedding-model-init.sh /app/docker/smoke/core-smoke.sh
WORKDIR /app/backend
USER thoth
EXPOSE 8787
HEALTHCHECK --interval=15s --timeout=3s --retries=5 --start-period=30s \
CMD curl -fsS http://127.0.0.1:8787/health || exit 1
ENTRYPOINT ["/usr/bin/tini","--","/app/docker/core-entrypoint.sh"]
CMD ["server"]