Files
macha-autonomous/notifier.py
Lily Miller 22ba493d9e Initial commit: Split Macha autonomous system into separate flake
Macha is now a standalone NixOS flake that can be imported into other
systems. This provides:

- Independent versioning
- Easier reusability
- Cleaner separation of concerns
- Better development workflow

Includes:
- Complete autonomous system code
- NixOS module with full configuration options
- Queue-based architecture with priority system
- Chunked map-reduce for large outputs
- ChromaDB knowledge base
- Tool calling system
- Multi-host SSH management
- Gotify notification integration

All capabilities from DESIGN.md are preserved.
2025-10-06 14:32:37 -06:00

249 lines
7.6 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Gotify Notifier - Send notifications to Gotify server
"""
import requests
import os
from typing import Optional
from datetime import datetime
class GotifyNotifier:
"""Send notifications to Gotify server"""
# Priority levels
PRIORITY_LOW = 2
PRIORITY_MEDIUM = 5
PRIORITY_HIGH = 8
def __init__(
self,
gotify_url: Optional[str] = None,
gotify_token: Optional[str] = None
):
"""
Initialize Gotify notifier
Args:
gotify_url: URL to Gotify server (e.g. http://rhiannon:8181)
gotify_token: Application token from Gotify
"""
self.gotify_url = gotify_url or os.environ.get("GOTIFY_URL", "")
self.gotify_token = gotify_token or os.environ.get("GOTIFY_TOKEN", "")
self.enabled = bool(self.gotify_url and self.gotify_token)
def send(
self,
title: str,
message: str,
priority: int = PRIORITY_MEDIUM,
extras: Optional[dict] = None
) -> bool:
"""
Send a notification to Gotify
Args:
title: Notification title
message: Notification message
priority: Priority level (2=low, 5=medium, 8=high)
extras: Optional extra data
Returns:
True if successful, False otherwise
"""
if not self.enabled:
return False
try:
url = f"{self.gotify_url}/message"
headers = {
"Authorization": f"Bearer {self.gotify_token}",
"Content-Type": "application/json"
}
data = {
"title": title,
"message": message,
"priority": priority,
}
if extras:
data["extras"] = extras
response = requests.post(
url,
json=data,
headers=headers,
timeout=10
)
return response.status_code == 200
except Exception as e:
# Fail silently - don't crash if Gotify is unavailable
print(f"Warning: Failed to send Gotify notification: {e}")
return False
def notify_critical_issue(self, issue_description: str, details: str = ""):
"""Send high-priority notification for critical issues"""
message = f"⚠️ Critical Issue Detected\n\n{issue_description}"
if details:
message += f"\n\nDetails:\n{details}"
return self.send(
title="🚨 Macha: Critical Issue",
message=message,
priority=self.PRIORITY_HIGH
)
def notify_issue_created(self, issue_id: str, title: str, severity: str):
"""Send notification when a new issue is created"""
severity_icons = {
"low": "",
"medium": "⚠️",
"high": "🚨",
"critical": "🔴"
}
icon = severity_icons.get(severity, "⚠️")
priority_map = {
"low": self.PRIORITY_LOW,
"medium": self.PRIORITY_MEDIUM,
"high": self.PRIORITY_HIGH,
"critical": self.PRIORITY_HIGH
}
priority = priority_map.get(severity, self.PRIORITY_MEDIUM)
message = f"{icon} New Issue Tracked\n\nID: {issue_id}\nSeverity: {severity.upper()}\n\n{title}"
return self.send(
title="📋 Macha: Issue Created",
message=message,
priority=priority
)
def notify_action_queued(self, action_description: str, risk_level: str):
"""Send notification when action is queued for approval"""
emoji = "⚠️" if risk_level == "high" else ""
message = (
f"{emoji} Action Queued for Approval\n\n"
f"Action: {action_description}\n"
f"Risk Level: {risk_level}\n\n"
f"Use 'macha-approve list' to review"
)
priority = self.PRIORITY_HIGH if risk_level == "high" else self.PRIORITY_MEDIUM
return self.send(
title="📋 Macha: Action Needs Approval",
message=message,
priority=priority
)
def notify_action_executed(self, action_description: str, success: bool, output: str = ""):
"""Send notification when action is executed"""
if success:
emoji = ""
title_prefix = "Success"
else:
emoji = ""
title_prefix = "Failed"
message = f"{emoji} Action {title_prefix}\n\n{action_description}"
if output:
message += f"\n\nOutput:\n{output[:500]}" # Limit output length
priority = self.PRIORITY_HIGH if not success else self.PRIORITY_LOW
return self.send(
title=f"{emoji} Macha: Action {title_prefix}",
message=message,
priority=priority
)
def notify_service_failure(self, service_name: str, details: str = ""):
"""Send notification for service failures"""
message = f"🔴 Service Failed: {service_name}"
if details:
message += f"\n\nDetails:\n{details}"
return self.send(
title="🔴 Macha: Service Failure",
message=message,
priority=self.PRIORITY_HIGH
)
def notify_health_summary(self, summary: str, status: str):
"""Send periodic health summary"""
emoji = {
"healthy": "",
"attention_needed": "⚠️",
"intervention_required": "🚨"
}.get(status, "")
priority = {
"healthy": self.PRIORITY_LOW,
"attention_needed": self.PRIORITY_MEDIUM,
"intervention_required": self.PRIORITY_HIGH
}.get(status, self.PRIORITY_MEDIUM)
return self.send(
title=f"{emoji} Macha: Health Check",
message=summary,
priority=priority
)
def send_system_discovered(
self,
hostname: str,
os_type: str,
role: str,
services_count: int
):
"""Send notification when a new system is discovered"""
message = (
f"🔍 New System Auto-Discovered\n\n"
f"Hostname: {hostname}\n"
f"OS: {os_type.upper()}\n"
f"Role: {role}\n"
f"Services: {services_count} detected\n\n"
f"System has been registered and analyzed.\n"
f"Use 'macha-systems' to view all registered systems."
)
return self.send(
title="🌐 Macha: New System Discovered",
message=message,
priority=self.PRIORITY_MEDIUM
)
if __name__ == "__main__":
import sys
# Test the notifier
if len(sys.argv) < 3:
print("Usage: notifier.py <title> <message> [priority]")
print("Example: notifier.py 'Test' 'This is a test message' 5")
sys.exit(1)
title = sys.argv[1]
message = sys.argv[2]
priority = int(sys.argv[3]) if len(sys.argv) > 3 else GotifyNotifier.PRIORITY_MEDIUM
notifier = GotifyNotifier()
if not notifier.enabled:
print("Error: Gotify not configured (GOTIFY_URL and GOTIFY_TOKEN required)")
sys.exit(1)
success = notifier.send(title, message, priority)
if success:
print("✅ Notification sent successfully")
else:
print("❌ Failed to send notification")
sys.exit(1)