@@ -2,71 +2,153 @@ name: CI
22
33on :
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
1114jobs :
12- # ── Smart contract ─────── ─────────────────────────────────────────────────
13- contract :
14- name : Contract (Rust / Soroban )
15+ # ── Frontend quality gate ─────────────────────────────────────────────────
16+ frontend :
17+ name : Frontend (lint → typecheck → build )
1518 runs-on : ubuntu-latest
16- env :
17- RUSTFLAGS : " -D warnings"
19+ defaults :
20+ run :
21+ working-directory : frontend
1822 steps :
1923 - uses : actions/checkout@v4
2024
21- - uses : dtolnay/rust-toolchain@stable
25+ - uses : actions/setup-node@v4
2226 with :
23- targets : wasm32-unknown-unknown
24- components : rustfmt, clippy
27+ node-version-file : .nvmrc
28+ cache : npm
29+ cache-dependency-path : frontend/package-lock.json
30+
31+ - name : Install dependencies
32+ run : npm ci
33+
34+ - name : Lint (fail on warnings)
35+ run : npm run lint -- --max-warnings=0
36+
37+ - name : Typecheck
38+ run : npm run typecheck
39+
40+ - name : Build
41+ run : npm run build
42+
43+ # ── Soroban ABI golden-vector drift guard ────────────────────────────────
44+ golden-vectors :
45+ name : Soroban ABI golden vectors
46+ runs-on : ubuntu-latest
47+ # Run whenever contracts or backend builder code changes
48+ if : |
49+ github.event_name == 'push' ||
50+ contains(toJson(github.event.pull_request.changed_files), 'contracts/') ||
51+ contains(toJson(github.event.pull_request.changed_files), 'backend/src/soroban/') ||
52+ contains(toJson(github.event.pull_request.changed_files), 'backend/src/tx/')
53+ defaults :
54+ run :
55+ working-directory : backend
56+ steps :
57+ - uses : actions/checkout@v4
2558
26- - uses : actions/cache @v4
59+ - uses : actions/setup-node @v4
2760 with :
28- path : |
29- ~/.cargo/registry
30- ~/.cargo/git
31- target
32- key : ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
61+ node-version : 22
3362
34- - run : cargo fmt --all -- --check
35- - run : cargo clippy --target wasm32-unknown-unknown --release -- -D warnings
36- - run : cargo test
37- - run : cargo build --target wasm32-unknown-unknown --release
63+ - run : npm install
3864
39- - name : Record wasm SHA-256
40- run : sha256sum target/wasm32-unknown-unknown/release/niffyinsure.wasm | tee niffyinsure.wasm.sha256
65+ - name : Run golden-vector encoding tests
66+ run : npx jest --testPathPattern="golden-vectors" --no-coverage
4167
42- - uses : actions/upload-artifact@v4
68+ - name : Verify vectors are up-to-date (no uncommitted drift)
69+ run : |
70+ npx ts-node ../scripts/refresh-vectors.ts
71+ if ! git diff --exit-code backend/src/soroban/golden-vectors.json; then
72+ echo "::error::golden-vectors.json is stale. Run 'npm run refresh-vectors' locally, review the diff, and commit the updated file."
73+ exit 1
74+ fi
75+
76+ # ── Smart contract ────────────────────────────────────────────────────────
77+ contract :
78+ name : Contract (Rust / Soroban)
79+ runs-on : ubuntu-latest
80+ steps :
81+ - uses : actions/checkout@v4
82+ - uses : actions/setup-node@v4
83+ with :
84+ node-version : ' 20'
85+ - name : Determine package manager
86+ id : pkgmgr
87+ run : |
88+ if [ -f pnpm-lock.yaml ]; then
89+ echo "manager=pnpm" >> "$GITHUB_OUTPUT"
90+ elif [ -f package-lock.json ]; then
91+ echo "manager=npm" >> "$GITHUB_OUTPUT"
92+ elif [ -f yarn.lock ]; then
93+ echo "manager=yarn" >> "$GITHUB_OUTPUT"
94+ else
95+ echo "manager=npm" >> "$GITHUB_OUTPUT"
96+ fi
97+ - name : Setup pnpm when needed
98+ if : steps.pkgmgr.outputs.manager == 'pnpm'
99+ uses : pnpm/action-setup@v2
100+ with :
101+ version : 8
102+ - name : Cache node modules
103+ uses : actions/cache@v4
43104 with :
44- name : niffyinsure-wasm-${{ github.sha }}
45105 path : |
46- target/wasm32-unknown-unknown/release/niffyinsure.wasm
47- niffyinsure.wasm.sha256
48- retention-days : 30
106+ node_modules
107+ ~/.pnpm-store
108+ key : ${{ runner.os }}-node-${{ steps.pkgmgr.outputs.manager }}-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml', '**/yarn.lock') }}
109+ restore-keys : ${{ runner.os }}-node-${{ steps.pkgmgr.outputs.manager }}-
110+ - name : Cache .next cache
111+ uses : actions/cache@v4
112+ with :
113+ path : .next/cache
114+ key : ${{ runner.os }}-next-cache-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml', '**/yarn.lock') }}
115+ restore-keys : ${{ runner.os }}-next-cache-
116+ - name : Install dependencies
117+ run : |
118+ if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
119+ pnpm install --frozen-lockfile
120+ else
121+ npm ci
122+ fi
123+ - name : Lint (fail on warnings)
124+ run : |
125+ if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
126+ pnpm eslint --max-warnings=0 .
127+ else
128+ npm run lint -- --max-warnings=0
129+ fi
130+ - name : TypeScript compile
131+ run : |
132+ if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
133+ pnpm tsc --noEmit
134+ else
135+ npm run build --if-present -- --noEmit
136+ fi
137+ - name : Build
138+ run : |
139+ if [ "${{ steps.pkgmgr.outputs.manager }}" = "pnpm" ]; then
140+ pnpm build
141+ else
142+ npm run build
143+ fi
49144
50- # ── Backend ───────────────────────────────────────────────────────────────
51- backend :
52- name : Backend (Node / TypeScript)
145+ unit-tests :
146+ name : Unit tests
53147 runs-on : ubuntu-latest
54148 defaults :
55149 run :
56150 working-directory : backend
57151
58- services :
59- redis :
60- image : redis:7-alpine
61- ports :
62- - 6379:6379
63- options : >-
64- --health-cmd "redis-cli ping"
65- --health-interval 5s
66- --health-timeout 3s
67- --health-retries 5
68- --health-start-period 5s
69-
70152 env :
71153 REDIS_HOST : 127.0.0.1
72154 REDIS_PORT : 6379
@@ -75,14 +157,48 @@ jobs:
75157 steps :
76158 - uses : actions/checkout@v4
77159
160+ # Install Redis directly on the runner — avoids Docker Hub rate limits entirely
161+ - name : Start Redis
162+ run : |
163+ sudo apt-get update -qq
164+ sudo apt-get install -y redis-server
165+ sudo systemctl start redis-server
166+ redis-cli ping
167+
78168 - uses : actions/setup-node@v4
79169 with :
80- node-version : 22
170+ node-version : ' 20'
171+ - name : Install dependencies
172+ run : npm ci
173+ - name : Run unit tests
174+ run : npm test
81175
82- - run : npm install
83- - run : npm run lint
84- - run : npm run build
85- - run : npm test
176+ e2e-tests :
177+ name : Playwright E2E tests
178+ runs-on : ubuntu-latest
179+ needs : frontend
180+ steps :
181+ - uses : actions/checkout@v4
182+ - uses : actions/setup-node@v4
183+ with :
184+ node-version : ' 20'
185+ - name : Install dependencies
186+ run : npm ci
187+ - name : Install Playwright browsers
188+ run : npx playwright install --with-deps
189+ - name : Run Playwright tests
190+ run : npx playwright test --reporter=html
191+ continue-on-error : true
192+ - name : Upload Playwright artifacts on failure
193+ if : failure()
194+ uses : actions/upload-artifact@v3
195+ with :
196+ name : playwright-failure-${{ github.run_id }}
197+ path : |
198+ feat/accessibility-audit
199+ sbom-backend.json
200+ sbom-frontend.json
201+ retention-days : 90
86202
87203 # ── Frontend ──────────────────────────────────────────────────────────────
88204 frontend :
@@ -102,5 +218,46 @@ jobs:
102218
103219 - run : npm ci
104220 - run : npm run lint
221+ - run : npm run check-docs
105222 - run : npm run build
106223 - run : npm test
224+
225+ # ── Accessibility (axe) ───────────────────────────────────────────────────
226+ accessibility :
227+ name : Accessibility (axe / Playwright)
228+ runs-on : ubuntu-latest
229+ defaults :
230+ run :
231+ working-directory : frontend
232+ steps :
233+ - uses : actions/checkout@v4
234+
235+ - uses : actions/setup-node@v4
236+ with :
237+ node-version : 22
238+ cache : npm
239+ cache-dependency-path : frontend/package-lock.json
240+
241+ - run : npm ci
242+ - run : npm run build
243+
244+ - name : Install Playwright browsers
245+ run : npx playwright install --with-deps chromium
246+
247+ - name : Run axe accessibility checks
248+ run : npx playwright test tests/accessibility.spec.ts --reporter=list
249+ env :
250+ BASE_URL : http://localhost:3000
251+
252+ - uses : actions/upload-artifact@v4
253+ if : failure()
254+ with :
255+ name : axe-report-${{ github.sha }}
256+ path : frontend/playwright-report/
257+ retention-days : 14
258+
259+ test-results
260+ playwright-report
261+ traces
262+ .playwright/traces
263+
0 commit comments