-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDockerfile
More file actions
95 lines (85 loc) · 5.15 KB
/
Copy pathDockerfile
File metadata and controls
95 lines (85 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Evidentia container image — multi-stage: python:3.13-slim builder ->
# dhi.io/python:3.13 (Docker Hardened Images) distroless runtime.
#
# The runtime is shell-free, curl-free, gpg-free and runs as nonroot uid 65532.
# Air-gap evidence signing uses the binary-free DSSE path (evidentia_core.oscal
# .keysign); Sigstore is online-only; the gpg-EMIT code path fails closed
# (GPGNotAvailableError) since no gpg binary is present. Honest framing: the win
# is post-exploitation attack-surface reduction + a green fixable-rescan gate,
# NOT raw CVE-count.
#
# INSTALL_SOURCE selects the install path (pypi default / local for release.yml);
# see docs/dockerfile-pinning.md. BuildKit only builds stages in the final
# image's graph, so the pypi path never evaluates docker/wheels/.
ARG INSTALL_SOURCE=pypi
# ---- base-builder: slim + venv + install toolchain (has a shell) ------------
FROM python:3.13-slim@sha256:eb43ff125d8d58d7449dcba7d336c23bcac412f526d861db493b9994d8010280 AS base-builder
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PYTHONDONTWRITEBYTECODE=1
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:${PATH}"
# Output-dir skeleton COPYed into the distroless runtime (an EMPTY dir does not
# survive COPY, so each carries a .keep placeholder).
RUN mkdir -p /build/home/.evidentia /build/home/evidence /build/home/reports /build/home/risks \
&& touch /build/home/.evidentia/.keep /build/home/evidence/.keep \
/build/home/reports/.keep /build/home/risks/.keep
# ---- deps-pypi (DEFAULT): hash-pinned install from PyPI ----------------------
FROM base-builder AS deps-pypi
COPY docker/requirements.txt /tmp/requirements.txt
RUN /opt/venv/bin/pip install --no-cache-dir --require-hashes -r /tmp/requirements.txt
# ---- deps-local: hash-pinned install from locally-built wheels ---------------
FROM base-builder AS deps-local
COPY docker/requirements.txt /tmp/requirements.txt
COPY docker/wheels/ /tmp/wheels/
RUN /opt/venv/bin/pip install --no-cache-dir --require-hashes --find-links /tmp/wheels -r /tmp/requirements.txt
# ---- venv-fix: repoint the venv at DHI's interpreter (/usr/bin) --------------
# DHI ships python at /usr/bin/python with the stdlib at /usr/lib/python3.13
# (NOT the slim /usr/local/bin/python). LAYOUT CHANGE (2026-07): DHI bases
# built through June 2026 carried python under /opt/python/bin; the current
# digests (observed 1842a6b9…, built 2026-07-08) moved it to the standard
# system paths and /opt/python no longer exists — CI-probe-verified via a
# rootfs listing on this exact pinned digest, after the build-time validation
# below failed with `exec /opt/venv/bin/evidentia: no such file or directory`
# (a shebang pointing at the vanished interpreter). Console-script shebangs
# reference /opt/venv/bin/python (the venv symlink), so repointing that
# symlink + pyvenv.cfg is sufficient.
FROM deps-${INSTALL_SOURCE} AS venv-fix
RUN set -eux; \
rm -f /opt/venv/bin/python /opt/venv/bin/python3 /opt/venv/bin/python3.13; \
ln -s /usr/bin/python /opt/venv/bin/python; \
ln -s /usr/bin/python /opt/venv/bin/python3; \
ln -s /usr/bin/python /opt/venv/bin/python3.13; \
sed -i \
-e 's|^home = .*|home = /usr/bin|' \
-e 's|^executable = .*|executable = /usr/bin/python|' \
-e 's|^base-prefix = .*|base-prefix = /usr|' \
-e 's|^base-exec-prefix = .*|base-exec-prefix = /usr|' \
-e 's|^base-executable = .*|base-executable = /usr/bin/python|' \
/opt/venv/pyvenv.cfg
# ---- final: distroless DHI runtime, nonroot uid 65532 -----------------------
FROM dhi.io/python:3.13@sha256:1842a6b9ce76177a8df5b5c9dbde6e0be15bfc317055d66b340ae5d8eada6470 AS final
COPY --from=venv-fix --chown=65532:65532 /opt/venv /opt/venv
COPY --from=venv-fix --chown=65532:65532 /build/home/ /home/nonroot/
ENV PATH="/opt/venv/bin:${PATH}" \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /home/nonroot
USER 65532
# Build-time validation — EXEC-FORM (no /bin/sh on distroless).
RUN ["/opt/venv/bin/evidentia", "version"]
EXPOSE 8000
# Python healthcheck (no curl on distroless). Must hit /api/health (NOT /health —
# a bare /health falls through to the SPA fallback and 200s falsely; regression
# test: tests/integration/test_api/test_basic_endpoints.py::TestHealth).
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD ["python", "-c", "import sys,urllib.request; sys.exit(0 if urllib.request.urlopen('http://localhost:8000/api/health', timeout=5).status == 200 else 1)"]
ENTRYPOINT ["/opt/venv/bin/evidentia"]
CMD ["serve", "--host", "0.0.0.0", "--port", "8000"]
LABEL org.opencontainers.image.title="Evidentia"
LABEL org.opencontainers.image.description="Open-source GRC infrastructure: OSCAL-native gap analysis, AI risk-statement generation, Sigstore-signed evidence. 82 frameworks bundled."
LABEL org.opencontainers.image.source="https://github.com/polycentric-labs/evidentia"
LABEL org.opencontainers.image.url="https://github.com/polycentric-labs/evidentia"
LABEL org.opencontainers.image.documentation="https://github.com/polycentric-labs/evidentia/blob/main/README.md"
LABEL org.opencontainers.image.licenses="Apache-2.0"
LABEL org.opencontainers.image.vendor="polycentric-labs"