Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,62 @@ 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.
COPY verifier/package.json ./package.json
RUN npm install --omit=dev --ignore-scripts && npm cache clean --force

# 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

USER zeroauth

ENV NODE_ENV=production
ENV VERIFIER_VKEY_PATH=/app/circuits/build/verification_key.json
ENV VERIFIER_BIND=0.0.0.0
ENV VERIFIER_PORT=3001

EXPOSE 3001

HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1

CMD ["node", "dist/server.js"]

# ── Production Stage ──────────────────────────
FROM node:20-alpine AS production
WORKDIR /app
Expand Down
37 changes: 37 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ services:
retries: 3
profiles: ['dev', 'test', 'prod']

# ── Verifier (Plan B — TS, B02 Phase 2) ──────
# Standalone Groth16 verifier service. Loopback-only on the docker
# network (no host port binding). The API reaches it via the service
# name `zeroauth-verifier`.
zeroauth-verifier:
build:
context: .
target: verifier-production
container_name: zeroauth-verifier
expose:
- '3001'
environment:
- NODE_ENV=production
- VERIFIER_CIRCUIT_VERSION=v1
- LOG_LEVEL=info
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3001/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
profiles: ['dev', 'prod']

# ── Development ──────────────────────────────
zeroauth-dev:
build:
Expand All @@ -50,6 +74,9 @@ services:
- USE_REDIS_SESSIONS=true
- REDIS_URL=redis://redis:6379
- POSTGRES_HOST=postgres
# B02 Phase 2 — route ZKP verifications through the verifier service.
- VERIFIER_URL=http://zeroauth-verifier:3001
- VERIFIER_TIMEOUT_MS=2000
volumes:
- ./src:/app/src
- ./public:/app/public
Expand All @@ -63,6 +90,8 @@ services:
condition: service_healthy
postgres:
condition: service_healthy
zeroauth-verifier:
condition: service_healthy
profiles: ['dev']

# ── Test ─────────────────────────────────────
Expand Down Expand Up @@ -100,11 +129,19 @@ services:
- REDIS_URL=redis://redis:6379
- POSTGRES_HOST=postgres
- TRUST_PROXY=true
# B02 Phase 2 — production cutover. Routes /v1/auth/zkp/verify
# through the verifier service instead of inline snarkjs. The
# inline-fallback in src/services/zkp.ts stays in the binary as
# a safety net but is no longer the default code path in prod.
- VERIFIER_URL=http://zeroauth-verifier:3001
- VERIFIER_TIMEOUT_MS=2000
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
zeroauth-verifier:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/api/health']
Expand Down
94 changes: 94 additions & 0 deletions qa-log/2026-05-15.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# QA Log — 2026-05-15

**Run by:** Pulkit Pareek (alone)
**Time:** 12:30 IST (DW01 canonical slot is 09:55; today's entry is late because email-infra deployment ran through the morning — the runbook fix landed first, this entry second)
**Build:**

- API (`pulkitpareek18/ZeroAuth`): `02a79d0` on `main`
- Governance (`pulkitpareek18/ZeroAuth-Governance`): `bad10e7` on `main`
- IoT firmware: **not built** (B03 — Week 3)
- Mobile SDK: **not built** (B04 — Week 5)
- Liveness detection: **not built** (B13 — Week 3 / Week 5)
- Offline queue: **not built** (B14 — Week 4)
- Verifier service (Plan B, TS): **built + tested + in repo**, **NOT yet wired into prod docker-compose** — that's today's B02 Phase 2 work, next task on the day's list.

## Results — four-demo battery

### Demo 1 — Printed photo rejection

**Status:** Blocked
**Note:** Same as 2026-05-13/14. IoT hardware unavailable; liveness detection unbuilt. Unblocks Week 3.

### Demo 2 — Airplane mode authentication

**Status:** Blocked
**Note:** Offline queue unbuilt. Unblocks Week 4.

### Demo 3 — Three-different-hashes for the same identity

**Status:** Blocked
**Note:** LSH bucket protocol unbuilt. Unblocks Week 3+.

### Demo 4 — Hand-the-phone (impostor)

**Status:** Blocked
**Note:** Mobile SDK + on-device liveness unbuilt. Unblocks Week 5.

## Surrogate smoke (while battery is Blocked)

### S-1 — API reachability against production

**Status:** Green

| Endpoint | HTTP code |
|---|---|
| `GET /v1/audit` | 200 |
| `GET /v1/devices` | 200 |
| `GET /v1/users` | 200 |
| `GET /v1/verifications` | 200 |
| `GET /v1/attendance` | 200 |
| `GET /api/health` | 200 |

### S-2 — Email send (NEW today, was Blocked previously)

**Status:** Green
**Method:** Live signup against `https://zeroauth.dev/api/console/signup` at 06:51 UTC + duplicate-signup attempt at 06:51 UTC.

| Path | Outcome |
|---|---|
| Fresh signup → welcome email | ✅ Sent, messageId `<244c9a1f-958c-db5b-7da5-c93492194084@zeroauth.dev>` |
| Duplicate signup → notice email to legitimate holder | ✅ Sent, messageId `<a722369e-3ed2-dafb-9c4e-0345140f95a5@zeroauth.dev>` |
| SMTP transport | Brevo SMTP via `nodemailer 8.0.7`, IP `104.207.143.14` now allowlisted on Brevo |

This is the F-2 partial mitigation from issue #27 actually operating in production.

### S-3 — Playwright happy-path E2E

**Status:** Green
**Reference:** Last CI run on the most recent merge commit (`02a79d0`). Not re-run today.

### S-4 — Unit + integration suites

**Status:** Green
**Result:** 228 tests passing on the backend (Jest) + 23 on the verifier package = 251 total across both.

## Rollup

**Overall:** **HOLD**

Unchanged status — HOLD stays until B03/B04/B13/B14 ship. Today's notable progress is on the *email* surrogate (S-2 flipped from "not configured" to "delivering"), not on the demo battery itself.

## Escalations

None today. No regressions. Email infrastructure deployed cleanly after correcting the `docker compose restart` vs `up -d --force-recreate` gotcha — captured in [`docs/operations/env-vars.md`](../docs/operations/env-vars.md) so the next operator doesn't hit it.

## Operator notes

- This entry is the third DW01 run. The cadence is establishing itself.
- The W05 Friday gate review is scheduled for 16:00 IST today. DW10 engineering annex assembly happens at 15:30 IST — task #6 on today's list.
- Today's headline build: B02 Phase 2 — wire the verifier into the prod `docker-compose.yml` and flip `VERIFIER_URL` so production traffic actually goes through the new service (currently it still runs the inline-fallback path; the verifier package is shipped to the VPS but unused).
- Yesterday's email infra changes were a "below-the-fold" win — the marketing site doesn't show anything new, but a buyer's security team reading the threat model sees the F-2 mitigation in place.

---

LAST_UPDATED: 2026-05-15
8 changes: 4 additions & 4 deletions qa-log/LATEST.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Latest QA Run

→ [`2026-05-14.md`](2026-05-14.md)
→ [`2026-05-15.md`](2026-05-15.md)

**Rollup:** HOLD (every demo Blocked; surrogate smokes green; production stable on `ad2a04a`)
**Date:** 2026-05-14
**Next run:** Friday 2026-05-15 at 09:55 IST (before the W05 review at 16:00 IST)
**Rollup:** HOLD (every demo Blocked; surrogate smokes green; email delivery NEW + working today)
**Date:** 2026-05-15
**Next run:** Tuesday 2026-05-19 at 09:55 IST (W2 Day 1 — second-week metronome resumes Tue/Thu cadence)

(This file is overwritten on every run. For history, see the dated files in this directory.)
Loading