Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0404e3b
fix(#114): implement analytics service authentication
Nonso-Eze Apr 29, 2026
efdda51
fix(#110): add brute-force protection on auth endpoints
Nonso-Eze Apr 29, 2026
e7879de
Update CI workflow and add dependabot configuration
Apr 29, 2026
1f8c014
feat(#120): implement issuer onboarding workflow
Nonso-Eze Apr 29, 2026
45f0b66
docs(#116): add product roadmap and milestone structure
Nonso-Eze Apr 29, 2026
b778b51
merge: fix/114-analytics-auth into combined branch
Nonso-Eze Apr 29, 2026
212b41f
merge: fix/110-brute-force-protection into combined branch
Nonso-Eze Apr 29, 2026
49a81dd
merge: feat/120-issuer-onboarding into combined branch
Nonso-Eze Apr 29, 2026
c805fbe
merge: docs/116-roadmap-milestones into combined branch
Nonso-Eze Apr 29, 2026
ecf10c9
fix: document contract error codes and map backend messages
MickeeJay Apr 29, 2026
2cb15a2
Merge pull request #212 from bigvictoh/feat/issues-110-114-116-120-co…
dev-fatima-24 Apr 29, 2026
e7b9a7f
Merge pull request #213 from MickeeJay/fix/contract-error-codes
dev-fatima-24 Apr 29, 2026
01961e4
Merge pull request #211 from Ugasutun/main
dev-fatima-24 Apr 29, 2026
b160687
Add secret scanning protection with Gitleaks
ayomidearegbeshola29-dev Apr 29, 2026
5e00d57
Add comprehensive security headers to prevent XSS and clickjacking
ayomidearegbeshola29-dev Apr 29, 2026
e23b94b
fix(#105): enforce HTTPS and secure transport in production
Nonso-Eze Apr 29, 2026
fad8c49
fix(#107): implement JWT signing key rotation
Nonso-Eze Apr 29, 2026
3826ed2
feat(admin): add issuer management endpoints (#34)
mathewsap45 Apr 29, 2026
53ddc31
feat(frontend): add visual regression tests for NFTCard, Verification…
mathewsap45 Apr 29, 2026
cecd7bd
fix(#108): add input sanitization to prevent injection attacks
Nonso-Eze Apr 29, 2026
be32156
fix(#109): implement admin action multi-signature requirement
Nonso-Eze Apr 29, 2026
83c7934
merge: #105 enforce HTTPS and secure transport
Nonso-Eze Apr 29, 2026
e658a6c
merge: #107 JWT signing key rotation
Nonso-Eze Apr 29, 2026
ddfcfdf
merge: #108 input sanitization
Nonso-Eze Apr 29, 2026
f3f5ae6
merge: #109 admin multi-signature (resolve conflict in admin.js)
Nonso-Eze Apr 29, 2026
2a9fbec
feat: secure issuer middleware with on-chain verification and caching
Abd-Standard Apr 29, 2026
9f42f43
Merge branch 'main' into feat/secure-issuer-middleware
Abd-Standard Apr 29, 2026
1a8f7e0
Merge pull request #217 from Abd-Standard/feat/secure-issuer-middleware
dev-fatima-24 Apr 29, 2026
4cd3747
Merge pull request #216 from Christopherdominic/fix/security-issues-1…
dev-fatima-24 Apr 29, 2026
0e49bfe
Merge branch 'main' into feature/add-security-headers
dev-fatima-24 Apr 29, 2026
9d674c1
Merge pull request #215 from ayomidearegbeshola29-dev/feature/add-sec…
dev-fatima-24 Apr 29, 2026
4badb57
Merge branch 'main' into feature/add-secret-scanning-protection
dev-fatima-24 Apr 29, 2026
61723ce
Merge pull request #214 from ayomidearegbeshola29-dev/feature/add-sec…
dev-fatima-24 Apr 29, 2026
82f3550
feat: implement comprehensive coverage reporting and threshold enforc…
Abd-Standard Apr 29, 2026
2e5f8da
Merge branch 'main' into feat/coverage-reporting
Abd-Standard Apr 29, 2026
293a0d9
Merge pull request #218 from Abd-Standard/feat/coverage-reporting
dev-fatima-24 Apr 29, 2026
1e2c859
feat(contract): add pause/unpause mechanism for emergency stops
devEunicee Apr 29, 2026
c8a9dde
feat(contract): add pause/unpause mechanism for emergency stops
devEunicee Apr 29, 2026
c8d57ce
Merge pull request #219 from devEunicee/feat/contract-pause-mechanism
dev-fatima-24 Apr 29, 2026
46c0233
test(contract): add security invariant tests
devEunicee Apr 29, 2026
dd8758a
test(backend): add middleware unit tests for auth.js and issuer.js
devEunicee Apr 29, 2026
b826b2b
feat(frontend): add analytics dashboard page
devEunicee Apr 29, 2026
910f154
Merge pull request #221 from devEunicee/feat/backend-middleware-tests
dev-fatima-24 Apr 29, 2026
d97ad7d
Merge pull request #220 from devEunicee/feat/contract-security-invari…
dev-fatima-24 Apr 29, 2026
4876b48
Merge pull request #222 from devEunicee/feat/analytics-dashboard-page
dev-fatima-24 Apr 29, 2026
5ce5521
Merge pull request #224 from mathewsap45/feature/issue-98-visual-regr…
dev-fatima-24 May 5, 2026
43a5282
Merge branch 'main' into feature/issue-34-admin-issuer-endpoints
dev-fatima-24 May 5, 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
37 changes: 36 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ ISSUER_SECRET_KEY=
# JWT signing secret — min 32 chars recommended; rotate to invalidate sessions
JWT_SECRET=

# kid (key ID) for the current JWT signing key — increment on each rotation
JWT_KEY_ID=1

# Comma-separated list of previous JWT secrets still valid for verification
# during the transition window after a rotation. Remove entries once all
# tokens signed with those secrets have expired.
# Example: JWT_PREVIOUS_KEYS=oldSecret1,oldSecret2
JWT_PREVIOUS_KEYS=

# ── Backend server ────────────────────────────────────────────────────────────
# TCP port for the Express backend (default: 4000)
PORT=4000
Expand All @@ -53,6 +62,16 @@ RATE_LIMIT_SEP10=10
# Max public verify requests per IP per minute (default: 60)
RATE_LIMIT_VERIFY=60

# ── Brute-force protection ────────────────────────────────────────────────────
# Max failed /auth/verify attempts before blocking (default: 5)
BRUTE_FORCE_MAX_ATTEMPTS=5

# Sliding window for counting failures in milliseconds (default: 600000 = 10 min)
BRUTE_FORCE_WINDOW_MS=600000

# How long a blocked IP/wallet stays blocked in milliseconds (default: 900000 = 15 min)
BRUTE_FORCE_BLOCK_MS=900000

# ── Audit log ─────────────────────────────────────────────────────────────────
# Path to append-only NDJSON audit log (default: ./audit.log)
AUDIT_LOG_PATH=./audit.log
Expand All @@ -64,6 +83,10 @@ ANALYTICS_PORT=8001
# Base URL the analytics service uses to reach the backend (default set by Compose)
BACKEND_URL=http://backend:4000

# API key required to access protected analytics endpoints (rates, issuers, anomalies)
# Generate with: openssl rand -hex 32
ANALYTICS_API_KEY=

# ── Backup service ────────────────────────────────────────────────────────────
# S3 Bucket for analytics DB backup
S3_BUCKET_NAME=
Expand All @@ -87,7 +110,19 @@ AWS_SECRET_NAME=
# AWS region for Secrets Manager (default: us-east-1)
AWS_REGION=us-east-1

# ── Patient consent ───────────────────────────────────────────────────────────
# ── Admin multi-signature ─────────────────────────────────────────────────────
# Number of approvals required for critical admin operations (default: 2)
MULTISIG_THRESHOLD=2

# Comma-separated list of wallet addresses authorised to approve proposals.
# Leave empty to allow any admin-role JWT holder to approve.
# Example: MULTISIG_KEY_HOLDERS=GABC...,GDEF...,GHIJ...
MULTISIG_KEY_HOLDERS=

# How long a pending proposal stays valid in milliseconds (default: 3600000 = 1 hour)
MULTISIG_PROPOSAL_TTL_MS=3600000


# Set to 'false' to waive consent requirement (e.g. jurisdiction config).
# Default: true (consent required before minting)
REQUIRE_PATIENT_CONSENT=true
127 changes: 122 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,32 @@ jobs:
working-directory: contracts
run: make build

- name: Run contract tests
- name: Run contract tests with coverage
working-directory: contracts
run: make test
run: |
cargo install cargo-tarpaulin
make test-coverage

- name: Upload Contract Coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: contracts/tarpaulin-report.xml
flags: contracts
token: ${{ secrets.CODECOV_TOKEN }}

- name: Install cargo-audit
run: cargo install cargo-audit

- name: Dependency audit
working-directory: contracts
run: cargo audit | tee audit-report.txt

- name: Upload audit report
if: always()
uses: actions/upload-artifact@v4
with:
name: contract-audit-report
path: contracts/audit-report.txt

backend:
name: Node.js backend
Expand All @@ -54,9 +77,83 @@ jobs:
working-directory: backend
run: npm ci

- name: Run tests
- name: Run tests with coverage
working-directory: backend
run: npm run test:coverage

- name: Upload Backend Coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: backend/coverage/lcov.info
flags: backend
token: ${{ secrets.CODECOV_TOKEN }}

frontend:
name: Node.js frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: frontend
run: npm install --legacy-peer-deps

- name: Run tests with coverage
working-directory: frontend
run: npm run test:coverage

- name: Upload Frontend Coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: frontend/coverage/lcov.info
flags: frontend
token: ${{ secrets.CODECOV_TOKEN }}

- name: Dependency audit
working-directory: backend
run: npm test
run: npm audit --audit-level=high | tee audit-report.txt

- name: Upload audit report
if: always()
uses: actions/upload-artifact@v4
with:
name: backend-audit-report
path: backend/audit-report.txt

frontend:
name: Node.js frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: frontend
run: npm ci

- name: Dependency audit
working-directory: frontend
run: npm audit --audit-level=high | tee audit-report.txt

- name: Upload audit report
if: always()
uses: actions/upload-artifact@v4
with:
name: frontend-audit-report
path: frontend/audit-report.txt

python:
name: Python analytics service
Expand All @@ -75,10 +172,30 @@ jobs:
working-directory: python-service
run: pip install -r requirements.txt

- name: Run tests
- name: Run tests with coverage
working-directory: python-service
run: pytest

- name: Upload Python Coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: python-service/coverage.xml
flags: python
token: ${{ secrets.CODECOV_TOKEN }}
- name: Install pip-audit
run: pip install pip-audit

- name: Dependency audit
working-directory: python-service
run: pip-audit -r requirements.txt | tee audit-report.txt

- name: Upload audit report
if: always()
uses: actions/upload-artifact@v4
with:
name: python-audit-report
path: python-service/audit-report.txt

docker:
name: Docker build validation
runs-on: ubuntu-latest
Expand Down
32 changes: 32 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,35 @@ jobs:
name: test-videos
path: frontend/test-results/
retention-days: 7

visual:
name: Visual regression tests
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '18'

- name: Install frontend dependencies
run: cd frontend && npm install

- name: Install Playwright Chromium
run: cd frontend && npx playwright install chromium --with-deps

- name: Run visual regression tests
run: cd frontend && npx playwright test e2e/visual.spec.js --project=chromium
env:
CI: true

- name: Upload visual diff artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: visual-diff-results
path: |
frontend/test-results/
frontend/playwright-report/
retention-days: 14
36 changes: 36 additions & 0 deletions .github/workflows/gitleaks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Secret Scanning with Gitleaks

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

jobs:
gitleaks:
name: Scan for Secrets
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for all branches and tags

- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # Optional: for Gitleaks Pro

- name: Upload Gitleaks Report
if: failure()
uses: actions/upload-artifact@v4
with:
name: gitleaks-report
path: gitleaks-report.json
retention-days: 30
71 changes: 71 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
title = "VacciChain Gitleaks Configuration"

[extend]
# Use default gitleaks rules as base
useDefault = true

# Custom rules for VacciChain-specific secrets
[[rules]]
id = "stellar-secret-key"
description = "Stellar Secret Key"
regex = '''S[A-Z0-9]{55}'''
tags = ["stellar", "secret", "key"]

[[rules]]
id = "stellar-private-key"
description = "Stellar Private Key (alternative format)"
regex = '''(?i)(stellar[_-]?secret|stellar[_-]?private)[_-]?key["\s:=]+[A-Z0-9]{56}'''
tags = ["stellar", "secret", "key"]

[[rules]]
id = "jwt-secret"
description = "JWT Secret"
regex = '''(?i)(jwt[_-]?secret|jwt[_-]?key)["\s:=]+[A-Za-z0-9+/=]{32,}'''
tags = ["jwt", "secret"]

[[rules]]
id = "soroban-secret"
description = "Soroban Secret Key"
regex = '''(?i)(soroban[_-]?secret|soroban[_-]?key)["\s:=]+[A-Za-z0-9+/=]{32,}'''
tags = ["soroban", "secret"]

[[rules]]
id = "api-key-generic"
description = "Generic API Key"
regex = '''(?i)(api[_-]?key|apikey)["\s:=]+[A-Za-z0-9_\-]{20,}'''
tags = ["api", "key"]

# Allowlist for false positives
[allowlist]
description = "Allowlist for known false positives"
paths = [
'''\.env\.example$''',
'''env\.example$''',
'''\.md$''',
'''test_.*\.js$''',
'''.*\.test\.js$''',
'''.*\.spec\.js$''',
'''__mocks__/.*''',
]

# Allowlist specific patterns that are not real secrets
regexes = [
'''EXAMPLE_.*''',
'''TEST_.*''',
'''DEMO_.*''',
'''your-.*-here''',
'''replace-with-.*''',
'''<.*>''',
'''SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX''',
]

# Stop words that indicate example/placeholder values
stopwords = [
"example",
"sample",
"test",
"demo",
"placeholder",
"your-secret-here",
"replace-me",
]
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
hooks:
- id: gitleaks
name: Detect hardcoded secrets
description: Detect hardcoded secrets using Gitleaks
entry: gitleaks protect --verbose --redact --staged
language: golang
pass_filenames: false
Loading
Loading