Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5e3b79d
land BFSI v1 production plan under docs/plan/bfsi-v1
pulkitpareek18 May 28, 2026
51bc705
add ADR 0011 for dev+main branching workflow
pulkitpareek18 May 28, 2026
27ed93c
add ADRs 0013/0014/0015 for audit chain + on-chain anchor + circuit v…
pulkitpareek18 May 28, 2026
02e1734
remove demo bypass from proof-pairing submitProof
pulkitpareek18 May 28, 2026
ee6aad4
remove access_token query fallback from console SSE auth
pulkitpareek18 May 28, 2026
5425032
add schema-purity test locking down tenant-scoped table columns
pulkitpareek18 May 28, 2026
a475ed8
add hash chain to audit_events writes
pulkitpareek18 May 28, 2026
d634b2d
add /api/admin/audit-integrity endpoint
pulkitpareek18 May 28, 2026
c09c081
add biometric-rejection test grepping forbidden payload keys
pulkitpareek18 May 28, 2026
573ff5d
track audit findings and update threat model for Phase 0 closures
pulkitpareek18 May 28, 2026
c240378
update CLAUDE.md with Phase 0 references and closed P0 findings
pulkitpareek18 May 28, 2026
a1bbc47
add cross-tenant source-level guard for /v1/* routes
pulkitpareek18 May 28, 2026
e98d158
lock circuit version with boot-time vkey hash check
pulkitpareek18 May 28, 2026
ea6a7f6
mark C-7 and C-12 audit findings closed
pulkitpareek18 May 28, 2026
d6c6a4e
add AuditAnchor contract with write-once daily anchors
pulkitpareek18 May 28, 2026
df3f063
add seed script for Anchor Bank demo tenant
pulkitpareek18 May 28, 2026
f8a756c
add nightly CVE monitor with high-severity alert
pulkitpareek18 May 28, 2026
bb682f3
add trusted-setup ceremony runbook for v1.2 circuit
pulkitpareek18 May 28, 2026
96e50d2
add Android device-support matrix for tier-1 tier-2 tier-3
pulkitpareek18 May 28, 2026
8b72f5f
add Anchor Bank demo runbook with scene-by-scene operator script
pulkitpareek18 May 28, 2026
651bd16
add 12-month compliance roadmap v1
pulkitpareek18 May 28, 2026
76f8d4e
add ADR 0016 for zod input validation layer
pulkitpareek18 May 28, 2026
416eaab
add DPDP section 2t commitments memo skeleton
pulkitpareek18 May 28, 2026
6e06a14
add dashboard users view with no-PII assertion
May 28, 2026
0c89321
set ADMIN_API_KEY in jest setupFiles for admin-audit tests
May 28, 2026
e165569
add data inventory v1 + PIA template + retention policy v0
May 28, 2026
48ed797
bootstrap mobile/ Android subtree with Compose + module shell
May 28, 2026
78366cd
add kiosk web app skeleton for Scene 2 demo
May 28, 2026
0848640
add audit-integrity dashboard view skeleton with PASS/FAIL card
May 28, 2026
52eadd4
add 20-slide BFSI pitch deck storyboard v0
May 28, 2026
8494ffc
add anchor-job service + audit_anchors schema (off-chain half)
May 28, 2026
c7841b7
add Postgres-backed rate limit on verify and login
May 28, 2026
6f1c164
add enterprise risk register v1 with 10-item baseline
May 28, 2026
dfd70ae
add SOC 2 control narratives batch 1 (CC1.x..CC8.1)
amitduabits May 28, 2026
67da733
add BFSI bank intel packs and 5-email outreach sequence
May 28, 2026
c95bf26
add ADR 0017 blockchain-agnostic platform posture
May 28, 2026
6b55210
gate chain providers behind tenant security_policy opt-in
May 28, 2026
d455045
add face-first POST /v1/identity/register endpoint
May 28, 2026
85a49ae
add face-first POST /v1/identity/verify with commitment check
May 28, 2026
394243f
add Auth0 differentiation one-pager for BFSI CIO/CISO
May 28, 2026
f5aa82a
expand biometric-rejection guard to compound keys
May 28, 2026
0460568
document face-first identity endpoints in api_contract
May 28, 2026
d874d44
add source-level guard for blockchain-agnostic posture
May 28, 2026
1395c24
add mobile face capture flow with CameraX + ML Kit liveness gate
May 28, 2026
799376c
add Deprecation + Sunset headers to legacy /v1/auth/zkp endpoints
May 28, 2026
1712c9e
add mobile face embedding + commitment pipeline (no Poseidon impl yet)
May 28, 2026
aff7b6d
add live verifications dashboard view with SSE stream
May 28, 2026
e0d030c
wire face-first dashboard views into App router
May 28, 2026
221ee73
implement Poseidon-BN128 in mobile/biometric (vendored from android/sec)
May 28, 2026
be15174
document face-first pivot in CLAUDE.md and update audit findings
May 28, 2026
5ad545c
add husky pre-commit + commit-msg hooks (closes audit C-15)
May 28, 2026
447b813
add per-tenant CORS allowlist middleware
May 28, 2026
5a12bb4
Postgres-backed session store with write-through cache (closes C-9)
May 28, 2026
36b3923
migrate JWT to RS256 with JWKS endpoint and dual-issuer rollover
May 28, 2026
0b689e8
vendor W3 WebView snarkjs prover into mobile/prover
May 28, 2026
a0d7479
mark C-9 C-11 C-13 C-15 closed in audit-findings tracker
May 28, 2026
5ade6e8
fix docs site build: parse .md as CommonMark instead of MDX
May 28, 2026
083bca1
grant security-review workflow issues:write to fix 404 on PR comment
May 28, 2026
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
168 changes: 168 additions & 0 deletions .github/workflows/cve-monitor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
name: CVE Monitor

# Nightly supply-chain CVE monitor — closes Phase 0 audit finding C-14.
# Plan: docs/plan/bfsi-v1/04-commits.md commit C-032 (owner Role 22).
#
# Runs `npm audit --json` (always available) plus `npx osv-scanner -r .`
# (Google's OSV scanner — covers ecosystems npm audit doesn't, eg cargo,
# gradle, swift packages used by the mobile sub-projects).
#
# If either scanner reports any vulnerability with severity `high` or
# `critical`, the workflow opens a GitHub issue with the scanner output
# attached and sends an email alert to the address held in the
# SECURITY_ALERT_EMAIL secret. Both signals are intentional belt-and-
# braces — Slack alerts are wired in by C-129..C-142 (alert tuning).

on:
schedule:
# Nightly at 00:00 UTC (05:30 IST — well before the 09:30 IST standup).
- cron: '0 0 * * *'
workflow_dispatch:

concurrency:
group: cve-monitor
cancel-in-progress: false

permissions:
contents: read
issues: write

jobs:
scan:
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: |
package-lock.json
dashboard/package-lock.json
website/package-lock.json

- name: Install root dependencies
run: npm ci

- name: Install dashboard dependencies
run: npm --prefix dashboard ci

- name: Install website dependencies
run: npm --prefix website ci

- name: Run CVE scanners
id: scan
# The helper script exits 0 when no high/critical CVEs are found
# and exits non-zero (1) when at least one is found. We capture
# the exit status into a step output so the follow-up "open
# issue" + "email alert" steps can fire conditionally without
# short-circuiting the whole job.
run: |
set +e
./scripts/cve-monitor.sh > /tmp/cve-monitor.log 2>&1
status=$?
echo "status=${status}" >> "$GITHUB_OUTPUT"
cat /tmp/cve-monitor.log
# Always succeed at this step so artefact upload + alerting
# run; the job itself fails at the final guard step below.
exit 0

- name: Upload scanner output
if: always()
uses: actions/upload-artifact@v4
with:
name: cve-monitor-log
path: /tmp/cve-monitor.log
retention-days: 30
if-no-files-found: warn

- name: Open GitHub issue on high/critical finding
if: steps.scan.outputs.status != '0'
uses: actions/github-script@v7
env:
SCAN_LOG_PATH: /tmp/cve-monitor.log
with:
script: |
const fs = require('fs');
const path = process.env.SCAN_LOG_PATH;
let log = '(scanner log missing)';
try {
log = fs.readFileSync(path, 'utf8');
} catch (err) {
core.warning(`Could not read scanner log at ${path}: ${err.message}`);
}
// Cap at 60 KB so the issue body stays under GitHub's limit.
if (log.length > 60_000) {
log = log.slice(0, 60_000) + '\n\n…truncated…';
}
const today = new Date().toISOString().slice(0, 10);
const title = `CVE monitor: high/critical finding ${today}`;
const body = [
'## Nightly CVE monitor — high/critical finding',
'',
`Run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
`Workflow: \`${context.workflow}\``,
`Commit: ${context.sha}`,
'',
'Closes audit-findings.md C-14 instrumentation; see',
'`docs/plan/bfsi-v1/04-commits.md` commit C-032 for context.',
'',
'### Scanner output',
'',
'```',
log,
'```',
].join('\n');
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: ['security', 'cve-monitor'],
});

- name: Send email alert on high/critical finding
if: steps.scan.outputs.status != '0'
env:
SECURITY_ALERT_EMAIL: ${{ secrets.SECURITY_ALERT_EMAIL }}
run: |
if [ -z "${SECURITY_ALERT_EMAIL:-}" ]; then
echo "::warning::SECURITY_ALERT_EMAIL secret is not set; skipping email alert."
exit 0
fi
# The repo's mail relay is exercised by tests/email.test.ts; the
# workflow itself uses a thin sendmail wrapper rather than
# introducing a new GitHub Action dep (DP6: every dep is an ADR).
subject="[ZeroAuth] CVE monitor: high/critical finding $(date -u +%F)"
{
echo "To: ${SECURITY_ALERT_EMAIL}"
echo "From: cve-monitor@zeroauth.dev"
echo "Subject: ${subject}"
echo ""
echo "The nightly CVE monitor (.github/workflows/cve-monitor.yml)"
echo "found at least one vulnerability rated high or critical."
echo ""
echo "Run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
echo ""
echo "Scanner output:"
echo "----"
cat /tmp/cve-monitor.log || echo "(log unavailable)"
} > /tmp/cve-monitor.mail
if command -v sendmail >/dev/null 2>&1; then
sendmail -t < /tmp/cve-monitor.mail
echo "Email queued via sendmail to ${SECURITY_ALERT_EMAIL}."
else
echo "::warning::sendmail not available on runner; falling back to printing the message."
cat /tmp/cve-monitor.mail
fi

- name: Fail job if any high/critical CVE was found
if: steps.scan.outputs.status != '0'
run: |
echo "::error::High or critical CVE detected; see uploaded log and opened issue."
exit 1
9 changes: 9 additions & 0 deletions .github/workflows/security-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ on:
permissions:
contents: read
pull-requests: write
# `issues: write` is required because the script calls
# github.rest.issues.{listComments,createComment,updateComment} —
# those endpoints sit under /repos/{owner}/{repo}/issues/{n}/comments
# even when {n} is a pull-request number, and the `issues` scope is
# the one that gates them. Without this, GitHub returns 404 on the
# listComments call (it conceals access denial as not-found). The
# `pull-requests` scope alone is not sufficient for issue-comment
# CRUD on PR conversations.
issues: write

jobs:
flag:
Expand Down
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ artifacts/
cache/
typechain-types/

# ─── Android (mobile/ — Phase 1 banking app, C-101 onwards) ───
# Duplicates the rules in mobile/.gitignore so an accidental top-level
# `git add .` outside the subtree still skips the noisy artefacts.
mobile/.gradle/
mobile/local.properties
mobile/**/build/
mobile/**/.cxx/
mobile/**/*.keystore
mobile/**/*.jks

# ─── Coverage / logs ────────────────────────────────────
coverage/
*.log
Expand Down
61 changes: 61 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# Commit-msg hook — enforces the commit-subject rules per
# docs/plan/bfsi-v1/06-ways-of-working.md § Commit format.
#
# Blocks the commit if:
# - the body contains a `Co-Authored-By: Claude` trailer
# - the subject is > 72 characters
# - the subject starts with a Conventional-Commits prefix
# (feat:, fix:, chore:, refactor:, docs:, test:, etc.)
# - the subject starts with `[bracket]`, `WIP`, or `checkpoint`

set -euo pipefail

MSG_FILE="$1"

# Subject is the first non-blank line.
SUBJECT=$(awk 'NF{print; exit}' "$MSG_FILE")

# 1. Co-Authored-By: Claude check — only matches an actual trailer line,
# i.e. a line beginning with the literal trailer key. ADR docs +
# rejection messages that quote the string in prose are fine.
if grep -iE "^Co-Authored-By:[[:space:]]+Claude" "$MSG_FILE" >/dev/null 2>&1; then
echo "✗ Commit message has a 'Co-Authored-By: Claude' trailer line." >&2
echo " This is explicitly forbidden by the user's standing constraints." >&2
echo " Remove the trailer and re-commit." >&2
exit 1
fi

# 2. Subject length
SUBJECT_LEN=${#SUBJECT}
if (( SUBJECT_LEN > 72 )); then
echo "✗ Commit subject is ${SUBJECT_LEN} chars (> 72)." >&2
echo " Subject: $SUBJECT" >&2
echo " Tighten it; use the body for detail." >&2
exit 1
fi

# 3. No Conventional-Commits prefix
if echo "$SUBJECT" | grep -E '^(feat|fix|chore|refactor|docs|test|build|ci|perf|style|revert):' >/dev/null; then
echo "✗ Commit subject starts with a Conventional-Commits prefix." >&2
echo " Subject: $SUBJECT" >&2
echo " Plain English, imperative mood — see 06-ways-of-working.md." >&2
exit 1
fi

# 4. No bracket / WIP / checkpoint prefix
if echo "$SUBJECT" | grep -E '^(\[|WIP|wip|Checkpoint|checkpoint)' >/dev/null; then
echo "✗ Commit subject starts with a bracket prefix, WIP, or 'checkpoint'." >&2
echo " Subject: $SUBJECT" >&2
exit 1
fi

# 5. No emoji at the start (only the first few chars to avoid catching
# inline emoji elsewhere in the subject — though we ban it there too).
if echo "$SUBJECT" | head -c 4 | LC_ALL=C grep -P '[\x{1F300}-\x{1FAFF}]|[\x{2600}-\x{27BF}]' >/dev/null 2>&1; then
echo "✗ Commit subject starts with an emoji." >&2
echo " Subject: $SUBJECT" >&2
exit 1
fi

exit 0
7 changes: 7 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Pre-commit hook — ADR 0020.
# Runs the shared gate library so the same logic also fires in CI.
# To skip in an emergency: ZEROAUTH_PRECOMMIT_SKIP=1 git commit ...
# (The CI mirror catches anything skipped locally.)

exec bash scripts/pre-commit-checks.sh
48 changes: 47 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,52 @@

You are working in the **zeroauth.dev API + dashboard + docs** repo. Read this file at the start of every session. It overrides anything in inline comments or sub-folder READMEs that contradicts it.

## Current phase

ZeroAuth is on the BFSI v1 production plan. The plan is the source of truth for everything below — phase boundaries, commit ordering, agent responsibilities. Read these documents alongside this file:

- [docs/plan/bfsi-v1/00-README.md](docs/plan/bfsi-v1/00-README.md) — phase map + the 10 standing constraints.
- [docs/plan/bfsi-v1/01-pain-points.md](docs/plan/bfsi-v1/01-pain-points.md) — the 10 BFSI pain points ZeroAuth solves; every commit must trace to one.
- [docs/plan/bfsi-v1/02-bank-demo.md](docs/plan/bfsi-v1/02-bank-demo.md) — the Anchor Bank demo (5 scenes + optional Scene 6); Phase 1 exit gate is "all 6 scenes run end-to-end without operator intervention beyond the script."
- [docs/plan/bfsi-v1/03-team.md](docs/plan/bfsi-v1/03-team.md) — 50-person roster + KPIs.
- [docs/plan/bfsi-v1/04-commits.md](docs/plan/bfsi-v1/04-commits.md) — commit-by-commit plan (C-001..C-194 for Phase 0 + Phase 1). Commit subjects in the codebase reference these IDs.
- [docs/plan/bfsi-v1/05-agents.md](docs/plan/bfsi-v1/05-agents.md) — per-agent week-by-week tickets.
- [docs/plan/bfsi-v1/agents/](docs/plan/bfsi-v1/agents/) — per-agent daily Mon-Fri tickets for weeks 1-4 with 5-field DoD per ticket.
- [docs/plan/bfsi-v1/06-ways-of-working.md](docs/plan/bfsi-v1/06-ways-of-working.md) — branch policy, commit gates, sub-agent rules, cadence.

Phase 0 (weeks 1-2) closes the 21 Phase 0 audit findings (tracked in [docs/security/audit-findings.md](docs/security/audit-findings.md)). Phase 1 (weeks 3-12) builds the Anchor Bank demo end-to-end.

Phase 0 closed P0 findings as of LAST_UPDATED: C-1 (demo bypass), C-3 (access_token query fallback), C-4 (audit hash chain), C-6 (direct INSERT guard), C-7 (vkey integrity), C-8 (biometric-payload guard), C-10 (rate-limit), C-12 (cross-tenant matrix), C-14 (CVE monitor). C-2 (fake mobile prover) tracks to Phase 1 Sprint 3.

## Blockchain-agnostic pivot (ADR 0017)

The platform is **blockchain-agnostic by default**. Per [adr/0017-blockchain-agnostic-posture.md](adr/0017-blockchain-agnostic-posture.md), the on-chain anchor + DIDRegistry + on-chain verifier are now **opt-in providers** keyed on `tenant.security_policy`:

- `did_provider`: `off-chain` (default) | `base-sepolia` | `base-mainnet` | `custom-chain`
- `verifier_provider`: `off-chain` (default) | `on-chain`
- `audit_anchor_provider`: `none` (default) | `signed-transcript` | `base-sepolia` | `base-mainnet` | `witness-cosign`

A default tenant boots with zero `BLOCKCHAIN_PRIVATE_KEY`, zero contract address, zero RPC dependency. The Pramaan ZK protocol + hash-chained audit log work end-to-end off-chain. The Auth0 differentiation pitch ([docs/why-zeroauth/vs-auth0.md](docs/why-zeroauth/vs-auth0.md)) does not require any blockchain to hold.

## Face-first identity surface (ADR 0017)

The production register + verify endpoints are:

- `POST /v1/identity/register` — accepts on-device-computed `(did, commitment)` only. No biometric template, no image, no embedding ever crosses the wire.
- `POST /v1/identity/verify` — looks up user by DID, asserts `publicSignals[0]` matches stored commitment, runs `snarkjs.groth16.verify` against the boot-pinned vkey, mints session.

The legacy `/v1/auth/zkp/register` (which accepts a base64 biometricTemplate) and `/v1/auth/zkp/verify` (no DID lookup) are retained for backward compat with the W3 demo client and carry `Deprecation: true` + `Sunset: 2026-12-31` headers. New integrations MUST use `/v1/identity/*`.

On-device commitment pipeline lives in [mobile/biometric/](mobile/biometric/):

- `FaceEmbedder` (TFLite MobileFaceNet) → 128-dim L2-normalised embedding
- `Quantizer` → 256-byte deterministic int16 BE
- `Sha256` (with buffer zeroing) → 32-byte secret
- `Poseidon.hash2(secret, salt)` → 32-byte commitment (BN128 field element, byte-identical to `circomlibjs.poseidon2`)
- `Keccak256(commitment)[:20]` → DID suffix

CameraX face-capture + ML Kit detection lives in [mobile/face/](mobile/face/).

## What this repo is

ZeroAuth is the zero-knowledge identity verification layer for India's regulated industries (BFSI, healthcare, government). This repo holds:
Expand Down Expand Up @@ -179,5 +225,5 @@ More skills (`release-cut`, `test-from-threat-model`, `migration-writer`, `adr-w

---

LAST_UPDATED: 2026-05-12
LAST_UPDATED: 2026-05-28
OWNER: Pulkit Pareek (engineering) + Amit Dua (product)
Loading
Loading