1. app/web/utils/validators.py - Added 'finalizing' to valid_statuses list
2. app/web/models.py - Updated status field comment to document all valid statuses
3. app/web/jobs/scan_job.py
- Added transition to 'finalizing' status before output file generation
- Sets current_phase = 'generating_outputs' during this phase
- Wrapped output generation in try-except with proper error handling
- If output generation fails, scan is marked 'completed' with warning message (scan data is still valid)
4. app/web/api/scans.py
- Added _recover_orphaned_scan() helper function for smart recovery
- Modified stop_running_scan() to:
- Allow stopping scans with status 'running' OR 'finalizing'
- When scanner not in registry, perform smart recovery instead of returning 404
- Smart recovery checks for output files and marks as 'completed' if found, 'cancelled' if not
5. app/web/services/scan_service.py
- Enhanced cleanup_orphaned_scans() with smart recovery logic
- Now finds scans in both 'running' and 'finalizing' status
- Returns dict with stats: {'recovered': N, 'failed': N, 'total': N}
6. app/web/app.py - Updated caller to handle new dict return type from cleanup_orphaned_scans()
Expected Behavior Now
1. Normal scan flow: running → finalizing → completed
2. Stop on active scan: Sends cancel signal, becomes 'cancelled'
3. Stop on orphaned scan with files: Smart recovery → 'completed'
4. Stop on orphaned scan without files: → 'cancelled'
5. App restart with orphans: Startup cleanup uses smart recovery
32 lines
844 B
Python
32 lines
844 B
Python
"""
|
|
Input validation utilities for SneakyScanner web application.
|
|
|
|
Provides validation functions for API inputs and data integrity.
|
|
"""
|
|
|
|
from typing import Optional
|
|
|
|
|
|
def validate_scan_status(status: str) -> tuple[bool, Optional[str]]:
|
|
"""
|
|
Validate scan status value.
|
|
|
|
Args:
|
|
status: Status string to validate
|
|
|
|
Returns:
|
|
Tuple of (is_valid, error_message)
|
|
|
|
Examples:
|
|
>>> validate_scan_status('running')
|
|
(True, None)
|
|
>>> validate_scan_status('invalid')
|
|
(False, 'Invalid status: invalid. Must be one of: running, completed, failed')
|
|
"""
|
|
valid_statuses = ['running', 'finalizing', 'completed', 'failed', 'cancelled']
|
|
|
|
if status not in valid_statuses:
|
|
return False, f'Invalid status: {status}. Must be one of: {", ".join(valid_statuses)}'
|
|
|
|
return True, None
|