- Updated Definition of Done report with detailed checks and results for backend and frontend tests. - Documented issues related to race conditions and test failures in QA reports. - Improved security scan notes and code cleanup status in QA reports. - Added summaries for rate limit integration test fixes, including root causes and resolutions. - Introduced new debug and integration scripts for rate limit testing. - Updated security documentation to reflect changes in configuration and troubleshooting steps. - Enhanced troubleshooting guides for CrowdSec and Go language server (gopls) errors. - Improved frontend and scripts README files for clarity and usage instructions.
4.6 KiB
WebSocket Live Log Viewer Fix
Problem
The live log viewer in the Cerberus Dashboard was always showing "Disconnected" status even when it should connect to the WebSocket endpoint.
Root Cause
The LiveLogViewer component was setting isConnected=true immediately when the component mounted, before the WebSocket actually established a connection. This premature status update masked the real connection state and made it impossible to see whether the WebSocket was actually connecting.
Solution
Modified the WebSocket connection flow to properly track connection lifecycle:
Frontend Changes
1. API Layer (frontend/src/api/logs.ts)
- Added
onOpen?: () => voidcallback parameter toconnectLiveLogs() - Added
ws.onopenevent handler that calls the callback when connection opens - Enhanced logging for debugging:
- Log WebSocket URL on connection attempt
- Log when connection establishes
- Log close event details (code, reason, wasClean)
2. Component (frontend/src/components/LiveLogViewer.tsx)
- Updated to use the new
onOpencallback - Initial state is now "Disconnected"
- Only set
isConnected=truewhenonOpencallback fires - Added console logging for connection state changes
- Properly cleanup and set disconnected state on unmount
3. Tests (frontend/src/components/__tests__/LiveLogViewer.test.tsx)
- Updated mock implementation to include
onOpencallback - Fixed test expectations to match new behavior (initially Disconnected)
- Added proper simulation of WebSocket opening
Backend Changes (for debugging)
1. Auth Middleware (backend/internal/api/middleware/auth.go)
- Added
fmtimport for logging - Detect WebSocket upgrade requests (
Upgrade: websocketheader) - Log auth method used for WebSocket (cookie vs query param)
- Log auth failures with context
2. WebSocket Handler (backend/internal/api/handlers/logs_ws.go)
- Added log on connection attempt received
- Added log when connection successfully established with subscriber ID
How Authentication Works
The WebSocket endpoint (/api/v1/logs/live) is protected by the auth middleware, which supports three authentication methods (in order):
- Authorization header:
Authorization: Bearer <token> - HttpOnly cookie:
auth_token=<token>(automatically sent by browser) - Query parameter:
?token=<token>
For same-origin WebSocket connections from a browser, cookies are sent automatically, so the existing cookie-based auth should work. The middleware has been enhanced with logging to debug any auth issues.
Testing
To test the fix:
-
Build and Deploy:
# Build Docker image docker build -t charon:local . # Restart containers docker-compose -f docker-compose.local.yml down docker-compose -f docker-compose.local.yml up -d -
Access the Application:
- Navigate to the Security page
- Enable Cerberus if not already enabled
- The LiveLogViewer should appear at the bottom
-
Check Connection Status:
- Should initially show "Disconnected" (red badge)
- Should change to "Connected" (green badge) within 1-2 seconds
- Look for console logs:
- "Connecting to WebSocket: ws://..."
- "WebSocket connection established"
- "Live log viewer connected"
-
Verify WebSocket in DevTools:
- Open Browser DevTools → Network tab
- Filter by "WS" (WebSocket)
- Should see connection to
/api/v1/logs/live - Status should be "101 Switching Protocols"
- Messages tab should show incoming log entries
-
Check Backend Logs:
docker logs <charon-container> 2>&1 | grep -i websocketShould see:
- "WebSocket connection attempt received"
- "WebSocket connection established successfully"
Expected Behavior
- Initial State: "Disconnected" (red badge)
- After Connection: "Connected" (green badge)
- Log Streaming: Real-time security logs appear as they happen
- On Error: Badge turns red, shows "Disconnected"
- Reconnection: Not currently implemented (would require retry logic)
Files Modified
frontend/src/api/logs.tsfrontend/src/components/LiveLogViewer.tsxfrontend/src/components/__tests__/LiveLogViewer.test.tsxbackend/internal/api/middleware/auth.gobackend/internal/api/handlers/logs_ws.go
Notes
- The fix properly implements the WebSocket lifecycle tracking
- All frontend tests pass
- Pre-commit checks pass (except coverage which is expected)
- The backend logging is temporary for debugging and can be removed once verified working
- SameSite=Strict cookie policy should work for same-origin WebSocket connections