Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6c4f38b
Merge pull request #788 from codebestia/feat/drips-pr-wave
0xVida May 31, 2026
20cf478
feat: theme toggle, api-key usage charts, settings panel, leaderboard…
Adeolu01 May 31, 2026
2114b17
Merge pull request #789 from Adeolu01/feat/issues-738-742-748-749
0xVida May 31, 2026
5b90ed3
security: express-body-limits
dorismaduegbunam May 31, 2026
04fa2f8
feat: implement sandbox transaction builder interface (#741)
JoyLight00 May 31, 2026
64e7b5a
test: add verification, fuzzing, and cross-browser E2E coverage (#718…
jahrulezfrancis May 31, 2026
8e36d41
Merge pull request #790 from jahrulezfrancis/testing/verification-fuz…
0xVida May 31, 2026
41f8a8f
Merge pull request #791 from Luluameh/feature/oss-issues-733-734-737-741
0xVida May 31, 2026
0f11908
feat: implement load testing bypass configuration, scripts, and docum…
EDOHWARES May 31, 2026
a1df9eb
Merge pull request #792 from EDOHWARES/feat/load-testing-with-k6-and-…
0xVida May 31, 2026
2a4ce72
feat: sandbox cleanup, webhook backoff tests, and Envoy gateway confi…
testersweb May 31, 2026
493f86b
Merge pull request #793 from testersweb0-bug/feat/issues-715-717-723-…
0xVida Jun 1, 2026
03bb219
feat: cache soroban contracts, decouple notifications, tenant isolati…
Ogstevyn Jun 1, 2026
67c1523
Merge branch 'main' into TTL-based-in-memory-cache
Ogstevyn Jun 1, 2026
a2895c7
Merge pull request #794 from Ogstevyn/TTL-based-in-memory-cache
0xVida Jun 1, 2026
8813fe2
feat: distributed-tracing-integration, partition-audit-logs-table, lo…
devJaja Jun 1, 2026
377fce3
feat: harden auth, errors, and db adapters
xqcxx Jun 1, 2026
8a14b4a
Merge pull request #796 from xqcxx/feat/issue-670-672-673-698-pr
0xVida Jun 1, 2026
00b7693
Merge pull request #795 from devJaja/feat/issues-709-711-712-720
0xVida Jun 1, 2026
f747786
feat: interactive-congestion-fee-estimator-graph
dorismaduegbunam Jun 1, 2026
ca616b4
feat: wcag-21-web-accessibility-audit
dorismaduegbunam Jun 1, 2026
c949522
feat: alert-system-cooldown-and-deduplication
dorismaduegbunam Jun 1, 2026
8b42bbc
docs: PR description markdown
dorismaduegbunam Jun 1, 2026
4f84fb7
Merge branch 'main' into fix/fluid-issues
dorismaduegbunam Jun 1, 2026
13c18d7
Merge pull request #797 from dorismaduegbunam/fix/fluid-issues
0xVida Jun 1, 2026
3b2ecac
ops: dependency-scans-integration
josephchimebuka Jun 1, 2026
ea8caf4
feat: pre-flight-validation-of-inner-transaction-signer-weight
josephchimebuka Jun 1, 2026
f52de92
Merge pull request #798 from josephchimebuka/feat/issues-674-686-depe…
0xVida Jun 1, 2026
76387d8
Integrate HashiCorp Vault for Secure Fee Payer Secret Management
Agbeleshe Jun 1, 2026
3153e9e
Merge pull request #799 from Agbeleshe/newbranch
0xVida Jun 1, 2026
0516a47
feat: resilience & error handling - issues #688, #691, #692, #687
Dev-AdeTutu Jun 1, 2026
3c09d6c
Merge pull request #800 from Dev-AdeTutu/feat/resilience-error-handli…
0xVida Jun 1, 2026
5d66d42
some changes
devfoma Jun 2, 2026
b4d12e7
test: add muxed address integration test
devfoma Jun 2, 2026
b511beb
feat: live configuration reload without restart using RwLock
devfoma Jun 2, 2026
e3dc7e6
test: add WASM vs Native Node crypto benchmarks
devfoma Jun 2, 2026
317372f
feat: add Redis cluster failure rate limiter fallback
devfoma Jun 2, 2026
20671a5
Merge pull request #801 from devfoma/feat/sponsorship-limiter-hardening
0xVida Jun 2, 2026
a52415a
chore: bump the minor-and-patch group across 1 directory with 7 updates
dependabot[bot] Jun 19, 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
69 changes: 69 additions & 0 deletions .github/workflows/dependency-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Dependency Vulnerability Audit (fluid-server)

on:
pull_request:
paths:
- "fluid-server/**"
- ".github/workflows/dependency-audit.yml"
push:
branches:
- main
paths:
- "fluid-server/**"
- ".github/workflows/dependency-audit.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
dependency-audit:
name: ${{ matrix.scanner }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- scanner: cargo-audit
working-directory: fluid-server
- scanner: npm-audit
working-directory: fluid-server/wasm-demo

defaults:
run:
working-directory: ${{ matrix.working-directory }}

steps:
- uses: actions/checkout@v4

- name: cargo-audit (Rust)
if: matrix.scanner == 'cargo-audit'
run: |
cargo install cargo-audit --locked
cargo audit --version
cargo audit --json > "${RUNNER_TEMP}/cargo-audit-report.json"
cargo audit --deny warnings

- name: Upload cargo-audit report
if: matrix.scanner == 'cargo-audit' && always()
uses: actions/upload-artifact@v4
with:
name: cargo-audit-report
path: ${{ runner.temp }}/cargo-audit-report.json
if-no-files-found: warn

- name: npm audit (wasm-demo)
if: matrix.scanner == 'npm-audit'
run: |
npm --version
npm ci
npm audit --json > "${RUNNER_TEMP}/npm-audit-report.json" || true
npm audit --audit-level=high

- name: Upload npm-audit report
if: matrix.scanner == 'npm-audit' && always()
uses: actions/upload-artifact@v4
with:
name: npm-audit-report
path: ${{ runner.temp }}/npm-audit-report.json
if-no-files-found: warn
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["fluid-core", "fluid-server"]
members = ["fluid-server"]
resolver = "2"

[workspace.package]
Expand Down
118 changes: 118 additions & 0 deletions PR_DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Pull Request Description - Fluid Platform Enhancements, Security and Resilience Polish

## Title
feat: security-limits-congestion-graph-wcag-audit-and-alert-cooldowns

## Summary

This PR addresses and resolves four distinct key issues across the `server`, `admin-dashboard`, and `fluid-server` directories. All changes are thoroughly tested with zero regressions.

### 1. Express Endpoints Strict Payload Limits (`server/`)
- Enforces strict request body content-length limits of **256KB** using `express.json({ limit: "256kb" })`.
- Intercepts body-parser `PayloadTooLargeError` errors in the global error handler (`server/src/middleware/errorHandler.ts`) to return a clean JSON payload and HTTP **413 Payload too large** status.
- Added comprehensive Vitest integration tests verifying both compliant payloads and oversized blocks are rejected.

### 2. Interactive Congestion Fee Estimator Graph (`admin-dashboard/`)
- Implemented a premium, highly interactive Recharts-based 24-hour congestion curve and projected fee cost visualization under `admin-dashboard/src/fees/components/CongestionFeeEstimatorGraph.tsx`.
- Features real-time parameter controls for base fee and region alongside a **Surge Simulator** slider allowing manual traffic simulation over selected hours with instant graph and calculation updates.
- Fully integrated onto the main dashboard and backed by comprehensive Vitest component tests.

### 3. WCAG 2.1 Web Accessibility Auditing Engine (`admin-dashboard/`)
- Designed and built a robust programmatic accessibility checking engine (`admin-dashboard/src/compliance/accessibility/WCAGAudit.ts`) conforming to **WCAG 2.1 Level AA** standards.
- Supports relative luminance color contrast ratio math, keyboard focusability tabindex checking, screen reader alt tag presence, paired input labels, and structural heading sequence audits.
- Implemented a standard `ComplianceHook` integration and created full unit test coverage using the native Node test runner.

### 4. Stateful Cooldown & Deduplication for SMTP/Slack Alerts (`fluid-server/`)
- Hardens the alert system (`fluid-server/src/notifications/alertSystem.ts`) to prevent operator alert flooding during balance drops by enforcing a stateful **6-hour cooldown**.
- Implemented a **Critical Drop Override** (Catastrophic Bypass) which immediately fires an emergency notification if the balance has plummeted by 50% or more since the last alerted state.
- Tracks Slack and SMTP channels independently and backed by a comprehensive unit test suite in Vitest.

---

## Verification & Test Results

### 1. Express Endpoints Payload Limit Tests
```bash
RUN v4.1.4 C:/Users/U S E R/Drips/Doris/fluid/server

✓ src/test/payloadLimit.test.ts (2 tests) 146ms

Test Files 1 passed (1)
Tests 2 passed (2)
Duration 2.46s
```

### 2. Interactive Congestion Fee Estimator Graph Component Tests
```bash
RUN v4.1.4 C:/Users/U S E R/Drips/Doris/fluid/admin-dashboard

✓ src/fees/__tests__/CongestionFeeEstimatorGraph.test.tsx (4 tests) 993ms

Test Files 1 passed (1)
Tests 4 passed (4)
Duration 16.25s
```

### 3. WCAG 2.1 Accessibility Audit Compliance Engine Tests
```bash
✔ WCAGAudit calculates relative luminance of black and white exactly (33.1534ms)
✔ WCAGAudit calculates contrast ratio of black vs white exactly as 21:1 (1.1711ms)
✔ WCAGAudit verifies compliant and non-compliant contrast ratios (0.5741ms)
✔ WCAGAudit audits heading sequences and flags skipped levels (4.0104ms)
✔ WCAGAudit audits negative tabIndexes for keyboard accessibility (0.3881ms)
✔ WCAGAudit audits images for alt descriptive labels (2.0307ms)
✔ WCAGAudit audits form controls for valid label pairings (1.3858ms)
✔ WCAGAccessibilityHook executes through compliance framework (0.7105ms)
✔ WCAGAccessibilityHook handles null, undefined, and non-string inputs gracefully (0.4626ms)
ℹ tests 9
ℹ suites 0
ℹ pass 9
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 447.197
```

### 4. Alert Stateful Cooldown and Critical Bypass Tests
```bash
RUN v4.1.4 C:/Users/U S E R/Drips/Doris/fluid

✓ fluid-server/src/notifications/alertSystem.test.ts (7 tests) 22ms

Test Files 1 passed (1)
Tests 7 passed (7)
Duration 1.03s
```

---

## Changed and Added Files

```
server/
├── src/index.ts (Enforce 256KB limits)
├── src/middleware/errorHandler.ts (Intercept 413)
└── src/test/payloadLimit.test.ts [NEW] (Supertest integration)

admin-dashboard/
├── package.json (Updated test:unit command)
├── app/admin/dashboard/page.tsx (Render new graph widget)
├── src/compliance/index.ts (Export accessibility hook)
├── src/compliance/accessibility/WCAGAudit.ts [NEW] (Relative luminance math, element scan)
├── src/compliance/hooks/wcag-accessibility-hook.ts [NEW] (Compliance integration)
├── src/compliance/__tests__/wcag-accessibility.test.ts [NEW] (Node tests)
├── src/fees/index.ts (Export new graph)
├── src/fees/components/CongestionFeeEstimatorGraph.tsx [NEW] (Interactive graph and simulator)
└── src/fees/__tests__/CongestionFeeEstimatorGraph.test.tsx [NEW] (Vitest component tests)

fluid-server/
├── src/notifications/alertSystem.ts [NEW] (Stateful cooldown and bypass override)
└── src/notifications/alertSystem.test.ts [NEW] (Stateful alert system tests)

docs/
├── localized-fee-estimation.md (Updated details)
├── compliance-hooks.md (Updated architectural outline)
├── wcag-21-web-accessibility-audit.md [NEW] (Accessibility audit documentation)
└── alert-system-cooldown-deduplication.md [NEW] (Alert system cooldown documentation)
```
3 changes: 3 additions & 0 deletions admin-dashboard/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

# testing
/coverage
/playwright-report/
/test-results/
/e2e/.auth/

# next.js
/.next/
Expand Down
39 changes: 30 additions & 9 deletions admin-dashboard/app/admin/api-keys/page.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import { auth } from "@/auth";
import Link from "next/link";
import { ApiKeysTable } from "@/components/dashboard/ApiKeysTable";
import { ApiKeyUsageCharts } from "@/components/dashboard/ApiKeyUsageCharts";
import { getApiKeysPageData } from "@/lib/api-keys-data";
import { buildApiKeyUsageStats } from "@/lib/api-key-usage-data";

export default async function AdminApiKeysPage() {
const session = await auth();
const { keys, source, serverUrl, adminToken } = await getApiKeysPageData();
const usageStats = buildApiKeyUsageStats(keys);

return (
<main className="min-h-screen bg-slate-100">
<div className="border-b border-slate-200 bg-white/90 backdrop-blur">
<main className="min-h-screen bg-background">
<div className="border-b border-border/50 bg-background/90 backdrop-blur sticky top-0 z-10">
<div className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div>
<p className="text-sm font-semibold uppercase tracking-[0.25em] text-sky-600">
<p className="text-[10px] font-black uppercase tracking-[0.3em] text-primary">
Fluid Admin
</p>
<h1 className="mt-2 text-3xl font-bold text-slate-900">
<h1 className="mt-2 text-3xl font-bold text-foreground">
API Key Management
</h1>
<p className="mt-2 max-w-2xl text-sm text-slate-600">
<p className="mt-2 max-w-2xl text-sm text-muted-foreground">
Revoke keys immediately if a key is leaked or a dApp is abusive.
</p>
</div>
<div className="flex items-center gap-4">
<div className="rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
<div className="font-medium text-slate-900">
<div className="rounded-2xl border border-border/50 bg-card px-4 py-3 text-sm text-muted-foreground">
<div className="font-medium text-foreground">
{session?.user?.email}
</div>
<div>
Expand All @@ -34,7 +37,7 @@ export default async function AdminApiKeysPage() {
</div>
<Link
href="/admin/dashboard"
className="inline-flex min-h-10 items-center justify-center rounded-full border border-slate-300 bg-white px-4 text-sm font-semibold text-slate-700 transition hover:border-slate-400 hover:bg-slate-50"
className="inline-flex min-h-10 items-center justify-center rounded-full border border-border/50 bg-card px-4 text-sm font-semibold text-foreground transition hover:bg-muted"
>
Back to dashboard
</Link>
Expand All @@ -43,12 +46,30 @@ export default async function AdminApiKeysPage() {
</div>
</div>

<div className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
<div className="mx-auto max-w-7xl space-y-8 px-4 py-8 sm:px-6 lg:px-8">
<ApiKeysTable
initialKeys={keys}
serverUrl={serverUrl}
adminToken={adminToken}
/>

<section aria-labelledby="usage-charts-heading">
<h2
id="usage-charts-heading"
className="mb-4 text-xl font-bold tracking-tight text-foreground"
>
Usage Analytics
</h2>
<p className="mb-6 text-sm text-muted-foreground">
Per-key performance metrics including request counts, failure rates, and fee cost.
{source === "sample" && (
<span className="ml-2 font-medium text-amber-600">
Showing sample data — connect a live server to see real metrics.
</span>
)}
</p>
<ApiKeyUsageCharts stats={usageStats} />
</section>
</div>
</main>
);
Expand Down
5 changes: 5 additions & 0 deletions admin-dashboard/app/admin/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Coins, CheckCircle, Wallet, Zap } from "lucide-react";
import { getSpendForecastData } from "@/lib/spend-chart-data";
import { getFeeMultiplierData } from "@/lib/fee-multiplier-data";
import { FeeEstimatorWidget } from "@/components/dashboard/FeeEstimatorWidget";
import { CongestionFeeEstimatorGraph } from "@/src/fees";
import { ExpenseBreakdown } from "@/components/dashboard/ExpenseBreakdown";
import { getExpenseBreakdownData } from "@/lib/expense-breakdown-data";
import { TelemetryConsentSettings } from "@/components/dashboard/TelemetryConsentSettings";
Expand Down Expand Up @@ -141,6 +142,10 @@ export default async function AdminDashboard() {
<FeeEstimatorWidget />
</section>

<section className="mt-6">
<CongestionFeeEstimatorGraph />
</section>

<section className="mt-6">
<TelemetryConsentSettings />
</section>
Expand Down
2 changes: 2 additions & 0 deletions admin-dashboard/app/admin/sandbox/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { redirect } from "next/navigation";
import Link from "next/link";
import { getSandboxPageData } from "@/lib/sandbox-data";
import { SandboxPanel } from "@/components/dashboard/SandboxPanel";
import { SandboxTransactionBuilder } from "@/components/dashboard/SandboxTransactionBuilder";

export default async function AdminSandboxPage() {
const session = await auth();
Expand Down Expand Up @@ -45,6 +46,7 @@ export default async function AdminSandboxPage() {
sandboxHorizonUrl={sandboxHorizonUrl}
sandboxRateLimitMax={sandboxRateLimitMax}
/>
<SandboxTransactionBuilder />
</main>
</div>
);
Expand Down
Loading
Loading