forked from sbomify/sbomify
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
307 lines (253 loc) · 12.3 KB
/
Dockerfile
File metadata and controls
307 lines (253 loc) · 12.3 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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# Base Python version
ARG PYTHON_VERSION=3.13-slim-trixie@sha256:1f3781f578e17958f55ada96c0a827bf279a11e10d6a458ecb8bde667afbb669
ARG BUILD_ENV=production # Default to production
ARG OSV_SCANNER_VERSION=v2.0.2
# Build metadata arguments (passed from CI/CD)
ARG BUILD_DATE=""
ARG GIT_COMMIT=""
ARG GIT_COMMIT_SHORT=""
ARG GIT_REF=""
ARG VERSION=""
ARG BUILD_TYPE=""
### Stage 0: Keycloak Theme Build (Fully Independent)
FROM oven/bun:1.3-debian@sha256:3da1c52799fc527af4c5969876734cbaddbf3e49479c601cfebdb0d7cbcc61b4 AS keycloak-build
WORKDIR /keycloak-build
# Copy Keycloak-specific files only
COPY keycloak/package.json ./
COPY keycloak/bun.lock* ./
COPY keycloak/tailwind.config.ts ./
COPY keycloak/themes/ ./themes/
# Install Keycloak dependencies and build
RUN bun install --frozen-lockfile && bun run build
### Stage 1: Bun JS build for Production Frontend Assets
FROM oven/bun:1.3-debian@sha256:b5cf5ca5dc3e2a02d805802ba089401c4beabf597daabbf35a17b8e82dc2f7bc AS js-build-prod
WORKDIR /js-build
# Copy all frontend configuration files first
COPY package.json ./
COPY bun.lock ./
COPY tsconfig*.json ./
COPY vite.config.ts ./
COPY tailwind.config.js ./
COPY postcss.config.js ./
COPY eslint.config.js ./
COPY .prettierrc.js ./
# Install dependencies
RUN bun install --frozen-lockfile --production
# Copy JS source files
COPY sbomify/apps/core/js/ ./sbomify/apps/core/js/
COPY sbomify/apps/sboms/js/ ./sbomify/apps/sboms/js/
COPY sbomify/apps/teams/js/ ./sbomify/apps/teams/js/
COPY sbomify/apps/billing/js/ ./sbomify/apps/billing/js/
COPY sbomify/apps/documents/js/ ./sbomify/apps/documents/js/
COPY sbomify/apps/vulnerability_scanning/js/ ./sbomify/apps/vulnerability_scanning/js/
COPY sbomify/apps/plugins/js/ ./sbomify/apps/plugins/js/
# Copy templates for Tailwind CSS content scanning (@source directives)
COPY sbomify/apps/core/templates/ ./sbomify/apps/core/templates/
COPY sbomify/apps/sboms/templates/ ./sbomify/apps/sboms/templates/
COPY sbomify/apps/teams/templates/ ./sbomify/apps/teams/templates/
COPY sbomify/apps/billing/templates/ ./sbomify/apps/billing/templates/
COPY sbomify/apps/documents/templates/ ./sbomify/apps/documents/templates/
COPY sbomify/apps/vulnerability_scanning/templates/ ./sbomify/apps/vulnerability_scanning/templates/
COPY sbomify/apps/plugins/templates/ ./sbomify/apps/plugins/templates/
COPY sbomify/apps/onboarding/templates/ ./sbomify/apps/onboarding/templates/
COPY sbomify/templates/ ./sbomify/templates/
# Copy existing static files
COPY sbomify/static/ ./sbomify/static/
# Copy assets (includes Tailwind source CSS)
COPY sbomify/assets/ ./sbomify/assets/
# Create additional directories for build scripts
RUN mkdir -p sbomify/static/css sbomify/static/webfonts sbomify/static/dist
# Build main frontend assets (Keycloak is built separately in Stage 0)
RUN bun run copy-deps && bun x vite build
### Stage 2: Frontend Development Server
FROM oven/bun:1.3-debian@sha256:b5cf5ca5dc3e2a02d805802ba089401c4beabf597daabbf35a17b8e82dc2f7bc AS frontend-dev-server
WORKDIR /app-frontend
# Copy frontend configuration and source
COPY package.json ./
COPY bun.lock ./
COPY tsconfig*.json ./
COPY vite.config.ts ./
COPY tailwind.config.js ./
COPY postcss.config.js ./
COPY eslint.config.js ./
COPY .prettierrc.js ./
# Install dependencies (before source files for better Docker layer caching)
RUN bun install --frozen-lockfile
# Copy JS source files
COPY sbomify/apps/core/js/ ./sbomify/apps/core/js/
COPY sbomify/apps/sboms/js/ ./sbomify/apps/sboms/js/
COPY sbomify/apps/teams/js/ ./sbomify/apps/teams/js/
COPY sbomify/apps/billing/js/ ./sbomify/apps/billing/js/
COPY sbomify/apps/documents/js/ ./sbomify/apps/documents/js/
COPY sbomify/apps/vulnerability_scanning/js/ ./sbomify/apps/vulnerability_scanning/js/
COPY sbomify/apps/plugins/js/ ./sbomify/apps/plugins/js/
# Copy templates for Tailwind CSS content scanning (@source directives)
COPY sbomify/apps/core/templates/ ./sbomify/apps/core/templates/
COPY sbomify/apps/sboms/templates/ ./sbomify/apps/sboms/templates/
COPY sbomify/apps/teams/templates/ ./sbomify/apps/teams/templates/
COPY sbomify/apps/billing/templates/ ./sbomify/apps/billing/templates/
COPY sbomify/apps/documents/templates/ ./sbomify/apps/documents/templates/
COPY sbomify/apps/vulnerability_scanning/templates/ ./sbomify/apps/vulnerability_scanning/templates/
COPY sbomify/apps/plugins/templates/ ./sbomify/apps/plugins/templates/
COPY sbomify/apps/onboarding/templates/ ./sbomify/apps/onboarding/templates/
COPY sbomify/templates/ ./sbomify/templates/
# Copy static files (needed for Tailwind CSS source)
COPY sbomify/static/ ./sbomify/static/
# Copy assets (includes Tailwind source CSS)
COPY sbomify/assets/ ./sbomify/assets/
# Expose Vite dev server port
EXPOSE 5170
# Command to run Vite dev server
CMD ["bun", "run", "dev"]
### Stage 3: Python Common Code Base
FROM python:${PYTHON_VERSION} AS python-common-code
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Install system dependencies & uv
RUN apt-get update && apt-get install -y \
libpq-dev \
redis-tools \
postgresql-client \
gcc \
&& rm -rf /var/lib/apt/lists/* \
&& pip install --root-user-action=ignore uv
WORKDIR /code
# Copy project configuration and all application code
COPY pyproject.toml uv.lock ./
COPY . .
### Stage 4: Python Dependencies
FROM python-common-code AS python-dependencies
ARG BUILD_ENV
ENV BUILD_ENV=${BUILD_ENV}
# Configure uv environment
ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy
# Install Python dependencies based on BUILD_ENV
RUN if [ "${BUILD_ENV}" = "production" ]; then \
echo "Installing production Python dependencies..."; \
uv sync --locked --no-dev; \
else \
echo "Installing development Python dependencies (includes dev, test)..."; \
uv sync --locked; \
fi
### Stage 5: Download pre-built binaries for OSV-Scanner and Cosign
FROM alpine:3.21 AS binary-downloader
ARG OSV_SCANNER_VERSION
# For releases, see: https://github.com/sigstore/cosign/releases
ARG COSIGN_VERSION=v2.4.1
ARG TARGETARCH
RUN set -e && apk add --no-cache curl && \
ARCH="${TARGETARCH}" && \
# Download osv-scanner and verify checksum
curl -fsSL "https://github.com/google/osv-scanner/releases/download/${OSV_SCANNER_VERSION}/osv-scanner_linux_${ARCH}" \
-o /usr/local/bin/osv-scanner && \
curl -fsSL "https://github.com/google/osv-scanner/releases/download/${OSV_SCANNER_VERSION}/osv-scanner_SHA256SUMS" \
-o /tmp/osv-scanner_SHA256SUMS && \
cd /usr/local/bin && \
grep "osv-scanner_linux_${ARCH}$" /tmp/osv-scanner_SHA256SUMS > /tmp/osv-checksum.txt && \
sed -i "s|osv-scanner_linux_${ARCH}|osv-scanner|" /tmp/osv-checksum.txt && \
sha256sum -c /tmp/osv-checksum.txt && \
chmod +x /usr/local/bin/osv-scanner && \
# Download cosign and verify checksum
curl -fsSL "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-${ARCH}" \
-o /usr/local/bin/cosign && \
curl -fsSL "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign_checksums.txt" \
-o /tmp/cosign_checksums.txt && \
grep "cosign-linux-${ARCH}$" /tmp/cosign_checksums.txt > /tmp/cosign-checksum.txt && \
sed -i "s|cosign-linux-${ARCH}|cosign|" /tmp/cosign-checksum.txt && \
sha256sum -c /tmp/cosign-checksum.txt && \
chmod +x /usr/local/bin/cosign && \
rm -f /tmp/osv-scanner_SHA256SUMS /tmp/osv-checksum.txt /tmp/cosign_checksums.txt /tmp/cosign-checksum.txt
### Stage 6: Python Application for Development (python-app-dev)
FROM python-dependencies AS python-app-dev
WORKDIR /code
# No production-specific asset copying or collectstatic needed for dev
# Copy the osv-scanner and cosign binaries from the binary-downloader stage
COPY --from=binary-downloader /usr/local/bin/osv-scanner /usr/local/bin/osv-scanner
COPY --from=binary-downloader /usr/local/bin/cosign /usr/local/bin/cosign
# Create directories with proper permissions for non-root user
# Create dedicated directory for Prometheus metrics and ensure /tmp is writable for app processes
# Note: In development, .venv is writable by nobody to support editable installs and hot-reload
RUN mkdir -p /var/lib/dramatiq-prometheus /tmp/.cache && \
chown -R nobody:nogroup /var/lib/dramatiq-prometheus /tmp /tmp/.cache /code/.venv && \
chmod 755 /var/lib/dramatiq-prometheus && \
chmod 755 /tmp && \
chmod 755 /tmp/.cache
# Set environment variables for Prometheus metrics and UV cache
ENV PROMETHEUS_MULTIPROC_DIR=/var/lib/dramatiq-prometheus \
UV_CACHE_DIR=/tmp/.cache/uv \
HOME=/tmp
# Switch to non-root user
USER nobody
EXPOSE 8000
# CMD for Development (using uvicorn directly with reload for development)
CMD ["uv", "run", "uvicorn", "sbomify.asgi:application", \
"--host", "0.0.0.0", "--port", "8000", \
"--reload", "--reload-include", "*.j2", "--log-level", "info"]
### Stage 7: Python Application for Production (python-app-prod)
# This is the default final stage if no target is specified.
FROM python-dependencies AS python-app-prod
# Re-declare build metadata ARGs (required in each stage that uses them)
ARG BUILD_DATE=""
ARG GIT_COMMIT=""
ARG GIT_COMMIT_SHORT=""
ARG GIT_REF=""
ARG VERSION=""
ARG BUILD_TYPE=""
# OCI Image Spec labels for container metadata
LABEL org.opencontainers.image.title="sbomify" \
org.opencontainers.image.description="Your Security Artifact Hub - Generate, manage, and share SBOMs and compliance documents" \
org.opencontainers.image.url="https://github.com/sbomify/sbomify" \
org.opencontainers.image.source="https://github.com/sbomify/sbomify" \
org.opencontainers.image.vendor="sbomify" \
org.opencontainers.image.licenses="Apache-2.0 WITH Commons-Clause-1.0" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${GIT_COMMIT}" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.ref.name="${GIT_REF}" \
com.sbomify.build.type="${BUILD_TYPE}"
WORKDIR /code
# Copy the osv-scanner and cosign binaries from the binary-downloader stage
COPY --from=binary-downloader /usr/local/bin/osv-scanner /usr/local/bin/osv-scanner
COPY --from=binary-downloader /usr/local/bin/cosign /usr/local/bin/cosign
# Production-specific steps
COPY --from=js-build-prod /js-build/sbomify/static/dist /code/sbomify/static/dist
# Copy other static files that may have been created during build
COPY --from=js-build-prod /js-build/sbomify/static/css /code/sbomify/static/css
COPY --from=js-build-prod /js-build/sbomify/static/webfonts /code/sbomify/static/webfonts
# Copy the compiled Keycloak theme CSS from the separate Keycloak build stage
COPY --from=keycloak-build /keycloak-build/themes/sbomify/login/resources/css /code/keycloak/themes/sbomify/login/resources/css
# Prevent uv run from implicitly syncing (which would reinstall dev dependencies)
ENV UV_NO_SYNC=1
# Create directories and run collectstatic as root, then fix permissions
# Create dedicated directory for Prometheus metrics and ensure /tmp is writable for app processes
# Note: In production, .venv stays owned by root for better security (app can't modify its own dependencies)
RUN mkdir -p /var/lib/dramatiq-prometheus /code/staticfiles /tmp/.cache && \
uv run python manage.py collectstatic --noinput && \
chown -R nobody:nogroup /var/lib/dramatiq-prometheus /tmp /tmp/.cache && \
chmod 755 /var/lib/dramatiq-prometheus && \
chmod 755 /tmp && \
chmod 755 /tmp/.cache
# Set environment variables for Prometheus metrics, UV cache, and build metadata
# Build metadata is exposed at runtime for version display in the application
ENV PROMETHEUS_MULTIPROC_DIR=/var/lib/dramatiq-prometheus \
UV_CACHE_DIR=/tmp/.cache/uv \
HOME=/tmp \
SBOMIFY_BUILD_DATE="${BUILD_DATE}" \
SBOMIFY_GIT_COMMIT="${GIT_COMMIT}" \
SBOMIFY_GIT_COMMIT_SHORT="${GIT_COMMIT_SHORT}" \
SBOMIFY_GIT_REF="${GIT_REF}" \
SBOMIFY_VERSION="${VERSION}" \
SBOMIFY_BUILD_TYPE="${BUILD_TYPE}"
# Switch to non-root user
USER nobody
EXPOSE 8000
# CMD for Production - Using Gunicorn with Uvicorn worker as recommended by Django docs
# --graceful-timeout 30: Workers get 30s to finish requests on SIGTERM
# --timeout 120: Max time for a single request (2 min for large SBOM uploads)
CMD ["uv", "run", "gunicorn", "sbomify.asgi:application", \
"--bind", "0.0.0.0:8000", \
"--workers", "2", \
"--worker-class", "uvicorn_worker.UvicornWorker", \
"--graceful-timeout", "30", \
"--timeout", "120"]