mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-07-26 14:25:41 +00:00
80d273ff11
Closes the "backend has zero CI + manual SSH deploy" audit finding for the indexer. Part B — CI-runnable tests (the integration-tests/*.live.test.js need a live chain and are excluded, not stubbed): extract injectable cores (indexer.js: DB+HTTP+decode, no @pezkuwi import; council.js: createApp factory for the council/KYC routes). New node:test suite (19/19, fully offline) — in-memory sqlite, dependency-injected chain stub, an in-memory fake-supabase, and REAL @pezkuwi keyring signatures proving 401 bad-sig / 400 msg-mismatch / 200 valid / 409 dup / 403 non-member / threshold auto-execute. Backend job now runs npm ci + npm test and is in ci-gate (failing tests block merge). Fixed a latent bug: block indexing now awaits each insert (was fire-and-forget forEach). Added runtime deps server.js imported but were missing from package.json (@supabase/supabase-js, pino, pino-http) — server.js could not have `npm ci`-run before. Part C — Dockerfile (non-root, HEALTHCHECK /health, sqlite state on a /data VOLUME kept out of the image) + backend deploy pipeline mirroring the web one: build+push to GHCR, cosign keyless sign + verify, ssh deploy with the DB volume preserved across deploys, /health poll, auto-rollback to previous SHA, same Telegram CEO approval gate, main/tags only, never fork PRs. New secrets documented in backend/DEPLOY.md (BACKEND_VPS_HOST/USER/ SSH_KEY). DB_PATH env (default ./transactions.db) lets prod point at the volume. Note for owner: if server.js (council/KYC bootstrap) is legacy/unused, its newly-added deps can be dropped instead.
48 lines
1.8 KiB
Docker
48 lines
1.8 KiB
Docker
# pwap indexer service — runnable Node container (not a static-dist image).
|
|
#
|
|
# Two stages on the SAME debian base so the natively-compiled sqlite3 binding
|
|
# built in stage 1 is ABI-compatible with the runtime in stage 2 (do NOT mix
|
|
# alpine/musl here — sqlite3 would fail to load).
|
|
#
|
|
# STATEFUL DATA: the indexer's sqlite file is the service's memory. It is kept
|
|
# OUT of the image, under /data, which MUST be a mounted volume. A deploy
|
|
# replaces the container/image but never the volume — see backend/DEPLOY.md.
|
|
|
|
# ─── Stage 1: install production deps (compiles sqlite3) ────────
|
|
FROM node:20-bookworm AS builder
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
# --omit=dev: the test-only devDeps (supertest, @pezkuwi/keyring) never ship.
|
|
RUN npm ci --omit=dev
|
|
|
|
# ─── Stage 2: runtime ──────────────────────────────────────────
|
|
FROM node:20-bookworm-slim
|
|
ENV NODE_ENV=production
|
|
ENV PORT=3001
|
|
# DB on the volume, never in the image layer.
|
|
ENV DB_PATH=/data/transactions.db
|
|
WORKDIR /app
|
|
|
|
# curl only, for the HEALTHCHECK probe.
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends curl \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
COPY --from=builder /app/node_modules ./node_modules
|
|
COPY package.json ./
|
|
COPY src ./src
|
|
|
|
# /data holds the stateful sqlite DB — declared as a volume and owned by the
|
|
# non-root runtime user so the container can write to the mount.
|
|
RUN mkdir -p /data && chown -R node:node /app /data
|
|
VOLUME ["/data"]
|
|
|
|
USER node
|
|
EXPOSE 3001
|
|
|
|
# Probe the in-container /health endpoint added to the indexer API.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|
CMD sh -c 'curl -fsS "http://localhost:${PORT:-3001}/health" || exit 1'
|
|
|
|
CMD ["node", "src/index.js"]
|