fix: suppress sudo Telegram during SAC agent update (v0.5.3)
This commit is contained in:
@@ -15,6 +15,14 @@ from app.services.notification_severity import severity_meets_minimum
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
LIFECYCLE_EVENT_TYPE = "agent.lifecycle"
|
||||
PRIVILEGE_SUDO_TYPE = "privilege.sudo.command"
|
||||
SUDO_MAINTENANCE_MARKERS = (
|
||||
"update_ssh_monitor.sh",
|
||||
"update_via_sac",
|
||||
"update_script.log",
|
||||
"/opt/scripts/update",
|
||||
"agent-update-in-progress",
|
||||
)
|
||||
DAILY_REPORT_EVENT_TYPES = frozenset({"report.daily.ssh", "report.daily.rdp"})
|
||||
AUTH_LOGIN_SUCCESS_TYPES = frozenset({"rdp.login.success", "ssh.login.success"})
|
||||
RDG_CONNECTION_TYPES = frozenset({
|
||||
@@ -67,6 +75,8 @@ def notify_event(event: Event, *, db: Session | None = None) -> None:
|
||||
# Heartbeat — только для UI/статуса хоста, не для Telegram/email/push.
|
||||
if event.type == HEARTBEAT_TYPE:
|
||||
return
|
||||
if _should_suppress_sudo_notify(event, db=db):
|
||||
return
|
||||
if _skip_notifications_for_hidden_event(event, db):
|
||||
return
|
||||
policy = get_effective_notification_policy(db)
|
||||
@@ -112,7 +122,7 @@ def notify_daily_report(event: Event, *, db: Session | None = None) -> None:
|
||||
|
||||
|
||||
def _host_sac_update_running(event: Event, db: Session | None) -> bool:
|
||||
"""Пока SAC выполняет agent-update на хосте — не слать lifecycle в Telegram."""
|
||||
"""Пока SAC выполняет agent-update на хосте — не слать шумные TG."""
|
||||
if db is None or not event.host_id:
|
||||
return False
|
||||
host = db.get(Host, event.host_id)
|
||||
@@ -120,7 +130,8 @@ def _host_sac_update_running(event: Event, db: Session | None) -> bool:
|
||||
return False
|
||||
if (host.agent_update_state or "").strip().lower() == "running":
|
||||
logger.info(
|
||||
"notify lifecycle skipped host update running host_id=%s event_id=%s",
|
||||
"notify skipped (host update running) type=%s host_id=%s event_id=%s",
|
||||
event.type,
|
||||
host.id,
|
||||
event.event_id,
|
||||
)
|
||||
@@ -128,6 +139,30 @@ def _host_sac_update_running(event: Event, db: Session | None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _sudo_event_is_agent_maintenance(event: Event) -> bool:
|
||||
details = event.details if isinstance(event.details, dict) else {}
|
||||
cmd = str(details.get("command") or "").strip()
|
||||
if not cmd:
|
||||
cmd = str(event.summary or "").strip()
|
||||
text = cmd.casefold()
|
||||
return any(marker in text for marker in SUDO_MAINTENANCE_MARKERS)
|
||||
|
||||
|
||||
def _should_suppress_sudo_notify(event: Event, *, db: Session | None) -> bool:
|
||||
if event.type != PRIVILEGE_SUDO_TYPE:
|
||||
return False
|
||||
if _host_sac_update_running(event, db):
|
||||
return True
|
||||
if _sudo_event_is_agent_maintenance(event):
|
||||
logger.info(
|
||||
"notify sudo skipped maintenance command event_id=%s host_id=%s",
|
||||
event.event_id,
|
||||
event.host_id,
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _lifecycle_suppress_notifications(event: Event, *, db: Session | None = None) -> bool:
|
||||
"""Не слать TG при штатном SAC/cron update (lifecycle с trigger deploy_recycle)."""
|
||||
if _host_sac_update_running(event, db):
|
||||
|
||||
@@ -9,6 +9,7 @@ from dataclasses import dataclass
|
||||
from app.config import get_settings
|
||||
from app.models import Host
|
||||
|
||||
SSH_MONITOR_UPDATE_STATE_FILE = "/var/lib/ssh-monitor/agent-update-in-progress"
|
||||
SSH_MONITOR_UPDATE_LOG_PATH = "/var/log/update_script.log"
|
||||
SSH_MONITOR_UPDATE_SCRIPT = "/opt/scripts/update_ssh_monitor.sh"
|
||||
SSH_MONITOR_UPDATE_DIR = "/opt/scripts/update"
|
||||
@@ -454,6 +455,15 @@ def _ssh_monitor_bootstrap_command(repo_url: str, *, git_branch: str = "main") -
|
||||
)
|
||||
|
||||
|
||||
def _ssh_monitor_mark_update_begin_prefix() -> str:
|
||||
"""State-file до updater: lifecycle/sudo на агенте глушатся раньше bootstrap."""
|
||||
return (
|
||||
f"mkdir -p /var/lib/ssh-monitor && "
|
||||
f"date +%s > {SSH_MONITOR_UPDATE_STATE_FILE} && "
|
||||
f"chmod 600 {SSH_MONITOR_UPDATE_STATE_FILE} 2>/dev/null; "
|
||||
)
|
||||
|
||||
|
||||
def run_ssh_monitor_update(
|
||||
*,
|
||||
target: str,
|
||||
@@ -498,7 +508,7 @@ def run_ssh_monitor_update(
|
||||
target=target,
|
||||
user=user,
|
||||
password=password,
|
||||
remote_cmd=bootstrap_cmd,
|
||||
remote_cmd=_ssh_monitor_mark_update_begin_prefix() + bootstrap_cmd,
|
||||
command_timeout_sec=900,
|
||||
need_root=True,
|
||||
login_shell=False,
|
||||
@@ -509,7 +519,7 @@ def run_ssh_monitor_update(
|
||||
target=target,
|
||||
user=user,
|
||||
password=password,
|
||||
remote_cmd=update_cmd,
|
||||
remote_cmd=_ssh_monitor_mark_update_begin_prefix() + update_cmd,
|
||||
command_timeout_sec=900,
|
||||
need_root=True,
|
||||
login_shell=False,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
||||
|
||||
APP_NAME = "Security Alert Center"
|
||||
APP_VERSION = "0.5.2"
|
||||
APP_VERSION = "0.5.3"
|
||||
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
- [ ] При **shutdown** / `SIGTERM` не увеличивать `sac-fail.count` (или отдельный флаг «update in progress»).
|
||||
- [ ] После успешного heartbeat сбрасывать fail counter агрессивнее (уже частично есть).
|
||||
- [x] Watchdog: не слать Telegram при штатном restart во время SAC-update (state file `/var/lib/ssh-monitor/agent-update-in-progress` от updater) — **2.2.1-SAC**
|
||||
- [x] Lifecycle stop/start при SAC-update: подавление на агенте + state file — **2.2.1-SAC**
|
||||
- [x] Sudo bootstrap/update через SAC: не слать Telegram (`ssh_monitor_sudo_is_sac_maintenance`, state-file раньше) — **2.2.3-SAC**
|
||||
- [x] SAC: suppress `privilege.sudo.command` при `agent_update_state=running` / maintenance command — **0.5.3**
|
||||
- [ ] Документировать рекомендуемый `SAC_TIMEOUT_SEC` при тяжёлом ingest (сейчас 45s).
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user