Skip to content

Commit f97919e

Browse files
authored
Merge branch 'main' into feat/policy-expired-event
2 parents 10339ed + 90b6507 commit f97919e

307 files changed

Lines changed: 35892 additions & 6676 deletions

File tree

Some content is hidden

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

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Copy this file to .env and fill in values.
22
# .env is gitignored — never commit secrets.
3+
#
4+
# CONVENTION:
5+
# NEXT_PUBLIC_* → safe to expose in the browser bundle
6+
# (no prefix) → server-only; NEVER import in client components
7+
# use `import '@/lib/server-guard'` to enforce this
38

49
# ── Redis ─────────────────────────────────────────────────────────────────────
510
REDIS_HOST=127.0.0.1

.github/workflows/ci.yml

Lines changed: 101 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,41 @@ permissions:
1212
contents: read
1313

1414
jobs:
15+
# ── Frontend quality gate ─────────────────────────────────────────────────
16+
frontend:
17+
name: Frontend (lint → typecheck → build → test)
18+
runs-on: ubuntu-latest
19+
defaults:
20+
run:
21+
working-directory: frontend
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: actions/setup-node@v4
26+
with:
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+
- name: Test
44+
run: npm test
45+
1546
# ── Soroban ABI golden-vector drift guard ────────────────────────────────
1647
golden-vectors:
1748
name: Soroban ABI golden vectors
1849
runs-on: ubuntu-latest
19-
# Run whenever contracts or backend builder code changes
2050
if: |
2151
github.event_name == 'push' ||
2252
contains(toJson(github.event.pull_request.changed_files), 'contracts/') ||
@@ -45,77 +75,37 @@ jobs:
4575
exit 1
4676
fi
4777
48-
# ── Smart contract ────────────────────────────────────────────────────────
78+
# ── Smart contract (Rust / Soroban) ──────────────────────────────────────
4979
contract:
5080
name: Contract (Rust / Soroban)
5181
runs-on: ubuntu-latest
5282
steps:
5383
- uses: actions/checkout@v4
54-
- uses: actions/setup-node@v4
55-
with:
56-
node-version: '20'
57-
- name: Determine package manager
58-
id: pkgmgr
59-
run: |
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"
66-
else
67-
echo "manager=npm" >> "$GITHUB_OUTPUT"
68-
fi
69-
- name: Setup pnpm when needed
70-
if: steps.pkgmgr.outputs.manager == 'pnpm'
71-
uses: pnpm/action-setup@v2
84+
85+
- name: Install Rust toolchain
86+
uses: dtolnay/rust-toolchain@stable
7287
with:
73-
version: 8
74-
- name: Cache node modules
88+
targets: wasm32-unknown-unknown
89+
90+
- name: Cache Rust build artifacts
7591
uses: actions/cache@v4
7692
with:
7793
path: |
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
94+
~/.cargo/registry
95+
~/.cargo/git
96+
target/
97+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
98+
restore-keys: ${{ runner.os }}-cargo-
11699

100+
- name: Run contract tests
101+
run: cargo test --workspace --features testutils
102+
103+
- name: Build WASM (release)
104+
run: cargo build --release --target wasm32-unknown-unknown --workspace
105+
106+
# ── Backend unit tests ────────────────────────────────────────────────────
117107
unit-tests:
118-
name: Unit tests
108+
name: Backend unit tests
119109
runs-on: ubuntu-latest
120110
defaults:
121111
run:
@@ -129,7 +119,6 @@ jobs:
129119
steps:
130120
- uses: actions/checkout@v4
131121

132-
# Install Redis directly on the runner — avoids Docker Hub rate limits entirely
133122
- name: Start Redis
134123
run: |
135124
sudo apt-get update -qq
@@ -140,34 +129,78 @@ jobs:
140129
- uses: actions/setup-node@v4
141130
with:
142131
node-version: '20'
132+
143133
- name: Install dependencies
144134
run: npm ci
135+
145136
- name: Run unit tests
146137
run: npm test
147138

139+
# ── Playwright E2E tests ──────────────────────────────────────────────────
148140
e2e-tests:
149141
name: Playwright E2E tests
150142
runs-on: ubuntu-latest
151-
needs: quality-build
143+
needs: frontend
144+
defaults:
145+
run:
146+
working-directory: frontend
152147
steps:
153148
- uses: actions/checkout@v4
149+
154150
- uses: actions/setup-node@v4
155151
with:
156152
node-version: '20'
153+
157154
- name: Install dependencies
158155
run: npm ci
156+
159157
- name: Install Playwright browsers
160158
run: npx playwright install --with-deps
159+
161160
- name: Run Playwright tests
162161
run: npx playwright test --reporter=html
163162
continue-on-error: true
163+
164164
- name: Upload Playwright artifacts on failure
165165
if: failure()
166-
uses: actions/upload-artifact@v3
166+
uses: actions/upload-artifact@v4
167167
with:
168168
name: playwright-failure-${{ github.run_id }}
169169
path: |
170-
test-results
171-
playwright-report
172-
traces
173-
.playwright/traces
170+
test-results/
171+
playwright-report/
172+
retention-days: 14
173+
174+
# ── Accessibility (axe) ───────────────────────────────────────────────────
175+
accessibility:
176+
name: Accessibility (axe / Playwright)
177+
runs-on: ubuntu-latest
178+
defaults:
179+
run:
180+
working-directory: frontend
181+
steps:
182+
- uses: actions/checkout@v4
183+
184+
- uses: actions/setup-node@v4
185+
with:
186+
node-version: 22
187+
cache: npm
188+
cache-dependency-path: frontend/package-lock.json
189+
190+
- run: npm ci
191+
- run: npm run build
192+
193+
- name: Install Playwright browsers
194+
run: npx playwright install --with-deps chromium
195+
196+
- name: Run axe accessibility checks
197+
run: npx playwright test tests/accessibility.spec.ts --reporter=list
198+
env:
199+
BASE_URL: http://localhost:3000
200+
201+
- uses: actions/upload-artifact@v4
202+
if: failure()
203+
with:
204+
name: axe-report-${{ github.sha }}
205+
path: frontend/playwright-report/
206+
retention-days: 14

.github/workflows/coverage.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Coverage
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
contract-coverage:
16+
name: Contract coverage (≥ 95%)
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Install Rust toolchain
22+
uses: dtolnay/rust-toolchain@stable
23+
with:
24+
components: llvm-tools-preview
25+
26+
- name: Cache Rust build artifacts
27+
uses: actions/cache@v4
28+
with:
29+
path: |
30+
~/.cargo/registry
31+
~/.cargo/git
32+
target/
33+
key: ${{ runner.os }}-cargo-cov-${{ hashFiles('**/Cargo.lock') }}
34+
restore-keys: ${{ runner.os }}-cargo-cov-
35+
36+
- name: Install cargo-llvm-cov
37+
uses: taiki-e/install-action@cargo-llvm-cov
38+
39+
- name: Run coverage
40+
run: |
41+
cargo llvm-cov \
42+
--workspace \
43+
--features testutils \
44+
--lcov \
45+
--output-path lcov.info
46+
47+
- name: Enforce 95% line coverage threshold
48+
run: |
49+
cargo llvm-cov \
50+
--workspace \
51+
--features testutils \
52+
--summary-only 2>&1 | tee coverage-summary.txt
53+
54+
LINE_COV=$(grep -oP 'Lines\s+\K[\d.]+(?=%)' coverage-summary.txt | head -1)
55+
echo "Line coverage: ${LINE_COV}%"
56+
57+
# Use awk for float comparison (bash can't do floats)
58+
PASS=$(awk -v cov="$LINE_COV" 'BEGIN { print (cov >= 95.0) ? "yes" : "no" }')
59+
if [ "$PASS" != "yes" ]; then
60+
echo "::error::Coverage ${LINE_COV}% is below the required 95% threshold."
61+
exit 1
62+
fi
63+
echo "Coverage check passed: ${LINE_COV}%"
64+
65+
- name: Upload coverage report
66+
uses: actions/upload-artifact@v4
67+
with:
68+
name: lcov-${{ github.sha }}
69+
path: lcov.info
70+
retention-days: 30

0 commit comments

Comments
 (0)