-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
230 lines (198 loc) · 11.8 KB
/
Copy pathDockerfile
File metadata and controls
230 lines (198 loc) · 11.8 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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# syntax=docker/dockerfile:1.24@sha256:87999aa3d42bdc6bea60565083ee17e86d1f3339802f543c0d03998580f9cb89
ARG VARIANT=slim
# ──────────────────────────────────────────────────────────────────────────────
# Stage 1: python-builder — compiles Python deps into a venv
# ──────────────────────────────────────────────────────────────────────────────
# Alpine 3.11 builder paired with Alpine 3.11 runtime — matching musl libc and
# CPython ABIs so the venv's symlinked interpreter resolves cleanly at runtime.
# regis requires python>=3.10 per pyproject.toml.
FROM python:3.14-alpine@sha256:003970a263347645cd23d4f90929ad16ba7ce7d808ee4674ffcc93cb21cc289f AS python-builder
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# uv binary from the official distroless image — builder stage only, never
# shipped in the runtime image.
COPY --from=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a /uv /usr/local/bin/uv
# build-base: gcc/musl-dev for any source-wheel fallback
# linux-headers, libffi-dev, openssl-dev: required by cffi/cryptography-style
# C extensions if PyPI has no musl wheel for the version we resolve.
# hadolint ignore=DL3018
RUN apk add --no-cache build-base linux-headers libffi-dev openssl-dev
# uv targets /opt/venv directly; UV_PYTHON pins the image's CPython so uv
# does not fetch a managed interpreter (the repo's .python-version pins 3.13
# for dev, but the image intentionally stays on the 3.11 runtime base).
ENV UV_PROJECT_ENVIRONMENT=/opt/venv \
UV_PYTHON=/usr/local/bin/python3
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /src
COPY pyproject.toml uv.lock ./
COPY regis/ regis/
# Core install only, pinned exactly to uv.lock — the same lock pip-audit
# scans in CI. --no-editable bakes the package into site-packages; --no-dev
# keeps the dev dependency group out of the runtime venv.
# The bytecode prune is defense-in-depth: uv doesn't compile .pyc by default,
# but a build-backend hook could still leave caches behind.
SHELL ["/bin/ash", "-o", "pipefail", "-c"]
RUN VERSION=$(awk -F'"' '/^version = / { print $2; exit }' pyproject.toml) && \
SETUPTOOLS_SCM_PRETEND_VERSION="$VERSION" uv sync --locked --no-dev --no-editable && \
find /opt/venv -type d -name __pycache__ -prune -exec rm -rf {} + && \
find /opt/venv -type f -name '*.pyc' -delete
# ──────────────────────────────────────────────────────────────────────────────
# Stage 3: tools-fetcher — downloads external analyzer binaries
# ──────────────────────────────────────────────────────────────────────────────
FROM curlimages/curl:8.20.0@sha256:b3f1fb2a51d923260350d21b8654bbc607164a987e2f7c84a0ac199a67df812a AS tools-fetcher
ARG TARGETARCH
ENV HADOLINT_VERSION=2.12.0 \
DOCKLE_VERSION=0.4.15 \
REGCTL_VERSION=0.11.5 \
GRYPE_VERSION=0.112.0 \
SYFT_VERSION=1.44.0 \
TRUFFLEHOG_VERSION=3.95.3
USER root
WORKDIR /tools
# grype (static binary)
RUN case "$TARGETARCH" in \
amd64) arch="amd64" ;; \
arm64) arch="arm64" ;; \
*) echo "Unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \
esac && \
curl -sSfL "https://github.com/anchore/grype/releases/download/v${GRYPE_VERSION}/grype_${GRYPE_VERSION}_linux_${arch}.tar.gz" \
-o /tmp/grype.tar.gz && \
tar -xzf /tmp/grype.tar.gz -C /tools grype && \
chmod +x /tools/grype && rm /tmp/grype.tar.gz
# syft (static binary)
RUN case "$TARGETARCH" in \
amd64) arch="amd64" ;; \
arm64) arch="arm64" ;; \
*) echo "Unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \
esac && \
curl -sSfL "https://github.com/anchore/syft/releases/download/v${SYFT_VERSION}/syft_${SYFT_VERSION}_linux_${arch}.tar.gz" \
-o /tmp/syft.tar.gz && \
tar -xzf /tmp/syft.tar.gz -C /tools syft && \
chmod +x /tools/syft && rm /tmp/syft.tar.gz
# trufflehog (static binary)
RUN case "$TARGETARCH" in \
amd64) arch="amd64" ;; \
arm64) arch="arm64" ;; \
*) echo "Unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \
esac && \
curl -sSfL "https://github.com/trufflesecurity/trufflehog/releases/download/v${TRUFFLEHOG_VERSION}/trufflehog_${TRUFFLEHOG_VERSION}_linux_${arch}.tar.gz" \
-o /tmp/trufflehog.tar.gz && \
tar -xzf /tmp/trufflehog.tar.gz -C /tools trufflehog && \
chmod +x /tools/trufflehog && rm /tmp/trufflehog.tar.gz
# Hadolint
RUN case "$TARGETARCH" in \
amd64) hadolint_arch="x86_64" ;; \
arm64) hadolint_arch="arm64" ;; \
*) echo "Unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \
esac && \
curl -sSfL "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-${hadolint_arch}" \
-o /tools/hadolint && \
chmod +x /tools/hadolint
# Dockle
RUN case "$TARGETARCH" in \
amd64) dockle_arch="64bit" ;; \
arm64) dockle_arch="ARM64" ;; \
*) echo "Unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \
esac && \
curl -sSfL "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-${dockle_arch}.tar.gz" \
-o /tmp/dockle.tar.gz && \
tar -xzf /tmp/dockle.tar.gz -C /tools dockle && \
chmod +x /tools/dockle && \
rm /tmp/dockle.tar.gz
# regctl (static binary; replaces skopeo for registry inspection)
RUN case "$TARGETARCH" in \
amd64|arm64) regctl_arch="$TARGETARCH" ;; \
*) echo "Unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \
esac && \
curl -sSfL "https://github.com/regclient/regclient/releases/download/v${REGCTL_VERSION}/regctl-linux-${regctl_arch}" \
-o /tools/regctl && \
chmod +x /tools/regctl
USER curl_user
# ──────────────────────────────────────────────────────────────────────────────
# Stage 4a: final-slim — minimal runtime with only regctl baked
# ──────────────────────────────────────────────────────────────────────────────
# Runtime base: python:3.11-alpine (round-3 task 14 — Alpine pivot).
# Alpine's ~50 MB base + musl libc beats both python:3.11-slim (~165 MB) and
# distroless (~80 MB but with libpython copy overhead) for this use case.
# PyYAML, MarkupSafe, and other C-extension deps have musl wheels on PyPI;
# the Anchore Go scanners are CGO-free and run cleanly on musl; hadolint
# (Haskell) needs Alpine's gcompat glibc shim in the full variant.
FROM python:3.14-alpine@sha256:003970a263347645cd23d4f90929ad16ba7ce7d808ee4674ffcc93cb21cc289f AS final-slim
LABEL org.opencontainers.image.title="regis" \
org.opencontainers.image.description="Regis — Slim variant (scanners lazy-loaded at first use)." \
org.opencontainers.image.url="https://github.com/trivoallan" \
org.opencontainers.image.source="https://github.com/trivoallan/regis" \
org.opencontainers.image.documentation="https://trivoallan.github.io/regis/" \
org.opencontainers.image.vendor="trivoallan" \
org.opencontainers.image.authors="trivoallan" \
org.opencontainers.image.licenses="MIT"
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/opt/venv/bin:/usr/local/bin:$PATH" \
PYTHONPATH=/opt/venv/lib/python3.11/site-packages \
REGIS_VARIANT=slim \
HOME=/home/regis
# ca-certificates for HTTPS to registries / GitHub releases (regis bootstrap
# tools / lazy ensure_tool fetcher uses urllib from stdlib, which honours
# /etc/ssl/certs).
# hadolint ignore=DL3018
RUN apk add --no-cache ca-certificates
# Non-root user (uid 1001) — matches the previous image's runtime identity so
# bind-mounts and CI cache permissions don't break.
RUN addgroup -g 1001 regis && \
adduser -D -u 1001 -G regis -h /home/regis regis
COPY --from=python-builder /opt/venv /opt/venv
COPY --from=tools-fetcher /tools/regctl /usr/local/bin/regctl
WORKDIR /home/regis
USER regis
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD ["regis", "list"]
ENTRYPOINT ["regis"]
CMD ["--help"]
# ──────────────────────────────────────────────────────────────────────────────
# Stage 4b: final-full — minimal runtime with all scanners baked
# ──────────────────────────────────────────────────────────────────────────────
FROM python:3.14-alpine@sha256:003970a263347645cd23d4f90929ad16ba7ce7d808ee4674ffcc93cb21cc289f AS final-full
LABEL org.opencontainers.image.title="regis" \
org.opencontainers.image.description="Regis — Full variant (all scanners baked)." \
org.opencontainers.image.url="https://github.com/trivoallan" \
org.opencontainers.image.source="https://github.com/trivoallan/regis" \
org.opencontainers.image.documentation="https://trivoallan.github.io/regis/" \
org.opencontainers.image.vendor="trivoallan" \
org.opencontainers.image.authors="trivoallan" \
org.opencontainers.image.licenses="MIT"
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/opt/venv/bin:/usr/local/bin:$PATH" \
PYTHONPATH=/opt/venv/lib/python3.11/site-packages \
REGIS_VARIANT=full \
HOME=/home/regis
# ca-certificates: HTTPS to registries.
# gcompat: glibc shim for Alpine — hadolint is a Haskell-compiled binary
# that depends on glibc's dynamic loader; gcompat provides the shim so it
# can run on musl. Adds ~500 KB but is required for hadolint to start.
# hadolint ignore=DL3018
RUN apk add --no-cache ca-certificates gcompat
RUN addgroup -g 1001 regis && \
adduser -D -u 1001 -G regis -h /home/regis regis
COPY --from=python-builder /opt/venv /opt/venv
COPY --from=tools-fetcher /tools/grype /usr/local/bin/grype
COPY --from=tools-fetcher /tools/syft /usr/local/bin/syft
COPY --from=tools-fetcher /tools/trufflehog /usr/local/bin/trufflehog
COPY --from=tools-fetcher /tools/hadolint /usr/local/bin/hadolint
COPY --from=tools-fetcher /tools/dockle /usr/local/bin/dockle
COPY --from=tools-fetcher /tools/regctl /usr/local/bin/regctl
WORKDIR /home/regis
USER regis
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD ["regis", "list"]
ENTRYPOINT ["regis"]
CMD ["--help"]
# ──────────────────────────────────────────────────────────────────────────────
# Final selector — picks final-slim or final-full based on VARIANT build-arg.
# DL3006/CKV_DOCKER_7 are suppressed: `final-${VARIANT}` resolves to a local
# build stage (final-slim or final-full above), not an external image, so the
# "pin the tag" advice does not apply.
# ──────────────────────────────────────────────────────────────────────────────
# trunk-ignore(checkov/CKV_DOCKER_7,hadolint/DL3006)
FROM final-${VARIANT} AS final