mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 14:07:55 +00:00
Pin all base images and ollama to fixed versions + @sha256 digests (no floating :latest), run Docker images as an unprivileged openjarvis user (uid 10001), replace the curl|bash NodeSource install with a digest-pinned multi-stage copy, install from the committed uv.lock via uv export --frozen --no-dev (hash-verified, --no-deps), and add systemd sandboxing (NoNewPrivileges, ProtectSystem=strict, PrivateTmp, kernel/SUID protections). Closes #228, #563, #564, #565, #566, #567.
61 lines
2.4 KiB
Docker
61 lines
2.4 KiB
Docker
# Base images are pinned to an immutable digest (in addition to a human-readable
|
|
# tag) so every build resolves the exact same layers — reproducible builds and
|
|
# safe rollbacks (#563).
|
|
|
|
# Stage 1: Build frontend SPA
|
|
FROM node:22.23.0-slim@sha256:d9f850096136edbc402debdd8729579a288aac64574ada0ff4db26b6ae58b0b2 AS frontend
|
|
|
|
WORKDIR /frontend
|
|
COPY frontend/package.json frontend/package-lock.json* ./
|
|
RUN npm ci --ignore-scripts 2>/dev/null || npm install
|
|
COPY frontend/ .
|
|
RUN npm run build
|
|
|
|
# Stage 2: Build Python package
|
|
FROM python:3.12.13-slim-bookworm@sha256:76d4b7b6305788c6b4c6a19d6a22a3921bf802e9af4d5e1e5bd771208dba74bf AS builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Install dependencies from the committed lockfile (#567). `uv export --frozen`
|
|
# reads uv.lock as-is (no re-resolution) and emits a fully pinned, hash-verified
|
|
# requirements set; `--no-deps` then installs exactly that set. This is a
|
|
# separate layer from the source copy so dependency installs stay cached when
|
|
# only application code changes.
|
|
COPY pyproject.toml uv.lock README.md ./
|
|
RUN pip install --no-cache-dir uv && \
|
|
uv export --frozen --no-dev --extra server --no-emit-project > requirements.txt && \
|
|
uv pip install --system --no-deps -r requirements.txt
|
|
|
|
# Copy the source and the non-src force-include paths (see pyproject
|
|
# [tool.hatch.build.targets.wheel.force-include]) before building the project.
|
|
COPY src/ src/
|
|
COPY scripts/install scripts/install
|
|
COPY deploy/windows deploy/windows
|
|
|
|
# Copy built frontend into the server static directory
|
|
COPY --from=frontend /src/openjarvis/server/static src/openjarvis/server/static/
|
|
|
|
# Install the project itself without re-resolving dependencies.
|
|
RUN uv pip install --system --no-deps .
|
|
|
|
# Stage 3: Runtime
|
|
FROM python:3.12.13-slim-bookworm@sha256:76d4b7b6305788c6b4c6a19d6a22a3921bf802e9af4d5e1e5bd771208dba74bf
|
|
|
|
COPY --from=builder /usr/local /usr/local
|
|
COPY --from=builder /app /app
|
|
WORKDIR /app
|
|
|
|
# Run as an unprivileged user — the server needs no root privileges, so dropping
|
|
# them limits the blast radius of a compromise (#565). The app writes only to
|
|
# $HOME (config/cache/state), which is owned by this user.
|
|
RUN groupadd --system --gid 10001 openjarvis && \
|
|
useradd --system --uid 10001 --gid openjarvis \
|
|
--create-home --home-dir /home/openjarvis openjarvis
|
|
ENV HOME=/home/openjarvis
|
|
USER openjarvis
|
|
|
|
EXPOSE 8000
|
|
|
|
ENTRYPOINT ["jarvis"]
|
|
CMD ["serve", "--host", "0.0.0.0", "--port", "8000"]
|