Skip to content

Commit be3afea

Browse files
authored
Merge branch 'main' into feat/rate-limiting-abuse-protection
2 parents 9500808 + 3c90de3 commit be3afea

44 files changed

Lines changed: 4797 additions & 225 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 97 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ name: CI
22

33
on:
44
push:
5-
branches: [main, "feat/**", "fix/**"]
5+
branches:
6+
- main
67
pull_request:
8+
branches:
9+
- main
710

8-
env:
9-
CARGO_TERM_COLOR: always
11+
permissions:
12+
contents: read
1013

1114
jobs:
1215
# ── Soroban ABI golden-vector drift guard ────────────────────────────────
@@ -46,75 +49,78 @@ jobs:
4649
contract:
4750
name: Contract (Rust / Soroban)
4851
runs-on: ubuntu-latest
49-
env:
50-
RUSTFLAGS: "-D warnings"
5152
steps:
5253
- uses: actions/checkout@v4
53-
54-
- uses: dtolnay/rust-toolchain@stable
55-
with:
56-
targets: wasm32-unknown-unknown
57-
components: rustfmt, clippy
58-
59-
- uses: actions/cache@v4
54+
- uses: actions/setup-node@v4
6055
with:
61-
path: |
62-
~/.cargo/registry
63-
~/.cargo/git
64-
target
65-
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
66-
67-
- run: cargo fmt --all -- --check
68-
- run: cargo clippy --target wasm32-unknown-unknown --release -- -D warnings
69-
- run: cargo test
70-
- run: cargo build --target wasm32-unknown-unknown --release
71-
72-
- name: Record wasm SHA-256
73-
run: sha256sum target/wasm32-unknown-unknown/release/niffyinsure.wasm | tee niffyinsure.wasm.sha256
74-
75-
- name: Simulate wasm drift (staging acceptance test)
56+
node-version: '20'
57+
- name: Determine package manager
58+
id: pkgmgr
7659
run: |
77-
ACTUAL=$(cat niffyinsure.wasm.sha256 | awk '{print $1}')
78-
EXPECTED=$(jq -r '.contracts[0].expectedWasmHash' contracts/deployment-registry.json)
79-
# In CI the registry holds a placeholder; drift is detected when they differ.
80-
# In staging, set NIFFYINSURE_EXPECTED_WASM_HASH to a known-wrong value to
81-
# verify the alert path fires. Exit 0 here — alerting is runtime, not build-time.
82-
if [ "$EXPECTED" = "\${NIFFYINSURE_EXPECTED_WASM_HASH}" ]; then
83-
echo "Registry uses env placeholder — skipping drift comparison in CI"
84-
elif [ "$ACTUAL" != "$EXPECTED" ]; then
85-
echo "::warning::Wasm drift detected: expected=$EXPECTED actual=$ACTUAL"
60+
if [ -f pnpm-lock.yaml ]; then
61+
echo "manager=pnpm" >> "$GITHUB_OUTPUT"
62+
elif [ -f package-lock.json ]; then
63+
echo "manager=npm" >> "$GITHUB_OUTPUT"
64+
elif [ -f yarn.lock ]; then
65+
echo "manager=yarn" >> "$GITHUB_OUTPUT"
8666
else
87-
echo "Wasm hash matches registry: $ACTUAL"
67+
echo "manager=npm" >> "$GITHUB_OUTPUT"
8868
fi
89-
90-
- uses: actions/upload-artifact@v4
69+
- name: Setup pnpm when needed
70+
if: steps.pkgmgr.outputs.manager == 'pnpm'
71+
uses: pnpm/action-setup@v2
72+
with:
73+
version: 8
74+
- name: Cache node modules
75+
uses: actions/cache@v4
9176
with:
92-
name: niffyinsure-wasm-${{ github.sha }}
9377
path: |
94-
target/wasm32-unknown-unknown/release/niffyinsure.wasm
95-
niffyinsure.wasm.sha256
96-
retention-days: 30
78+
node_modules
79+
~/.pnpm-store
80+
key: ${{ runner.os }}-node-${{ steps.pkgmgr.outputs.manager }}-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml', '**/yarn.lock') }}
81+
restore-keys: ${{ runner.os }}-node-${{ steps.pkgmgr.outputs.manager }}-
82+
- name: Cache .next cache
83+
uses: actions/cache@v4
84+
with:
85+
path: .next/cache
86+
key: ${{ runner.os }}-next-cache-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml', '**/yarn.lock') }}
87+
restore-keys: ${{ runner.os }}-next-cache-
88+
- name: Install dependencies
89+
run: |
90+
if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
91+
pnpm install --frozen-lockfile
92+
else
93+
npm ci
94+
fi
95+
- name: Lint (fail on warnings)
96+
run: |
97+
if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
98+
pnpm eslint --max-warnings=0 .
99+
else
100+
npm run lint -- --max-warnings=0
101+
fi
102+
- name: TypeScript compile
103+
run: |
104+
if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
105+
pnpm tsc --noEmit
106+
else
107+
npm run build --if-present -- --noEmit
108+
fi
109+
- name: Build
110+
run: |
111+
if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
112+
pnpm build
113+
else
114+
npm run build
115+
fi
97116
98-
# ── Backend ───────────────────────────────────────────────────────────────
99-
backend:
100-
name: Backend (Node / TypeScript)
117+
unit-tests:
118+
name: Unit tests
101119
runs-on: ubuntu-latest
102120
defaults:
103121
run:
104122
working-directory: backend
105123

106-
services:
107-
redis:
108-
image: redis:7-alpine
109-
ports:
110-
- 6379:6379
111-
options: >-
112-
--health-cmd "redis-cli ping"
113-
--health-interval 5s
114-
--health-timeout 3s
115-
--health-retries 5
116-
--health-start-period 5s
117-
118124
env:
119125
REDIS_HOST: 127.0.0.1
120126
REDIS_PORT: 6379
@@ -123,84 +129,45 @@ jobs:
123129
steps:
124130
- uses: actions/checkout@v4
125131

132+
# Install Redis directly on the runner — avoids Docker Hub rate limits entirely
133+
- name: Start Redis
134+
run: |
135+
sudo apt-get update -qq
136+
sudo apt-get install -y redis-server
137+
sudo systemctl start redis-server
138+
redis-cli ping
139+
126140
- uses: actions/setup-node@v4
127141
with:
128-
node-version: 22
129-
130-
- run: npm install
131-
- run: npm run lint
132-
- run: npm run build
133-
- run: npm test
134-
135-
# ── Dependency audit / supply-chain ─────────────────────────────────────
136-
# Policy: CRITICAL CVEs fail the build. HIGH CVEs produce a warning and
137-
# must be triaged within 7 days. Accepted risks require a signed-off entry
138-
# in docs/ops/audit-exceptions.md before the override label is applied.
139-
# Override process:
140-
# 1. Engineer opens a PR adding the CVE to audit-exceptions.md with
141-
# justification, mitigations, and a review-by date.
142-
# 2. A second engineer approves the PR.
143-
# 3. Add the GitHub label `audit-exception-approved` to the failing PR.
144-
# 4. Re-run this job — it will pass once the exception is documented.
145-
dependency-audit:
146-
name: Dependency Audit (npm / SBOM)
142+
node-version: '20'
143+
- name: Install dependencies
144+
run: npm ci
145+
- name: Run unit tests
146+
run: npm test
147+
148+
e2e-tests:
149+
name: Playwright E2E tests
147150
runs-on: ubuntu-latest
151+
needs: quality-build
148152
steps:
149153
- uses: actions/checkout@v4
150-
151154
- uses: actions/setup-node@v4
152155
with:
153-
node-version: 22
154-
155-
- name: Audit backend dependencies
156-
working-directory: backend
157-
run: |
158-
npm install --ignore-scripts
159-
# Fail on critical; warn on high (exit 0 so we can capture output)
160-
npm audit --audit-level=critical
161-
npm audit --audit-level=high || echo "::warning::High-severity advisories found — triage within 7 days per audit policy"
162-
163-
- name: Audit frontend dependencies
164-
working-directory: frontend
165-
run: |
166-
npm ci --ignore-scripts
167-
npm audit --audit-level=critical
168-
npm audit --audit-level=high || echo "::warning::High-severity advisories found — triage within 7 days per audit policy"
169-
170-
- name: Generate SBOM (backend)
171-
working-directory: backend
172-
run: npx --yes @cyclonedx/cyclonedx-npm --output-format JSON --output-file ../sbom-backend.json
173-
174-
- name: Generate SBOM (frontend)
175-
working-directory: frontend
176-
run: npx --yes @cyclonedx/cyclonedx-npm --output-format JSON --output-file ../sbom-frontend.json
177-
178-
- uses: actions/upload-artifact@v4
156+
node-version: '20'
157+
- name: Install dependencies
158+
run: npm ci
159+
- name: Install Playwright browsers
160+
run: npx playwright install --with-deps
161+
- name: Run Playwright tests
162+
run: npx playwright test --reporter=html
163+
continue-on-error: true
164+
- name: Upload Playwright artifacts on failure
165+
if: failure()
166+
uses: actions/upload-artifact@v3
179167
with:
180-
name: sbom-${{ github.sha }}
168+
name: playwright-failure-${{ github.run_id }}
181169
path: |
182-
sbom-backend.json
183-
sbom-frontend.json
184-
retention-days: 90
185-
186-
# ── Frontend ──────────────────────────────────────────────────────────────
187-
frontend:
188-
name: Frontend (Next.js / TypeScript)
189-
runs-on: ubuntu-latest
190-
defaults:
191-
run:
192-
working-directory: frontend
193-
steps:
194-
- uses: actions/checkout@v4
195-
196-
- uses: actions/setup-node@v4
197-
with:
198-
node-version: 22
199-
cache: npm
200-
cache-dependency-path: frontend/package-lock.json
201-
202-
- run: npm ci
203-
- run: npm run lint
204-
- run: npm run check-docs
205-
- run: npm run build
206-
- run: npm test
170+
test-results
171+
playwright-report
172+
traces
173+
.playwright/traces

0 commit comments

Comments
 (0)