# CRITICAL FIXES - Quick Reference ## 🔴 BLOCKERS THAT PREVENT THE TOOL FROM WORKING ### 1. Frontend Dependencies Missing ```bash cd frontend npm install ``` **Why**: 537 TypeScript errors preventing compilation --- ### 2. Frontend Type Mismatches **File**: `frontend/src/types/api.ts` Replace lines 5-46 with: ```typescript export interface Service { id: number; host_id: number; port: number; protocol: string; service_name: string | null; service_version: string | null; state: string; banner: string | null; first_seen: string; // ← MISSING last_seen: string; // ← MISSING } export interface Host { id: number; ip_address: string; hostname: string | null; mac_address: string | null; status: 'online' | 'offline' | 'scanning'; // ← WRONG: was 'up' | 'down' last_seen: string; first_seen: string; scan_id: number | null; } export interface Scan { id: number; network_range: string; // ← WRONG: was 'target' scan_type: 'quick' | 'standard' | 'deep' | 'custom'; status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'; progress: number; hosts_found: number; // ← WRONG: was 'total_hosts' ports_scanned: number; // ← WRONG: was 'hosts_scanned' started_at: string; // ← WRONG: was 'start_time' completed_at: string | null; // ← WRONG: was 'end_time' error_message: string | null; } ``` **Why**: Frontend will crash at runtime when API returns data --- ### 3. Database Session Leaks in Background Tasks **File**: `app/api/endpoints/scans.py` Replace the `start_scan` function (lines 19-52) with: ```python @router.post("/start", response_model=ScanStartResponse, status_code=202) async def start_scan( config: ScanConfigRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db) ): """Start a new network scan.""" try: scan_service = ScanService(db) scan = scan_service.create_scan(config) # Schedule background execution with fresh session async def run_scan(): fresh_db = SessionLocal() try: fresh_service = ScanService(fresh_db) await fresh_service.execute_scan(scan.id, config) finally: fresh_db.close() background_tasks.add_task(run_scan) logger.info(f"Started scan {scan.id} for {config.network_range}") return ScanStartResponse( scan_id=scan.id, message=f"Scan started for network {config.network_range}", status=ScanStatusEnum.PENDING ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Error starting scan: {e}", exc_info=True) raise HTTPException(status_code=500, detail="Failed to start scan") ``` **Why**: Current code passes db session that closes before scan executes --- ### 4. WebSocket Not Connected to Scan Updates **File**: `app/services/scan_service.py` Add import at top (line 5): ```python from app.api.endpoints.websocket import broadcast_scan_update ``` Replace the progress callbacks (around lines 302-322) with: ```python def _on_host_progress( self, scan_id: int, host: str, progress: float, callback: Optional[callable] ) -> None: """Handle host discovery progress.""" # Broadcast via WebSocket asyncio.run_coroutine_threadsafe( broadcast_scan_update(scan_id, 'scan_progress', { 'progress': progress * 0.5, 'current_host': host }), asyncio.get_event_loop() ) def _on_port_progress( self, scan_id: int, host: str, port: int, progress: float, callback: Optional[callable] ) -> None: """Handle port scanning progress.""" asyncio.run_coroutine_threadsafe( broadcast_scan_update(scan_id, 'scan_progress', { 'progress': 0.5 + (progress * 0.5), 'current_host': host, 'current_port': port }), asyncio.get_event_loop() ) ``` **Why**: Users won't see real-time scan progress --- ### 5. WebSocket Thread Safety Issue **File**: `app/api/endpoints/websocket.py` Replace the `ConnectionManager` class (lines 8-56) with: ```python class ConnectionManager: """Manager for WebSocket connections.""" def __init__(self): """Initialize connection manager.""" self.active_connections: Set[WebSocket] = set() self.lock = asyncio.Lock() async def connect(self, websocket: WebSocket): """Accept and register a new WebSocket connection.""" await websocket.accept() async with self.lock: self.active_connections.add(websocket) logger.info(f"WebSocket connected. Total: {len(self.active_connections)}") def disconnect(self, websocket: WebSocket): """Remove a WebSocket connection.""" self.active_connections.discard(websocket) logger.info(f"WebSocket disconnected. Total: {len(self.active_connections)}") async def send_personal_message(self, message: dict, websocket: WebSocket): """Send message to specific WebSocket.""" try: await websocket.send_json(message) except Exception as e: logger.error(f"Error sending message: {e}") self.disconnect(websocket) async def broadcast(self, message: dict): """Broadcast message to all connected WebSockets.""" disconnected = set() # Make a copy under lock async with self.lock: connections_copy = self.active_connections.copy() for connection in connections_copy: try: await connection.send_json(message) except Exception as e: logger.error(f"Error broadcasting: {e}") disconnected.add(connection) # Clean up disconnected for connection in disconnected: self.disconnect(connection) ``` **Why**: Race conditions can lose connections or cause crashes --- ### 6. Frontend Environment Variables **Create file**: `frontend/.env.example` ```env VITE_API_URL=http://localhost:8000 VITE_WS_URL=ws://localhost:8000 ``` **Create file**: `frontend/.env` ```env VITE_API_URL=http://localhost:8000 VITE_WS_URL=ws://localhost:8000 ``` **Why**: Frontend can't connect to backend without these --- ### 7. Port Range Validation **File**: `app/scanner/port_scanner.py` Replace `parse_port_range` method (lines 128-157) with: ```python def parse_port_range(self, port_range: str) -> List[int]: """Parse port range string to list of ports.""" ports = set() try: for part in port_range.split(','): part = part.strip() if not part: continue try: if '-' in part: # Range like "8000-8100" parts = part.split('-') if len(parts) != 2: logger.error(f"Invalid range format: {part}") continue start, end = int(parts[0].strip()), int(parts[1].strip()) if not (1 <= start <= end <= 65535): logger.error(f"Port range out of bounds: {start}-{end}") continue ports.update(range(start, end + 1)) else: # Single port port = int(part) if not (1 <= port <= 65535): logger.error(f"Port out of range: {port}") continue ports.add(port) except ValueError as e: logger.error(f"Invalid port specification: {part}") continue return sorted(list(ports)) except Exception as e: logger.error(f"Error parsing port range '{port_range}': {e}") return [] ``` **Why**: Invalid port ranges cause uncaught exceptions --- ### 8. Search Input Validation **File**: `app/api/endpoints/hosts.py` Update line 20: ```python search: Optional[str] = Query(None, max_length=100, description="Search by IP or hostname"), ``` **Why**: Prevents DoS with huge search strings --- ## Testing Verification Run these to verify fixes work: ```bash # Backend python -c "from app.database import init_db; init_db(); print('✅ DB OK')" python -c "from app.api.endpoints.websocket import manager; print('✅ WebSocket OK')" # Frontend cd frontend && npm install && npm run build # Should complete without errors ``` --- ## Deploy Checklist After Fixes - [ ] Backend starts without errors: `python main.py` - [ ] Frontend builds: `cd frontend && npm run build` - [ ] API responds: `curl http://localhost:8000/health` - [ ] WebSocket connects: Check browser console - [ ] Can start scan via API - [ ] Real-time updates in WebSocket - [ ] Frontend shows scan progress - [ ] Hosts display correctly --- **Estimated Time to Fix**: 2-3 hours for experienced developer