#!/usr/bin/env python3
"""
NoctisAI Health Check Script
Quick health check for all services and components
"""
import sys
import os
import json
import time
import subprocess
import psutil
from pathlib import Path
class NoctisAIHealthCheck:
def __init__(self):
self.base_dir = Path(__file__).parent.parent
self.health_status = {
"overall": "healthy",
"services": {},
"issues": []
}
def log(self, message, level="INFO"):
"""Log messages with timestamps"""
timestamp = time.strftime("%H:%M:%S")
print(f"[{timestamp}] [{level}] {message}")
def check_python_environment(self):
"""Check Python environment health"""
try:
python_version = sys.version_info
if python_version.major < 3 or (python_version.major == 3 and python_version.minor < 8):
self.health_status["issues"].append("Python version too old")
return False
# Check virtual environment
if not (hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix)):
self.health_status["issues"].append("No virtual environment detected")
return False
self.health_status["services"]["python"] = "healthy"
return True
except Exception as e:
self.health_status["issues"].append(f"Python environment error: {e}")
return False
def check_dependencies(self):
"""Check critical dependencies"""
critical_deps = ['fastapi', 'uvicorn', 'mcp', 'requests', 'cryptography']
missing_deps = []
for dep in critical_deps:
try:
__import__(dep)
except ImportError:
missing_deps.append(dep)
if missing_deps:
self.health_status["issues"].append(f"Missing dependencies: {', '.join(missing_deps)}")
self.health_status["services"]["dependencies"] = "unhealthy"
return False
else:
self.health_status["services"]["dependencies"] = "healthy"
return True
def check_file_structure(self):
"""Check critical files and directories"""
critical_files = [
"src/noctis_ai/mcp/noctis_mcp.py",
"src/noctis_ai/mcp/malware_tools.py",
"src/noctis_ai/mcp/thesilencer_integration.py",
"run_noctis_mcp.py",
"requirements.txt"
]
missing_files = []
for file_path in critical_files:
if not (self.base_dir / file_path).exists():
missing_files.append(file_path)
if missing_files:
self.health_status["issues"].append(f"Missing files: {', '.join(missing_files)}")
self.health_status["services"]["file_structure"] = "unhealthy"
return False
else:
self.health_status["services"]["file_structure"] = "healthy"
return True
def check_output_directories(self):
"""Check output directories"""
output_dirs = ["output", "output/thesilencer", "logs"]
for dir_path in output_dirs:
full_path = self.base_dir / dir_path
if not full_path.exists():
try:
full_path.mkdir(parents=True, exist_ok=True)
except Exception as e:
self.health_status["issues"].append(f"Cannot create directory {dir_path}: {e}")
return False
self.health_status["services"]["output_directories"] = "healthy"
return True
def check_mcp_configuration(self):
"""Check MCP configuration"""
mcp_config_path = Path.home() / ".cursor" / "mcp.json"
if not mcp_config_path.exists():
self.health_status["issues"].append("MCP configuration file not found")
self.health_status["services"]["mcp_config"] = "unhealthy"
return False
try:
with open(mcp_config_path, 'r') as f:
config = json.load(f)
if "noctis-ai" not in config.get("mcpServers", {}):
self.health_status["issues"].append("NoctisAI not configured in MCP")
self.health_status["services"]["mcp_config"] = "unhealthy"
return False
self.health_status["services"]["mcp_config"] = "healthy"
return True
except Exception as e:
self.health_status["issues"].append(f"MCP configuration error: {e}")
self.health_status["services"]["mcp_config"] = "unhealthy"
return False
def check_running_processes(self):
"""Check for running NoctisAI processes"""
noctisai_processes = []
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
try:
cmdline = ' '.join(proc.info['cmdline']) if proc.info['cmdline'] else ''
if 'noctis' in cmdline.lower() or 'run_noctis_mcp' in cmdline:
noctisai_processes.append(proc.info['pid'])
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if noctisai_processes:
self.health_status["services"]["running_processes"] = "healthy"
self.log(f"Found running NoctisAI processes: {noctisai_processes}")
else:
self.health_status["services"]["running_processes"] = "not_running"
self.log("No running NoctisAI processes found")
return True
def check_network_connectivity(self):
"""Check basic network connectivity"""
try:
import requests
response = requests.get("https://www.google.com", timeout=5)
if response.status_code == 200:
self.health_status["services"]["network"] = "healthy"
return True
else:
self.health_status["issues"].append("Network connectivity issues")
self.health_status["services"]["network"] = "unhealthy"
return False
except Exception as e:
self.health_status["issues"].append(f"Network connectivity error: {e}")
self.health_status["services"]["network"] = "unhealthy"
return False
def check_disk_space(self):
"""Check available disk space"""
try:
disk_usage = psutil.disk_usage(self.base_dir)
free_gb = disk_usage.free / (1024**3)
if free_gb < 1.0: # Less than 1GB free
self.health_status["issues"].append(f"Low disk space: {free_gb:.1f}GB free")
self.health_status["services"]["disk_space"] = "unhealthy"
return False
else:
self.health_status["services"]["disk_space"] = "healthy"
return True
except Exception as e:
self.health_status["issues"].append(f"Disk space check error: {e}")
return False
def run_health_check(self):
"""Run complete health check"""
self.log("š„ Starting NoctisAI health check...")
self.log("=" * 50)
checks = [
("Python Environment", self.check_python_environment),
("Dependencies", self.check_dependencies),
("File Structure", self.check_file_structure),
("Output Directories", self.check_output_directories),
("MCP Configuration", self.check_mcp_configuration),
("Running Processes", self.check_running_processes),
("Network Connectivity", self.check_network_connectivity),
("Disk Space", self.check_disk_space)
]
for check_name, check_func in checks:
try:
self.log(f"Checking {check_name}...")
check_func()
except Exception as e:
self.health_status["issues"].append(f"{check_name} check failed: {e}")
self.health_status["services"][check_name.lower().replace(" ", "_")] = "error"
# Determine overall health
if self.health_status["issues"]:
self.health_status["overall"] = "unhealthy"
else:
self.health_status["overall"] = "healthy"
self.print_health_report()
return self.health_status["overall"] == "healthy"
def print_health_report(self):
"""Print health check report"""
self.log("=" * 50)
self.log("š HEALTH CHECK REPORT")
self.log("=" * 50)
# Overall status
status_emoji = "ā
" if self.health_status["overall"] == "healthy" else "ā"
self.log(f"{status_emoji} Overall Status: {self.health_status['overall'].upper()}")
# Service status
self.log("\nš§ Service Status:")
for service, status in self.health_status["services"].items():
status_emoji = "ā
" if status == "healthy" else "ā ļø" if status == "not_running" else "ā"
self.log(f" {status_emoji} {service.replace('_', ' ').title()}: {status}")
# Issues
if self.health_status["issues"]:
self.log("\nšØ Issues Found:")
for issue in self.health_status["issues"]:
self.log(f" ⢠{issue}")
else:
self.log("\nš No issues found!")
# Recommendations
self.log("\nš” Recommendations:")
if self.health_status["services"].get("running_processes") == "not_running":
self.log(" ⢠Start NoctisAI: python run_noctis_mcp.py")
if "Missing dependencies" in str(self.health_status["issues"]):
self.log(" ⢠Install dependencies: pip install -r requirements.txt")
if "MCP configuration" in str(self.health_status["issues"]):
self.log(" ⢠Configure MCP: Add NoctisAI to ~/.cursor/mcp.json")
if "Low disk space" in str(self.health_status["issues"]):
self.log(" ⢠Free up disk space")
def get_health_status(self):
"""Get current health status"""
return self.health_status
def main():
"""Main health check runner"""
health_checker = NoctisAIHealthCheck()
is_healthy = health_checker.run_health_check()
sys.exit(0 if is_healthy else 1)
if __name__ == "__main__":
main()