Files
Charon/docs/reports/qa_report.md
GitHub Actions 489cd93384 chore: Revamp frontend test iteration plan and documentation
- Updated design documentation to reflect the new Playwright-first approach for frontend testing, including orchestration flow and runbook notes.
- Revised requirements to align with the new frontend test iteration strategy, emphasizing E2E environment management and coverage thresholds.
- Expanded tasks to outline phased implementation for frontend testing, including Playwright E2E baseline, backend triage, and coverage validation.
- Enhanced QA report to capture frontend coverage failures and type errors, with detailed remediation steps for accessibility compliance.
- Created new security validation and accessibility remediation reports for CrowdSec configuration, addressing identified issues and implementing fixes.
- Adjusted package.json scripts to prioritize Firefox for Playwright tests.
- Added canonical links for requirements and tasks documentation.
2026-02-08 00:03:48 +00:00

336 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QA & Security Report
**Date:** 2026-02-07
**Status:** 🔴 FAILED
**Evaluator:** GitHub Copilot (QA Security Mode)
## Executive Summary
QA validation was **stopped** after frontend coverage tests failed. Remaining checks were not executed per stop-on-failure policy.
| Check | Status | Details |
| :--- | :--- | :--- |
| **Frontend Coverage** | 🔴 FAIL | Test failures; see verbatim output below |
| **TypeScript Check** | ⚪ NOT RUN | Stopped after frontend coverage failure |
| **Pre-commit Hooks** | ⚪ NOT RUN | Stopped after frontend coverage failure |
| **Linting (Go/Frontend/Markdown/Hadolint)** | ⚪ NOT RUN | Stopped after frontend coverage failure |
| **Security Scans** | ⚪ SKIPPED | Skipped by request |
---
## 1. Security Findings
### Security Scans - SKIPPED
### Frontend Coverage - FAILED
**Failure Output (verbatim):**
```
Terminal: Test: Frontend with Coverage (Charon)
Output:
[... PREVIOUS OUTPUT TRUNCATED ...]
ity header profile to selected hosts using bulk endpoint 349ms
✓ removes security header profile when "None" selected 391ms
✓ handles partial failure with appropriate toast 303ms
✓ resets state on modal close 376ms
✓ shows profile description when profile is selected 504ms
✓ src/pages/__tests__/Plugins.test.tsx (30 tests) 1828ms
✓ src/components/__tests__/DNSProviderSelector.test.tsx (29 tests) 292ms
↓ src/pages/__tests__/Security.audit.test.tsx (18 tests | 18 skipped)
✓ src/api/__tests__/presets.test.ts (26 tests) 26ms
↓ src/pages/__tests__/Security.errors.test.tsx (13 tests | 13 skipped)
✓ src/components/__tests__/SecurityHeaderProfileForm.test.tsx (17 tests) 1928ms
✓ should show security score 582ms
✓ should calculate score after debounce 536ms
↓ src/pages/__tests__/Security.dashboard.test.tsx (18 tests | 18 skipped)
✓ src/components/__tests__/CertificateStatusCard.test.tsx (24 tests) 267ms
✓ src/api/__tests__/dnsProviders.test.ts (30 tests) 33ms
✓ src/pages/__tests__/Uptime.spec.tsx (11 tests) 1047ms
✓ src/components/__tests__/LoadingStates.security.test.tsx (41 tests) 417ms
↓ src/pages/__tests__/Security.loading.test.tsx (12 tests | 12 skipped)
✓ src/data/__tests__/crowdsecPresets.test.ts (38 tests) 22ms
Error: Not implemented: navigation (except hash changes)
at module.exports (/projects/Charon/frontend/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
at navigateFetch (/projects/Charon/frontend/node_modules/jsdom/lib/jsdom/living/window/navigation.js:77:3)
at exports.navigate (/projects/Charon/frontend/node_modules/jsdom/lib/jsdom/living/window/navigation.js:55:3)
at Timeout._onTimeout (/projects/Charon/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils
-impl.js:81:7)
at listOnTimeout (node:internal/timers:581:17)
at processTimers (node:internal/timers:519:7) undefined
stderr | src/pages/__tests__/AuditLogs.test.tsx > <AuditLogs /> > handles export error
Export error: Error: Export failed
at /projects/Charon/frontend/src/pages/__tests__/AuditLogs.test.tsx:324:7
at file:///projects/Charon/frontend/node_modules/@vitest/runner/dist/index.js:145:11
at file:///projects/Charon/frontend/node_modules/@vitest/runner/dist/index.js:915:26
at file:///projects/Charon/frontend/node_modules/@vitest/runner/dist/index.js:1243:20
at new Promise (<anonymous>)
at runWithTimeout (file:///projects/Charon/frontend/node_modules/@vitest/runner/dist/index.js:1209:10)
at file:///projects/Charon/frontend/node_modules/@vitest/runner/dist/index.js:1653:37
at Traces.$ (file:///projects/Charon/frontend/node_modules/vitest/dist/chunks/traces.CCmnQaNT.js:142:27)
at trace (file:///projects/Charon/frontend/node_modules/vitest/dist/chunks/test.B8ej_ZHS.js:239:21)
at runTest (file:///projects/Charon/frontend/node_modules/@vitest/runner/dist/index.js:1653:12)
✓ src/pages/__tests__/AuditLogs.test.tsx (14 tests) 1219ms
✓ src/hooks/__tests__/useSecurity.test.tsx (19 tests) 1107ms
✓ src/hooks/__tests__/useSecurityHeaders.test.tsx (15 tests) 805ms
stdout | src/api/logs.test.ts > logs api > connects to live logs websocket and handles lifecycle events
Connecting to WebSocket: ws://localhost/api/v1/logs/live?level=error&source=cerberus
WebSocket connection established
WebSocket connection closed { code: 1000, reason: '', wasClean: true }
stderr | src/api/logs.test.ts > logs api > connects to live logs websocket and handles lifecycle events
WebSocket error: Event { isTrusted: [Getter] }
stdout | src/api/logs.test.ts > connectSecurityLogs > connects to cerberus logs websocket endpoint
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
stdout | src/api/logs.test.ts > connectSecurityLogs > passes source filter to websocket url
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?source=waf
stdout | src/api/logs.test.ts > connectSecurityLogs > passes level filter to websocket url
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?level=error
stdout | src/api/logs.test.ts > connectSecurityLogs > passes ip filter to websocket url
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?ip=192.168
stdout | src/api/logs.test.ts > connectSecurityLogs > passes host filter to websocket url
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?host=example.com
stdout | src/api/logs.test.ts > connectSecurityLogs > passes blocked_only filter to websocket url
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?blocked_only=true
stdout | src/api/logs.test.ts > connectSecurityLogs > receives and parses security log entries
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
Cerberus logs WebSocket connection established
stdout | src/api/logs.test.ts > connectSecurityLogs > receives blocked security log entries
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
Cerberus logs WebSocket connection established
stdout | src/api/logs.test.ts > connectSecurityLogs > handles onOpen callback
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
Cerberus logs WebSocket connection established
stdout | src/api/logs.test.ts > connectSecurityLogs > handles onError callback
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
stderr | src/api/logs.test.ts > connectSecurityLogs > handles onError callback
Cerberus logs WebSocket error: Event { isTrusted: [Getter] }
stdout | src/api/logs.test.ts > connectSecurityLogs > handles onClose callback
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
Cerberus logs WebSocket closed { code: 1000, reason: '', wasClean: true }
stdout | src/api/logs.test.ts > connectSecurityLogs > returns disconnect function that closes websocket
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
Cerberus logs WebSocket connection established
Cerberus logs WebSocket closed { code: 1000, reason: '', wasClean: true }
stdout | src/api/logs.test.ts > connectSecurityLogs > handles JSON parse errors gracefully
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?
Cerberus logs WebSocket connection established
stdout | src/api/logs.test.ts > connectSecurityLogs > uses wss protocol when on https
Connecting to Cerberus logs WebSocket: wss://secure.example.com/api/v1/cerberus/logs/ws?
stdout | src/api/logs.test.ts > connectSecurityLogs > combines multiple filters in websocket url
Connecting to Cerberus logs WebSocket: ws://localhost/api/v1/cerberus/logs/ws?source=waf&level=warn&ip=10.0.0&host=examp
le.com&blocked_only=true
✓ src/api/logs.test.ts (19 tests) 18ms
✓ src/pages/__tests__/Security.spec.tsx (6 tests) 613ms
src/pages/__tests__/AccessLists.test.tsx (5 tests | 3 failed) 4121ms
✓ renders empty state and opens create form 168ms
✓ shows CGNAT warning and allows dismiss 74ms
× deletes access list with backup 1188ms
× bulk deletes selected access lists 1282ms
× tests IP against access list 1407ms
✓ src/components/__tests__/ProxyHostForm-dns.test.tsx (15 tests) 14889ms
✓ detects *.example.com as wildcard 1330ms
✓ does not detect sub.example.com as wildcard 632ms
✓ detects multiple wildcards in comma-separated list 1525ms
✓ detects wildcard at start of comma-separated list 1276ms
✓ shows DNS provider selector when wildcard domain entered 638ms
✓ shows info alert explaining DNS-01 requirement 645ms
✓ shows validation error on submit if wildcard without provider 1976ms
✓ does not show DNS provider selector without wildcard 711ms
✓ DNS provider selector is present for wildcard domains 542ms
✓ clears DNS provider when switching to non-wildcard 1362ms
✓ preserves form state during wildcard domain edits 1027ms
✓ includes dns_provider_id null for non-wildcard domains 1506ms
✓ prevents submission when wildcard present without DNS provider 1446ms
✓ src/hooks/__tests__/usePlugins.test.tsx (15 tests) 842ms
src/components/__tests__/Layout.test.tsx (16 tests | 1 failed) 1129ms
✓ renders the application logo 125ms
× renders all navigation items 302ms
✓ renders children content 26ms
✓ displays version information 50ms
✓ calls logout when logout button is clicked 140ms
✓ toggles sidebar on mobile 73ms
✓ persists collapse state to localStorage 63ms
✓ restores collapsed state from localStorage on load 25ms
✓ displays Security nav item when Cerberus is enabled 25ms
✓ hides Security nav item when Cerberus is disabled 49ms
✓ displays Uptime nav item when Uptime is enabled 38ms
✓ hides Uptime nav item when Uptime is disabled 46ms
✓ shows Security and Uptime when both features are enabled 55ms
✓ hides both Security and Uptime when both features are disabled 66ms
✓ defaults to showing Security and Uptime when feature flags are loading 24ms
✓ shows other nav items regardless of feature flags 19ms
✓ src/components/ui/__tests__/DataTable.test.tsx (19 tests) 450ms
✓ src/pages/__tests__/SMTPSettings.test.tsx (10 tests) 2655ms
✓ saves SMTP settings successfully 724ms
✓ sends test email 312ms
✓ surfaces backend validation errors on save 375ms
✓ disables test connection until required fields are set and shows error toast on failure 487ms
✓ handles test email failures and keeps input value intact 375ms
✓ src/components/__tests__/SecurityNotificationSettingsModal.test.tsx (13 tests) 1103ms
✓ submits updated settings 372ms
✓ src/hooks/__tests__/useCredentials.test.tsx (16 tests) 242ms
✓ src/pages/__tests__/Uptime.test.tsx (9 tests) 587ms
✓ src/hooks/__tests__/useRemoteServers.test.tsx (10 tests) 774ms
✓ src/api/auditLogs.test.ts (14 tests) 13ms
✓ src/api/__tests__/security.test.ts (16 tests) 13ms
✓ src/pages/__tests__/Login.overlay.audit.test.tsx (7 tests) 3011ms
✓ shows coin-themed overlay during login 650ms
✓ ATTACK: rapid fire login attempts are blocked by overlay 499ms
✓ ATTACK: XSS in login credentials does not break overlay 788ms
✓ ATTACK: network timeout does not leave overlay stuck 323ms
✓ src/hooks/__tests__/useNotifications.test.tsx (9 tests) 541ms
✓ src/pages/__tests__/CrowdSecConfig.test.tsx (7 tests) 1928ms
✓ allows reading and saving config files 582ms
✓ allows banning an IP 581ms
✓ src/pages/__tests__/EncryptionManagement.test.tsx (14 tests) 1237ms
✓ src/components/__tests__/WebSocketStatusCard.test.tsx (8 tests) 432ms
✓ src/components/__tests__/CSPBuilder.test.tsx (13 tests) 788ms
✓ src/components/__tests__/DNSProviderForm.test.tsx (7 tests) 2406ms
✓ handles form submission for creation 743ms
✓ tests connection 553ms
✓ handles test connection failure 402ms
✓ src/hooks/__tests__/useManualChallenge.test.tsx (11 tests) 236ms
✓ src/components/__tests__/ImportReviewTable.test.tsx (9 tests) 463ms
✓ src/pages/__tests__/RateLimiting.spec.tsx (9 tests) 389ms
✓ src/components/ui/Tabs.test.tsx (10 tests) 406ms
✓ src/components/import/__tests__/FileUploadSection.test.tsx (9 tests) 651ms
✓ rejects files over 5MB limit 415ms
✓ src/components/__tests__/CertificateList.test.tsx (6 tests) 365ms
✓ src/hooks/__tests__/useProxyHosts.test.tsx (8 tests) 492ms
✓ src/components/__tests__/DNSDetectionResult.test.tsx (10 tests) 210ms
✓ src/api/__tests__/users.test.ts (10 tests) 14ms
✓ src/api/__tests__/manualChallenge.test.ts (14 tests) 13ms
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > creates WebSocket connection with corre
ct URL
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > uses wss protocol when page is https
Connecting to WebSocket: wss://example.com/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > includes filters in query parameters
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?level=error&source=waf
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > calls onMessage callback when message i
s received
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > handles JSON parse errors gracefully
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > returns a close function that closes th
e WebSocket
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > does not throw when closing already clo
sed connection
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > handles missing optional callbacks
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stderr | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > handles missing optional callbacks
WebSocket error: Event { isTrusted: [Getter] }
stdout | src/api/__tests__/logs-websocket.test.ts > logs API - connectLiveLogs > processes multiple messages in sequence
Connecting to WebSocket: ws://localhost:8080/api/v1/logs/live?
stdout | src/api/__tests__/logs-websocket.test.ts
WebSocket connection closed { code: 1000, reason: '', wasClean: true }
✓ src/api/__tests__/logs-websocket.test.ts (11 tests | 2 skipped) 30ms
✓ src/hooks/__tests__/useDNSDetection.test.tsx (10 tests) 680ms
✓ src/components/__tests__/CrowdSecBouncerKeyDisplay.test.tsx (13 tests | 4 skipped) 198ms
✓ src/pages/__tests__/ProxyHosts-coverage-isolated.test.tsx (3 tests) 1504ms
✓ renders SSL staging badge, websocket badge 634ms
✓ bulk apply merges host data and calls updateHost 628ms
✓ src/components/__tests__/ImportReviewTable-warnings.test.tsx (7 tests) 337ms
✓ src/api/__tests__/settings.test.ts (16 tests) 11ms
✓ src/pages/__tests__/AcceptInvite.test.tsx (8 tests) 1368ms
✓ shows password mismatch error 315ms
✓ submits form and shows success 522ms
✓ shows error on submit failure 336ms
✓ src/components/__tests__/RemoteServerForm.test.tsx (9 tests) 726ms
✓ src/components/ui/__tests__/Skeleton.test.tsx (18 tests) 233ms
✓ src/components/__tests__/CrowdSecKeyWarning.test.tsx (8 tests) 380ms
✓ src/pages/__tests__/ProxyHosts-progress.test.tsx (2 tests) 902ms
✓ shows progress when applying multiple ACLs 819ms
✓ src/api/notifications.test.ts (5 tests) 10ms
✓ src/pages/__tests__/ImportCaddy-multifile-modal.test.tsx (9 tests) 359ms
✓ src/pages/__tests__/ProxyHosts-bulk-apply.test.tsx (3 tests) 1241ms
✓ shows Bulk Apply button when hosts selected and opens modal 497ms
✓ applies selected settings to all selected hosts by calling updateProxyHost merged payload 429ms
✓ cancels bulk apply modal when Cancel clicked 313ms
✓ src/components/ui/__tests__/Alert.test.tsx (18 tests) 210ms
✓ src/data/__tests__/securityPresets.test.ts (24 tests) 11ms
✓ src/pages/__tests__/ImportCaddy-warnings.test.tsx (6 tests) 82ms
✓ src/hooks/__tests__/useAccessLists.test.tsx (6 tests) 361ms
✓ src/components/__tests__/PermissionsPolicyBuilder.test.tsx (8 tests) 723ms
✓ src/components/ui/__tests__/StatsCard.test.tsx (14 tests) 245ms
src/components/__tests__/NotificationCenter.test.tsx 2/6
src/components/ui/__tests__/Input.test.tsx 10/16
Test Files 4 failed | 83 passed | 5 skipped (153)
Tests 39 failed | 1397 passed | 90 skipped (1536)
Start at 04:46:11
Duration 109.78s
```
src/pages/__tests__/ImportCrowdSec.spec.tsx 1/1
Test Files 8 failed | 129 passed | 5 skipped (153)
Tests 44 failed | 1669 passed | 90 skipped (1803)
Start at 04:32:30
Duration 119.07s
```
---
## 3. Completed Checks
No other checks were executed.
---
## 4. Deferred Checks (Not Run)
The following checks were **not executed** due to the frontend coverage failure:
- TypeScript type check
- Pre-commit hooks
- Linting (Go vet, staticcheck, frontend lint, markdownlint, hadolint)
---
## 5. Next Actions Required
1. Fix the failing frontend tests and rerun frontend coverage.
2. Resume deferred QA checks once frontend coverage passes.
---
## Accepted Risks
- Security scans skipped for this run per instruction; CVE risk accepted temporarily. Re-run when risk acceptance ends.