Skip to content

Feature: CrowdSec Dashboard Integration with Observable Metrics#887

Merged
Wikid82 merged 58 commits intodevelopmentfrom
feature/beta-release
Apr 6, 2026
Merged

Feature: CrowdSec Dashboard Integration with Observable Metrics#887
Wikid82 merged 58 commits intodevelopmentfrom
feature/beta-release

Conversation

@Wikid82
Copy link
Copy Markdown
Owner

@Wikid82 Wikid82 commented Mar 25, 2026

Summary

Adds a CrowdSec analytics dashboard to Charon's Security section, making security posture observable directly from the UI. Previously, viewing attack trends, scenario breakdowns, ban history, or top offenders required SSH access and running cscli commands. This feature closes that visibility gap.

Closes #26


What Changed

Backend: Aggregation API + Model Enrichment

  • 6 new API endpoints under /api/v1/admin/crowdsec/ (admin auth required):
    • GET /dashboard/summary — aggregate counts (total decisions, active bans, unique IPs, top scenario, trend %)
    • GET /dashboard/timeline — time-bucketed decision counts with configurable intervals (5m/15m/1h/6h/1d)
    • GET /dashboard/top-ips — top attacking IPs ranked by decision count
    • GET /dashboard/scenarios — scenario breakdown with percentages
    • GET /alerts — paginated LAPI alerts with cscli fallback
    • GET /decisions/export — CSV/JSON export with CSV injection protection and 100k row limit
  • SecurityDecision model enriched with Scenario, Country, ExpiresAt fields + 3 composite indexes for performant aggregation on large tables
  • In-memory TTL cache (30s summary/alerts, 60s timeline/charts) with automatic invalidation on ban/unban operations
  • Hybrid data sourcing: active decision counts from LAPI (authoritative), historical aggregations from SQLite, graceful fallback when LAPI is unreachable
  • Race condition fixes: moved validateCrowdsecLAPIBaseURLFunc from package-level mutable to instance field on CrowdsecHandler; consolidated gin.SetMode into TestMain entrypoint

Frontend: Dashboard UI + Charts

  • CrowdSec Dashboard page with Radix UI Tabs integration alongside existing Configuration tab
  • 4 summary stat cards with trend indicators and aria-live="polite" for screen readers
  • Ban timeline chart (Recharts AreaChart) showing ban/captcha events over time
  • Top attacking IPs chart (Recharts horizontal BarChart) with top 10 offenders
  • Scenario breakdown chart (Recharts PieChart) with percentage labels
  • Active decisions table displaying IP, alerts count, last seen, country with full Go duration parsing
  • Time range selector (1h/6h/24h/7d/30d) using role="radiogroup" with roving tabindex and arrow key navigation
  • Alerts feed with pagination, page reset on range change, and guarded edge cases
  • Export dropdown (CSV/JSON) with ARIA menu pattern, blob validation, and URL cleanup
  • Code-split via React.lazy() + <Suspense> to avoid loading Recharts on the Configuration tab
  • i18n across 5 locales (en, de, fr, es, zh)
  • Recharts added as dependency (SVG-based, accessible, tree-shakeable)

Testing

  • ~60 backend test functions covering all 6 endpoints, cache behavior, input validation, error paths, race conditions, and edge cases
  • ~68 frontend unit tests (Vitest) across 8 test files for all dashboard components and hooks
  • Playwright E2E tests for dashboard tab navigation, chart rendering, and export flows
  • Backend coverage: 88.4% (threshold: 87%)
  • Frontend coverage: 90%+ (threshold: 85%)
  • Patch coverage: 98.1% (threshold: 90%)

Stability Fixes

  • Eliminated data race on validateCrowdsecLAPIBaseURLFunc by moving to handler struct field
  • Consolidated gin.SetMode(gin.TestMode) into single TestMain entrypoint across 80+ test functions
  • Removed unsafe os.Setenv/os.Unsetenv calls from parallel cookie tests

New API Endpoints

Method Path Description
GET /admin/crowdsec/dashboard/summary?range=24h Aggregate stats with trend
GET /admin/crowdsec/dashboard/timeline?range=24h&interval=1h Time-bucketed ban counts
GET /admin/crowdsec/dashboard/top-ips?range=24h&limit=10 Top attacking IPs
GET /admin/crowdsec/dashboard/scenarios?range=24h Scenario breakdown
GET /admin/crowdsec/alerts?range=24h&limit=20&offset=0 Paginated LAPI alerts
GET /admin/crowdsec/decisions/export?format=csv&range=24h CSV/JSON export

All endpoints require admin authentication. Time ranges: 1h, 6h, 24h, 7d, 30d.


Frontend Components

CrowdSecConfig.tsx (Radix Tabs)
├── Tab: Configuration (existing, unchanged)
└── Tab: Dashboard (new, lazy-loaded)
    └── CrowdSecDashboard.tsx
        ├── DashboardTimeRangeSelector
        ├── DashboardSummaryCards (4 stat cards)
        ├── BanTimelineChart (Recharts AreaChart)
        ├── TopAttackingIPsChart (Recharts BarChart)
        ├── ScenarioBreakdownChart (Recharts PieChart)
        ├── ActiveDecisionsTable
        ├── AlertsList (paginated feed)
        └── DecisionsExportButton (CSV/JSON dropdown)

Accessibility

  • All interactive elements keyboard navigable with visible focus indicators
  • Time range selector uses role="radiogroup" / role="radio" with aria-checked, roving tabindex, Arrow/Home/End key support
  • Summary cards use aria-live="polite" for dynamic updates
  • Charts use role="img" with descriptive aria-label
  • Export menu uses ARIA menu pattern with aria-controls
  • WCAG 2.2 AA contrast verified for all chart colors
  • Skip navigation and semantic landmarks maintained

Security

  • No LAPI keys exposed in any API response
  • SSRF-safe LAPI URL validation via existing validateCrowdsecLAPIBaseURL
  • CSV export includes injection protection (cells starting with =, +, -, @ are escaped)
  • Export capped at 100k rows to prevent resource exhaustion
  • All endpoints behind admin authentication
  • GORM scanner: 0 CRITICAL/HIGH findings
  • Trivy filesystem scan: 0 HIGH/CRITICAL vulnerabilities
  • Blob validation on frontend export responses

Performance

  • Server-side caching: 30s TTL for summary/alerts, 60s for charts
  • 3 composite database indexes for sub-200ms aggregation on 100k+ row tables
  • Dashboard tab code-split via React.lazy (Recharts not loaded until tab visited)
  • Recharts tree-shaken (only imported chart types bundled)
  • Cache invalidated on ban/unban to prevent stale data

Quality Gates

Gate Result
Playwright E2E (670 tests, 3 browsers) ✅ Pass
Backend unit coverage (88.4%) ✅ ≥ 87%
Frontend unit coverage (90%+) ✅ ≥ 85%
Patch coverage (98.1%) ✅ ≥ 90%
GORM security scanner ✅ 0 CRITICAL/HIGH
Trivy filesystem scan ✅ 0 HIGH/CRITICAL
TypeScript type check ✅ 0 errors
Pre-commit hooks ✅ Pass
Go race detector (-race) ✅ 0 races

Screenshots

Dashboard screenshots pending — the feature is fully functional but screenshots require a running instance with CrowdSec decision data.


Out of Scope

  • Real-time WebSocket streaming (polling with cache is adequate for v1)
  • GeoIP map visualization (future enhancement)
  • Dark mode chart theme (uses existing palette)
  • i18n for chart data labels (scenario names come from CrowdSec in English)
  • Custom scenario creation (managed via CrowdSec Hub/CLI)

renovate bot and others added 2 commits March 25, 2026 11:35
…n-major-updates

chore(deps): update dependency knip to ^6.0.5 (feature/beta-release)
@github-advanced-security
Copy link
Copy Markdown
Contributor

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 25, 2026

✅ Supply Chain Verification Results

PASSED

📦 SBOM Summary

  • Components: 1487

🔍 Vulnerability Scan

Severity Count
🔴 Critical 0
🟠 High 0
🟡 Medium 4
🟢 Low 0
Total 4

📎 Artifacts

  • SBOM (CycloneDX JSON) and Grype results available in workflow artifacts

Generated by Supply Chain Verification workflow • View Details

actions-user and others added 25 commits March 25, 2026 17:19
…ec configuration page

- Implemented TopAttackingIPsChart component for visualizing top attacking IPs.
- Created hooks for fetching CrowdSec dashboard data including summary, timeline, top IPs, scenarios, and alerts.
- Added tests for the new hooks to ensure data fetching works as expected.
- Updated translation files for new dashboard terms in multiple languages.
- Refactored CrowdSecConfig page to include a tabbed interface for configuration and dashboard views.
- Added end-to-end tests for CrowdSec dashboard functionality including tab navigation, data display, and interaction with time range and refresh features.
- Added ~40 backend tests covering uncovered branches in CrowdSec
  dashboard handlers (error paths, validation, export edge cases)
- Patch coverage improved from 81.5% to 98.3%, exceeding 90% threshold
- Fixed DoD ordering: coverage tests now run before the patch report
  (the report requires coverage artifacts as input)
- Rewrote the local patch coverage DoD step in both the Management agent
  and testing instructions to clarify purpose, prerequisites, required
  action on findings, and blocking gate semantics
- Eliminated ambiguous "advisory" language that allowed agents to skip
  acting on uncovered lines
- Removed redundant `gin.SetMode(gin.TestMode)` calls from individual test files.
- Introduced a centralized `TestMain` function in `testmain_test.go` to set the Gin mode for all tests.
- Ensured consistent test environment setup across various handler test files.
…tions-deploy-pages-5.x

chore(deps): update actions/deploy-pages action to v5 (feature/beta-release)
…decov-codecov-action-6.x

chore(deps): update codecov/codecov-action action to v6 (feature/beta-release)
actions-user and others added 15 commits April 3, 2026 22:38
…asi-threads, @playwright/test, and dotenv for compatibility improvements
…act-i18next-17.x

fix(deps): update dependency react-i18next to v17 (feature/beta-release)
…n-major-updates

fix(deps): update non-major-updates (feature/beta-release)
@Wikid82 Wikid82 marked this pull request as ready for review April 5, 2026 02:22
Copilot AI review requested due to automatic review settings April 5, 2026 02:22
…act-i18next-17.x

fix(deps): update dependency react-i18next to v17 (feature/beta-release)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a CrowdSec analytics dashboard to the Security section so administrators can observe attack/ban trends directly in the UI, backed by new backend aggregation/storage and updated CI/test protocols.

Changes:

  • Add CrowdSec dashboard entry points in the frontend (tabbed UI + lazy-loaded dashboard hooks/components) and corresponding unit tests.
  • Enrich backend decision storage for analytics and introduce a small in-memory dashboard cache; centralize gin.TestMode setup in handler tests.
  • Update docs/changelog, bump container/dependency versions, and harden CI workflows (explicit permissions, action pin updates, added npm audit step).

Reviewed changes

Copilot reviewed 165 out of 168 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
README.md Updates security feature list/marketing copy to mention the CrowdSec analytics dashboard.
package.json Updates devDependencies and adds an override for a transitive dependency.
frontend/src/pages/CrowdSecConfig.tsx Adds Radix Tabs and lazy-loads the new CrowdSec Dashboard tab content.
frontend/src/hooks/useCrowdsecDashboard.ts Introduces React Query hooks for dashboard endpoints (summary/timeline/top IPs/scenarios/alerts).
frontend/src/components/tests/TopAttackingIPsChart.test.tsx Adds unit coverage for the “Top attacking IPs” chart states and accessibility label.
frontend/src/components/tests/BanTimelineChart.test.tsx Adds unit coverage for the ban timeline chart states and accessibility label.
docs/features.md Adds a new high-level marketing feature section for the CrowdSec Dashboard.
Dockerfile Bumps CrowdSec/Caddy-security/Coraza deps and Node builder image; updates pinned grpc version used during build.
CHANGELOG.md Adds release notes for the CrowdSec Dashboard feature.
backend/internal/models/security_decision.go Adds dashboard-enrichment fields and composite indexes to support analytics queries.
backend/internal/api/handlers/websocket_status_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/user_integration_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/uptime_monitor_initial_state_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/update_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/testmain_test.go Adds package-level TestMain to set gin.TestMode for all handler tests.
backend/internal/api/handlers/system_permissions_wave6_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/system_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_toggles_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_ratelimit_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_priority_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_notifications_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_notifications_single_source_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_notifications_patch_coverage_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_notifications_final_blockers_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_headers_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_handler_fixed_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_handler_cache_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_handler_authz_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_geoip_endpoints_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/security_event_intake_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/proxy_host_handler_update_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/notification_provider_patch_coverage_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/notification_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/manual_challenge_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/logs_ws_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/logs_handler_coverage_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/import_handler_sanitize_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/health_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/feature_flags_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/feature_flags_blocker3_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/encryption_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/dns_provider_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/dns_detection_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/db_health_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_wave7_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_wave6_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_wave3_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_state_sync_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_pull_apply_integration_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_lapi_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_dashboard_cache.go Adds a TTL cache used to reduce backend aggregation load for the dashboard.
backend/internal/api/handlers/crowdsec_coverage_gap_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_coverage_boost_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_cache_verification_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/crowdsec_archive_validation_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/credential_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/coverage_quick_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/certificate_handler_security_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/certificate_handler_coverage_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/cerberus_logs_ws_test.go Removes gin.SetMode from init-time setup (now handled by TestMain).
backend/internal/api/handlers/backup_handler_sanitize_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/access_list_handler_test.go Removes per-test gin.SetMode now that it’s centralized.
backend/internal/api/handlers/access_list_handler_coverage_test.go Removes per-test gin.SetMode now that it’s centralized.
.github/workflows/waf-integration.yml Adds explicit contents: read permissions.
.github/workflows/supply-chain-pr.yml Updates pinned upload-sarif action SHA.
.github/workflows/security-weekly-rebuild.yml Adds explicit permissions and updates pinned action SHAs.
.github/workflows/security-pr.yml Adds explicit permissions and updates pinned action SHAs/comments.
.github/workflows/repo-health.yml Adds explicit contents: read permissions.
.github/workflows/renovate.yml Updates pinned Renovate action SHA.
.github/workflows/release-goreleaser.yml Updates pinned setup-go action SHA.
.github/workflows/rate-limit-integration.yml Adds explicit contents: read permissions.
.github/workflows/quality-checks.yml Updates pinned setup-go action SHA; adds frontend npm audit step.
.github/workflows/pr-checklist.yml Adds explicit permissions including pull-requests: write.
.github/workflows/history-rewrite-tests.yml Adds explicit contents: read permissions.
.github/workflows/gh_cache_cleanup.yml Adds explicit contents: read permissions.
.github/workflows/docs.yml Updates pinned deploy-pages action SHA (major version bump).
.github/workflows/crowdsec-integration.yml Adds explicit contents: read permissions.
.github/workflows/create-labels.yml Adds explicit contents: read permissions.
.github/workflows/codeql.yml Updates pinned CodeQL/setup-go action SHAs.
.github/workflows/codecov-upload.yml Updates pinned setup-go and Codecov action SHAs (major version bump).
.github/workflows/cerberus-integration.yml Adds explicit contents: read permissions.
.github/workflows/benchmark.yml Updates pinned setup-go action SHA.
.github/workflows/auto-label-issues.yml Adds explicit contents: read permissions.
.github/workflows/auto-changelog.yml Sets workflow permissions to contents: write.
.github/workflows/auto-add-to-project.yml Adds explicit contents: read permissions.
.github/renovate.json Enables npmDedupe post-update option.
.github/instructions/testing.instructions.md Adjusts testing protocol ordering/requirements for local patch coverage reporting.
.github/agents/Management.agent.md Aligns management agent DoD with updated patch coverage report timing and thresholds.

@Wikid82 Wikid82 merged commit a5c6eb9 into development Apr 6, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants