Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
92 lines (66 loc) · 3.22 KB
/
Copy pathDockerfile
File metadata and controls
92 lines (66 loc) · 3.22 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
# Multi-stage build for OSCAL SOA/SSP/CCM Generator
# Author: Mukesh Kesharwani <mukesh.kesharwani@adobe.com>
# Copyright (c) 2025 Mukesh Kesharwani
FROM node:24-alpine AS frontend-builder
WORKDIR /app/frontend
# Copy frontend package files (lockfile pins Vite/Rolldown; npm install without it breaks vite.config bundling)
COPY frontend/package.json frontend/package-lock.json ./
# Install frontend dependencies (including dev deps needed for build)
RUN npm ci
# Copy frontend source
COPY frontend/ ./
# Catalogue preset manifest (imported from src/catalogues/sampleCatalogues.js via ../../../config/...)
COPY config/catalogues/sample-catalogues.json ../config/catalogues/sample-catalogues.json
# Shared constants (imported from src/constants/*.js via ../../../config/constants/*.json)
COPY config/constants/ ../config/constants/
# Build frontend
RUN npm run build
# Backend stage
FROM node:24-alpine AS production
WORKDIR /app
# Install dependencies for production
COPY backend/package*.json ./
RUN npm ci --omit=dev --no-audit --no-fund \
&& rm -rf /root/.npm /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/corepack \
/usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack
# The runtime only runs node. npm and corepack are removed after the install so the image does not ship their bundled
# packages (they carried fixable HIGH vulnerabilities) and has a smaller attack surface.
# Copy backend source
COPY backend/ ./
# Shared constants + catalogue manifest (backend/utils/constants.js and
# sampleCatalogues.js resolve these via path.resolve(__dirname, '../../config/...'),
# which lands at /config/... once backend/ is flattened into /app)
COPY config/constants/ /config/constants/
COPY config/catalogues/ /config/catalogues/
# Copy built frontend from frontend-builder stage
COPY --from=frontend-builder /app/frontend/dist ./public
# Bundled config with Generic OIDC _cfgenc (Docker bootstrap field key; OAuth secret not plaintext)
COPY config/app/config.json.example /tmp/config.json.example
RUN node scripts/prepare-docker-bundled-config.mjs /tmp/config.json.example /app/config/app/config.json \
&& rm -f /tmp/config.json.example
# Optional default users (volume init copies when missing)
COPY config/app/users.json.example /app/config/app/users.json.example
# Create config directory structure
RUN mkdir -p /app/config/app
# Copy entrypoint script for volume initialization
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Declare volume for persistent data (config and users)
# Users should mount this to preserve data across container updates
VOLUME ["/data"]
# Build argument for port (defaults to 3020 for Blue, 3019 for Green)
ARG PORT=3020
# Expose port
EXPOSE ${PORT}
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD node -e "require('http').get('http://localhost:${PORT}/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Set environment variables
ENV NODE_ENV=production
ENV PORT=${PORT}
ENV OSCAL_DOCKER_IMAGE=1
ENV OSCAL_PASS_DISABLED=1
# Use entrypoint script to handle volume initialization
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
# Start the application (passed to entrypoint)
CMD ["node", "server.js"]