-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
178 lines (148 loc) · 6.83 KB
/
Dockerfile
File metadata and controls
178 lines (148 loc) · 6.83 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
# ───────────────────────────────────────────────
# ZeroAuth Multi-Stage Dockerfile
# Supports: development, test, production targets
# ───────────────────────────────────────────────
# ── Development Stage ─────────────────────────
FROM node:20-alpine AS development
WORKDIR /app
RUN apk add --no-cache python3 make g++
COPY package.json package-lock.json* ./
RUN npm ci
COPY tsconfig.json ./
COPY src/ ./src/
COPY public/ ./public/
COPY circuits/ ./circuits/
COPY contracts/ ./contracts/
COPY dashboard/ ./dashboard/
COPY website/build/ ./website/build/
EXPOSE 3000 5173
CMD ["npx", "tsx", "watch", "src/server.ts"]
# ── Test Stage ────────────────────────────────
FROM node:20-alpine AS test
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
COPY tsconfig.json jest.config.* ./
COPY src/ ./src/
COPY tests/ ./tests/
COPY circuits/build/ ./circuits/build/
CMD ["npm", "test"]
# ── Build Stage — API ─────────────────────────
FROM node:20-alpine AS api-build
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --ignore-scripts
COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build
# ── Build Stage — Dashboard ───────────────────
FROM node:20-alpine AS dashboard-build
WORKDIR /app/dashboard
COPY dashboard/package.json dashboard/package-lock.json* ./
RUN npm ci --ignore-scripts
COPY dashboard/ ./
RUN npm run build
# ── Build Stage — Documentation ───────────────
FROM node:20-alpine AS docs-build
WORKDIR /app/website
COPY website/package.json website/package-lock.json* ./
RUN npm ci --ignore-scripts
COPY website/ ./
COPY docs/ ../docs/
RUN npm run build
# ── Build Stage — Verifier (B02 Plan B) ───────
# The verifier is an npm workspace of the root package. We install via
# the workspace flag (resolves against the committed root lockfile so the
# build is reproducible) but copy only what the verifier needs to compile.
FROM node:20-alpine AS verifier-build
WORKDIR /app
COPY package.json package-lock.json* ./
COPY verifier/package.json ./verifier/
RUN npm ci --workspace @zeroauth/verifier --include-workspace-root=false --ignore-scripts
COPY verifier/tsconfig.json ./verifier/
COPY verifier/src/ ./verifier/src/
RUN npm --workspace @zeroauth/verifier run build
# ── Verifier Production Stage ─────────────────
# Slim runtime image — just the compiled JS + production deps + the
# verification key. No source TS, no test deps, no snarkjs build tools.
# Bound to :3001 on the Docker network; the API container reaches it via
# its compose service name `zeroauth-verifier`. Loopback-only is enforced
# at the network boundary — no host port binding.
FROM node:20-alpine AS verifier-production
WORKDIR /app
RUN addgroup -g 1001 -S zeroauth && \
adduser -S zeroauth -u 1001
# Install verifier's prod deps in a flat node_modules. Deliberately uses
# `npm install --omit=dev` rather than `npm ci` because the verifier
# workspace doesn't have its own lockfile (it shares the root's via
# npm workspaces, which complicates a single-package install). Trade-off
# is acceptable for v0; full reproducible-build provenance is on the
# roadmap per ADR-0005 / the verifier design doc.
#
# NOTES:
# 1. `better-sqlite3` is a native Node addon. The npm-published prebuilds
# don't cover alpine-linux-musl-arm64 (the VPS architecture), so
# prebuild-install falls back to a node-gyp source build. That needs
# python3 + make + g++. We install them, build, then DELETE them to
# keep the runtime image small (cleanup at the end of this RUN saves
# ~150MB).
# 2. We allow lifecycle scripts here (no `--ignore-scripts`) because
# better-sqlite3's postinstall is what triggers the build. All 4
# other deps (express, snarkjs, uuid, winston) are JS-only.
COPY verifier/package.json ./package.json
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
&& npm install --omit=dev \
&& npm cache clean --force \
&& apk del .build-deps
# Compiled JS from the verifier-build stage
COPY --from=verifier-build /app/verifier/dist ./dist
# The Groth16 verification key — read at startup. Hard-coded absolute
# path via VERIFIER_VKEY_PATH so cwd changes can't make the file
# unfindable.
COPY circuits/build/verification_key.json /app/circuits/build/verification_key.json
# Writable data directory for the SQLite audit log (B02 design doc §4.3).
# Owned by the non-root user; mounted as a Docker volume in compose so
# the DB survives container restarts. Without this `mkdir` here, the
# non-root user can't create the dir at startup → service crashes.
RUN mkdir -p /app/data && chown -R zeroauth:zeroauth /app/data
USER zeroauth
ENV NODE_ENV=production
ENV VERIFIER_VKEY_PATH=/app/circuits/build/verification_key.json
ENV VERIFIER_AUDIT_DB_PATH=/app/data/audit.db
ENV VERIFIER_BIND=0.0.0.0
ENV VERIFIER_PORT=3001
EXPOSE 3001
# NOTE: 127.0.0.1 not localhost. Alpine's busybox wget resolves
# `localhost` to IPv6 (::1) first; the verifier binds IPv4 0.0.0.0,
# so the IPv6 connection is refused and busybox bails without falling
# back to IPv4. Using the literal IPv4 address sidesteps the resolver.
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:3001/health || exit 1
CMD ["node", "dist/server.js"]
# ── Production Stage ──────────────────────────
FROM node:20-alpine AS production
WORKDIR /app
# Security: run as non-root
RUN addgroup -g 1001 -S zeroauth && \
adduser -S zeroauth -u 1001
COPY package.json package-lock.json* ./
RUN npm ci --omit=dev --ignore-scripts && npm cache clean --force
# Copy compiled API
COPY --from=api-build /app/dist ./dist
# Copy landing page
COPY public/ ./public/
# Copy dashboard build
COPY --from=dashboard-build /app/dashboard/dist ./dashboard/dist
# Copy built documentation site
COPY --from=docs-build /app/website/build ./website/build
# Copy ZKP circuit artifacts (pre-compiled)
COPY circuits/build/verification_key.json ./circuits/build/verification_key.json
COPY circuits/build/circuit_final.zkey ./circuits/build/circuit_final.zkey
COPY circuits/build/identity_proof_js/ ./circuits/build/identity_proof_js/
# Copy contract ABIs
COPY contracts/deployed-addresses.json* ./contracts/
USER zeroauth
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
CMD ["node", "dist/server.js"]