mirror of
https://github.com/mblanke/StrikePackageGPT.git
synced 2026-03-01 14:20:21 -05:00
Add backend modules and frontend components for StrikePackageGPT expansion
Co-authored-by: mblanke <9078342+mblanke@users.noreply.github.com>
This commit is contained in:
547
services/hackgpt-api/app/explain.py
Normal file
547
services/hackgpt-api/app/explain.py
Normal file
@@ -0,0 +1,547 @@
|
||||
"""
|
||||
Explain Module
|
||||
Provides "Explain this" functionality for configs, logs, errors, and onboarding.
|
||||
Generates plain-English explanations and suggestions for fixes.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, List
|
||||
import re
|
||||
import os
|
||||
|
||||
|
||||
def explain_config(config_key: str, config_value: Any, context: Optional[Dict] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Explain a configuration setting in plain English.
|
||||
|
||||
Args:
|
||||
config_key: Configuration key/name
|
||||
config_value: Current value of the configuration
|
||||
context: Additional context about the configuration
|
||||
|
||||
Returns:
|
||||
Dictionary with explanation and recommendations
|
||||
"""
|
||||
# Common configuration patterns and their explanations
|
||||
config_patterns = {
|
||||
r'.*timeout.*': {
|
||||
'description': 'Controls how long the system waits before giving up on an operation',
|
||||
'example': 'A timeout of 30 seconds means operations will be cancelled after 30s',
|
||||
'recommendations': [
|
||||
'Increase timeout for slow networks or large scans',
|
||||
'Decrease timeout for faster detection of unavailable services',
|
||||
'Typical values: 10-300 seconds'
|
||||
]
|
||||
},
|
||||
r'.*port.*': {
|
||||
'description': 'Specifies which network port to use for communication',
|
||||
'example': 'Port 8080 is commonly used for web applications',
|
||||
'recommendations': [
|
||||
'Use standard ports (80/443) for production',
|
||||
'Use high ports (8000+) for development',
|
||||
'Ensure port is not blocked by firewall'
|
||||
]
|
||||
},
|
||||
r'.*api[_-]?key.*': {
|
||||
'description': 'Authentication key for accessing external services',
|
||||
'example': 'API keys should be kept secret and not shared publicly',
|
||||
'recommendations': [
|
||||
'Store API keys in environment variables',
|
||||
'Never commit API keys to version control',
|
||||
'Rotate keys regularly for security'
|
||||
]
|
||||
},
|
||||
r'.*thread.*|.*worker.*': {
|
||||
'description': 'Controls parallel processing and concurrency',
|
||||
'example': '4 workers means 4 operations can run simultaneously',
|
||||
'recommendations': [
|
||||
'More workers = faster but more resource usage',
|
||||
'Typical range: number of CPU cores or 2x CPU cores',
|
||||
'Too many workers can overwhelm the system'
|
||||
]
|
||||
},
|
||||
r'.*rate[_-]?limit.*': {
|
||||
'description': 'Limits the frequency of operations to prevent overload',
|
||||
'example': 'Rate limit of 100/minute means max 100 requests per minute',
|
||||
'recommendations': [
|
||||
'Set based on target system capabilities',
|
||||
'Lower for sensitive or production targets',
|
||||
'Higher for testing environments'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Find matching pattern
|
||||
explanation = {
|
||||
'description': 'Configuration setting',
|
||||
'example': '',
|
||||
'recommendations': []
|
||||
}
|
||||
|
||||
for pattern, details in config_patterns.items():
|
||||
if re.search(pattern, config_key, re.IGNORECASE):
|
||||
explanation = details
|
||||
break
|
||||
|
||||
# Value-specific analysis
|
||||
value_analysis = _analyze_config_value(config_key, config_value)
|
||||
|
||||
return {
|
||||
'config_key': config_key,
|
||||
'current_value': str(config_value),
|
||||
'description': explanation['description'],
|
||||
'example': explanation['example'],
|
||||
'recommendations': explanation['recommendations'],
|
||||
'value_analysis': value_analysis,
|
||||
'safe_to_change': _is_safe_to_change(config_key),
|
||||
'requires_restart': _requires_restart(config_key)
|
||||
}
|
||||
|
||||
|
||||
def explain_error(error_message: str, error_type: Optional[str] = None, context: Optional[Dict] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Explain an error message in plain English with suggested fixes.
|
||||
|
||||
Args:
|
||||
error_message: The error message text
|
||||
error_type: Type/category of error (if known)
|
||||
context: Additional context about where/when the error occurred
|
||||
|
||||
Returns:
|
||||
Dictionary with explanation and fix suggestions
|
||||
"""
|
||||
# Common error patterns
|
||||
error_patterns = [
|
||||
{
|
||||
'pattern': r'connection\s+(refused|timed?\s?out|failed|reset)',
|
||||
'plain_english': 'Unable to connect to the target',
|
||||
'likely_causes': [
|
||||
'Target is offline or unreachable',
|
||||
'Firewall blocking the connection',
|
||||
'Wrong IP address or port',
|
||||
'Network connectivity issues'
|
||||
],
|
||||
'suggested_fixes': [
|
||||
'Verify target IP address is correct',
|
||||
'Check if target is online (ping test)',
|
||||
'Ensure no firewall is blocking the connection',
|
||||
'Try a different port or protocol'
|
||||
]
|
||||
},
|
||||
{
|
||||
'pattern': r'permission\s+denied|access\s+denied|forbidden',
|
||||
'plain_english': 'You don\'t have permission to perform this action',
|
||||
'likely_causes': [
|
||||
'Insufficient user privileges',
|
||||
'Authentication failed',
|
||||
'Resource is protected',
|
||||
'Rate limiting in effect'
|
||||
],
|
||||
'suggested_fixes': [
|
||||
'Run with appropriate privileges (sudo if needed)',
|
||||
'Check authentication credentials',
|
||||
'Verify you have permission to access this resource',
|
||||
'Wait before retrying (if rate limited)'
|
||||
]
|
||||
},
|
||||
{
|
||||
'pattern': r'not\s+found|does\s+not\s+exist|no\s+such',
|
||||
'plain_english': 'The requested resource could not be found',
|
||||
'likely_causes': [
|
||||
'Resource has been moved or deleted',
|
||||
'Incorrect path or name',
|
||||
'Typo in the request',
|
||||
'Resource not yet created'
|
||||
],
|
||||
'suggested_fixes': [
|
||||
'Check spelling and capitalization',
|
||||
'Verify the resource exists',
|
||||
'Check if path or URL is correct',
|
||||
'Create the resource if needed'
|
||||
]
|
||||
},
|
||||
{
|
||||
'pattern': r'invalid\s+(argument|parameter|input|syntax)',
|
||||
'plain_english': 'The input provided is not valid or in the wrong format',
|
||||
'likely_causes': [
|
||||
'Wrong data type or format',
|
||||
'Missing required parameter',
|
||||
'Value out of valid range',
|
||||
'Syntax error in command'
|
||||
],
|
||||
'suggested_fixes': [
|
||||
'Check documentation for correct format',
|
||||
'Verify all required parameters are provided',
|
||||
'Ensure values are within valid ranges',
|
||||
'Check for typos in the command'
|
||||
]
|
||||
},
|
||||
{
|
||||
'pattern': r'timeout|timed\s+out',
|
||||
'plain_english': 'The operation took too long and was cancelled',
|
||||
'likely_causes': [
|
||||
'Network is slow or congested',
|
||||
'Target is responding slowly',
|
||||
'Timeout setting is too low',
|
||||
'Large operation needs more time'
|
||||
],
|
||||
'suggested_fixes': [
|
||||
'Increase timeout value in settings',
|
||||
'Check network connectivity',
|
||||
'Try again during off-peak hours',
|
||||
'Break operation into smaller parts'
|
||||
]
|
||||
},
|
||||
{
|
||||
'pattern': r'out\s+of\s+memory|memory\s+error',
|
||||
'plain_english': 'The system ran out of available memory',
|
||||
'likely_causes': [
|
||||
'Too many concurrent operations',
|
||||
'Processing too much data at once',
|
||||
'Memory leak in the application',
|
||||
'Insufficient system resources'
|
||||
],
|
||||
'suggested_fixes': [
|
||||
'Reduce number of concurrent operations',
|
||||
'Process data in smaller batches',
|
||||
'Restart the application',
|
||||
'Add more RAM to the system'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
# Find matching pattern
|
||||
match_result = {
|
||||
'plain_english': 'An error occurred',
|
||||
'likely_causes': ['Unknown error condition'],
|
||||
'suggested_fixes': ['Check logs for more details', 'Try the operation again']
|
||||
}
|
||||
|
||||
error_lower = error_message.lower()
|
||||
for pattern_info in error_patterns:
|
||||
if re.search(pattern_info['pattern'], error_lower):
|
||||
match_result = {
|
||||
'plain_english': pattern_info['plain_english'],
|
||||
'likely_causes': pattern_info['likely_causes'],
|
||||
'suggested_fixes': pattern_info['suggested_fixes']
|
||||
}
|
||||
break
|
||||
|
||||
return {
|
||||
'original_error': error_message,
|
||||
'error_type': error_type or 'unknown',
|
||||
'plain_english': match_result['plain_english'],
|
||||
'likely_causes': match_result['likely_causes'],
|
||||
'suggested_fixes': match_result['suggested_fixes'],
|
||||
'severity': _assess_error_severity(error_message),
|
||||
'context': context or {}
|
||||
}
|
||||
|
||||
|
||||
def explain_log_entry(log_entry: str, log_level: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Explain a log entry in plain English.
|
||||
|
||||
Args:
|
||||
log_entry: The log message text
|
||||
log_level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
|
||||
Returns:
|
||||
Dictionary with explanation of the log entry
|
||||
"""
|
||||
# Detect log level if not provided
|
||||
if not log_level:
|
||||
log_level = _detect_log_level(log_entry)
|
||||
|
||||
# Extract key information from log
|
||||
extracted_info = _extract_log_info(log_entry)
|
||||
|
||||
# Determine if action is needed
|
||||
action_needed = log_level in ['ERROR', 'CRITICAL', 'WARNING']
|
||||
|
||||
explanation = {
|
||||
'log_entry': log_entry,
|
||||
'log_level': log_level,
|
||||
'timestamp': extracted_info.get('timestamp'),
|
||||
'component': extracted_info.get('component'),
|
||||
'message': extracted_info.get('message', log_entry),
|
||||
'action_needed': action_needed,
|
||||
'explanation': _generate_log_explanation(log_entry, log_level),
|
||||
'next_steps': _suggest_log_next_steps(log_entry, log_level) if action_needed else []
|
||||
}
|
||||
|
||||
return explanation
|
||||
|
||||
|
||||
def get_wizard_step_help(wizard_type: str, step_number: int) -> Dict[str, Any]:
|
||||
"""
|
||||
Get help text for a specific wizard step.
|
||||
|
||||
Args:
|
||||
wizard_type: Type of wizard (create_operation, onboard_agent, run_scan, first_time_setup)
|
||||
step_number: Current step number (1-indexed)
|
||||
|
||||
Returns:
|
||||
Dictionary with help information for the step
|
||||
"""
|
||||
wizard_help = {
|
||||
'create_operation': {
|
||||
1: {
|
||||
'title': 'Operation Name and Type',
|
||||
'description': 'Give your operation a memorable name and select the type of security assessment',
|
||||
'tips': [
|
||||
'Use descriptive names like "Q4 External Assessment" or "Web App Pentest"',
|
||||
'Choose the operation type that matches your goals',
|
||||
'You can change these later in settings'
|
||||
],
|
||||
'example': 'Example: "Internal Network Audit - Production"'
|
||||
},
|
||||
2: {
|
||||
'title': 'Define Target Scope',
|
||||
'description': 'Specify which systems, networks, or applications to include in the assessment',
|
||||
'tips': [
|
||||
'Use CIDR notation for network ranges (e.g., 192.168.1.0/24)',
|
||||
'Add individual hosts or domains as needed',
|
||||
'Clearly define what is in-scope and out-of-scope'
|
||||
],
|
||||
'example': 'Example: 192.168.1.0/24, app.example.com'
|
||||
},
|
||||
3: {
|
||||
'title': 'Configure Assessment Tools',
|
||||
'description': 'Select which security tools to use and configure their settings',
|
||||
'tips': [
|
||||
'Start with reconnaissance tools (nmap, whatweb)',
|
||||
'Add vulnerability scanners based on target type',
|
||||
'Adjust scan intensity based on target sensitivity'
|
||||
],
|
||||
'example': 'Example: nmap (aggressive), nikto (web servers only)'
|
||||
}
|
||||
},
|
||||
'run_scan': {
|
||||
1: {
|
||||
'title': 'Select Scan Tool',
|
||||
'description': 'Choose the security tool appropriate for your target',
|
||||
'tips': [
|
||||
'nmap: Network scanning and service detection',
|
||||
'nikto: Web server vulnerability scanning',
|
||||
'gobuster: Directory and file discovery',
|
||||
'sqlmap: SQL injection testing'
|
||||
],
|
||||
'example': 'For a web server, use nikto or gobuster'
|
||||
},
|
||||
2: {
|
||||
'title': 'Specify Target',
|
||||
'description': 'Enter the IP address, hostname, or network range to scan',
|
||||
'tips': [
|
||||
'Single host: 192.168.1.100 or example.com',
|
||||
'Network range: 192.168.1.0/24',
|
||||
'Multiple hosts: 192.168.1.1-50'
|
||||
],
|
||||
'example': 'Example: 192.168.1.0/24 for entire subnet'
|
||||
},
|
||||
3: {
|
||||
'title': 'Scan Options',
|
||||
'description': 'Configure scan parameters and intensity',
|
||||
'tips': [
|
||||
'Quick scan: Fast but less thorough',
|
||||
'Full scan: Comprehensive but slower',
|
||||
'Stealth: Slower but harder to detect'
|
||||
],
|
||||
'example': 'Use quick scan for initial reconnaissance'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
steps = wizard_help.get(wizard_type, {})
|
||||
step_help = steps.get(step_number, {
|
||||
'title': f'Step {step_number}',
|
||||
'description': 'Complete this step to continue',
|
||||
'tips': ['Fill in the required information'],
|
||||
'example': ''
|
||||
})
|
||||
|
||||
return {
|
||||
'wizard_type': wizard_type,
|
||||
'step_number': step_number,
|
||||
'total_steps': len(steps),
|
||||
**step_help
|
||||
}
|
||||
|
||||
|
||||
def suggest_fix(issue_description: str, context: Optional[Dict] = None) -> List[str]:
|
||||
"""
|
||||
Suggest fixes for a described issue.
|
||||
|
||||
Args:
|
||||
issue_description: Description of the problem
|
||||
context: Additional context (error codes, logs, etc.)
|
||||
|
||||
Returns:
|
||||
List of suggested fix actions
|
||||
"""
|
||||
issue_lower = issue_description.lower()
|
||||
fixes = []
|
||||
|
||||
# Connectivity issues
|
||||
if any(word in issue_lower for word in ['connect', 'network', 'reach', 'timeout']):
|
||||
fixes.extend([
|
||||
'Verify target is online with ping test',
|
||||
'Check firewall rules and network connectivity',
|
||||
'Ensure correct IP address and port number',
|
||||
'Try increasing timeout value in settings'
|
||||
])
|
||||
|
||||
# Permission issues
|
||||
if any(word in issue_lower for word in ['permission', 'access', 'denied', 'forbidden']):
|
||||
fixes.extend([
|
||||
'Run with elevated privileges (sudo)',
|
||||
'Check file/directory permissions',
|
||||
'Verify authentication credentials',
|
||||
'Ensure user has required roles/permissions'
|
||||
])
|
||||
|
||||
# Configuration issues
|
||||
if any(word in issue_lower for word in ['config', 'setting', 'option']):
|
||||
fixes.extend([
|
||||
'Review configuration file for errors',
|
||||
'Restore default configuration',
|
||||
'Check configuration documentation',
|
||||
'Validate configuration format (JSON/YAML)'
|
||||
])
|
||||
|
||||
# Tool/command issues
|
||||
if any(word in issue_lower for word in ['command', 'tool', 'not found', 'install']):
|
||||
fixes.extend([
|
||||
'Install the required tool or package',
|
||||
'Check if tool is in system PATH',
|
||||
'Verify tool name spelling',
|
||||
'Update tool to latest version'
|
||||
])
|
||||
|
||||
# Default suggestions if no specific fix found
|
||||
if not fixes:
|
||||
fixes = [
|
||||
'Check system logs for more details',
|
||||
'Restart the affected service',
|
||||
'Review recent configuration changes',
|
||||
'Consult documentation or support'
|
||||
]
|
||||
|
||||
return fixes[:5] # Return top 5 suggestions
|
||||
|
||||
|
||||
# Helper functions
|
||||
|
||||
def _analyze_config_value(key: str, value: Any) -> str:
|
||||
"""Analyze a configuration value and provide feedback."""
|
||||
if isinstance(value, int):
|
||||
if 'timeout' in key.lower():
|
||||
if value < 10:
|
||||
return 'Very low - may cause premature failures'
|
||||
elif value > 300:
|
||||
return 'Very high - operations may take long to fail'
|
||||
else:
|
||||
return 'Reasonable value'
|
||||
elif 'port' in key.lower():
|
||||
if value < 1024:
|
||||
return 'System port - requires elevated privileges'
|
||||
else:
|
||||
return 'User port - no special privileges needed'
|
||||
|
||||
return 'Current value seems valid'
|
||||
|
||||
|
||||
def _is_safe_to_change(config_key: str) -> bool:
|
||||
"""Determine if a config is safe to change without risk."""
|
||||
unsafe_keys = ['database', 'credential', 'key', 'secret', 'password']
|
||||
return not any(unsafe in config_key.lower() for unsafe in unsafe_keys)
|
||||
|
||||
|
||||
def _requires_restart(config_key: str) -> bool:
|
||||
"""Determine if changing this config requires a restart."""
|
||||
restart_keys = ['port', 'host', 'database', 'worker', 'thread']
|
||||
return any(key in config_key.lower() for key in restart_keys)
|
||||
|
||||
|
||||
def _assess_error_severity(error_message: str) -> str:
|
||||
"""Assess the severity of an error."""
|
||||
error_lower = error_message.lower()
|
||||
|
||||
if any(word in error_lower for word in ['critical', 'fatal', 'crash', 'panic']):
|
||||
return 'critical'
|
||||
elif any(word in error_lower for word in ['error', 'fail', 'exception']):
|
||||
return 'high'
|
||||
elif any(word in error_lower for word in ['warning', 'warn']):
|
||||
return 'medium'
|
||||
else:
|
||||
return 'low'
|
||||
|
||||
|
||||
def _detect_log_level(log_entry: str) -> str:
|
||||
"""Detect log level from log entry."""
|
||||
levels = ['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']
|
||||
for level in levels:
|
||||
if level in log_entry.upper():
|
||||
return level
|
||||
return 'INFO'
|
||||
|
||||
|
||||
def _extract_log_info(log_entry: str) -> Dict[str, str]:
|
||||
"""Extract structured information from a log entry."""
|
||||
info = {}
|
||||
|
||||
# Try to extract timestamp
|
||||
timestamp_pattern = r'\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}:\d{2}'
|
||||
timestamp_match = re.search(timestamp_pattern, log_entry)
|
||||
if timestamp_match:
|
||||
info['timestamp'] = timestamp_match.group()
|
||||
|
||||
# Try to extract component/module name
|
||||
component_pattern = r'\[(\w+)\]'
|
||||
component_match = re.search(component_pattern, log_entry)
|
||||
if component_match:
|
||||
info['component'] = component_match.group(1)
|
||||
|
||||
# Extract the main message
|
||||
parts = log_entry.split(':', 1)
|
||||
if len(parts) > 1:
|
||||
info['message'] = parts[1].strip()
|
||||
else:
|
||||
info['message'] = log_entry
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def _generate_log_explanation(log_entry: str, log_level: str) -> str:
|
||||
"""Generate a plain English explanation of a log entry."""
|
||||
if log_level == 'ERROR':
|
||||
return 'An error occurred that may require attention. Check the details to understand what went wrong.'
|
||||
elif log_level == 'WARNING':
|
||||
return 'A potential issue was detected. It may not be critical but should be reviewed.'
|
||||
elif log_level == 'INFO':
|
||||
return 'Normal operational message providing status information.'
|
||||
elif log_level == 'DEBUG':
|
||||
return 'Detailed diagnostic information useful for troubleshooting.'
|
||||
else:
|
||||
return 'Log entry documenting system activity.'
|
||||
|
||||
|
||||
def _suggest_log_next_steps(log_entry: str, log_level: str) -> List[str]:
|
||||
"""Suggest next steps based on log entry."""
|
||||
steps = []
|
||||
|
||||
if log_level in ['ERROR', 'CRITICAL']:
|
||||
steps.append('Review the error details and check related logs')
|
||||
steps.append('Check if the issue is repeating or isolated')
|
||||
steps.append('Consider rolling back recent changes if applicable')
|
||||
|
||||
if log_level == 'WARNING':
|
||||
steps.append('Monitor for repeated warnings')
|
||||
steps.append('Check if this indicates a trend or pattern')
|
||||
|
||||
if 'connection' in log_entry.lower():
|
||||
steps.append('Verify network connectivity to the target')
|
||||
|
||||
if 'timeout' in log_entry.lower():
|
||||
steps.append('Consider increasing timeout values')
|
||||
|
||||
return steps
|
||||
Reference in New Issue
Block a user