Cuts release 0.20.0. ## Highlights - X-Request-ID header on every response + sanitized to [A-Za-z0-9_-] (CRLF log-forging mitigation) - Error pages (HTML + JSON 500) surface request_id for support tickets - Dev debug toolbar gated by DEBUG=1 — fastapi-debug-toolbar with custom DuckDBPanel - Centralized app.logging_config.setup_logging() replaces 23 scattered basicConfig calls - Telegram bot drops bot.log file — stdout only (BREAKING) ## Devin findings addressed - BUG_0001: .env.template no longer claims FastAPI debug=True - BUG_0002: subprocess extractor logs INFO to stderr again - ANALYSIS_0003: _wants_html no longer matches Accept: */* (curl gets JSON as before) - BUG on b1c6ee9: HTML 500 page no longer leaks str(exc) in production - BUG on b13d2fe: 2 CLAUDE.md compliance flags (transform.py + ws_gateway) accepted as scope-limited logging refactor — follow-up to update CLAUDE.md if needed See CHANGELOG [0.20.0] for full notes.
44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
"""
|
|
Shared notification dispatch to WebSocket gateway.
|
|
|
|
Used by both the Telegram bot and the webapp REST API to push
|
|
notifications to connected desktop app clients.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import time
|
|
import uuid
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
WS_GATEWAY_SOCKET_PATH = os.environ.get("WS_GATEWAY_SOCKET", "/run/ws-gateway/ws.sock")
|
|
|
|
|
|
def dispatch_to_ws_gateway(username: str, output: dict, script_name: str) -> None:
|
|
"""Dispatch notification to WebSocket gateway for desktop app clients."""
|
|
if not os.path.exists(WS_GATEWAY_SOCKET_PATH):
|
|
return
|
|
try:
|
|
import httpx
|
|
|
|
transport = httpx.HTTPTransport(uds=WS_GATEWAY_SOCKET_PATH)
|
|
with httpx.Client(transport=transport, timeout=10) as client:
|
|
notification = {
|
|
"id": str(uuid.uuid4()),
|
|
"title": output.get("title", ""),
|
|
"message": output.get("message", ""),
|
|
"script": script_name,
|
|
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
}
|
|
image_path = output.get("image_path", "")
|
|
if image_path and os.path.isfile(image_path):
|
|
filename = os.path.basename(image_path)
|
|
notification["image_url"] = f"/api/notifications/images/{filename}"
|
|
client.post(
|
|
"http://localhost/dispatch",
|
|
json={"user": username, "notification": notification},
|
|
)
|
|
except Exception:
|
|
logger.exception("WS gateway dispatch failed")
|