feat: daily report agent version line and fix active users layout

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
PTah
2026-05-31 11:28:30 +10:00
parent 799f8668e6
commit a45b641b8c
2 changed files with 68 additions and 9 deletions
+57 -7
View File
@@ -16,6 +16,8 @@ SSH_BAN_TYPES = frozenset({"ssh.ip.banned"})
_SERVER_LINE_RE = re.compile(r"(?m)^🖥️\s*Сервер\s*:")
_ACTIVE_USERS_HEADER_RE = re.compile(r"^👥\s*АКТИВНЫЕ ПОЛЬЗОВАТЕЛИ")
_AGENT_VERSION_LINE_RE = re.compile(r"(?m)^Agent version\s+", re.IGNORECASE)
_DAILY_REPORT_TITLE_MARKER = "ЕЖЕДНЕВНЫЙ ОТЧЕТ"
_SECTION_HEADER_RE = re.compile(r"^[📈🧾👥🖥️🕐]")
@@ -76,6 +78,39 @@ def normalize_active_users_list(users: list[Any] | None) -> list[str]:
return out
def format_agent_version_line(version: str) -> str:
v = (version or "").strip()
if not v:
return ""
return f"Agent version {v}"
def ensure_agent_version_line(body: str, version: str | None) -> str:
line = format_agent_version_line(version or "")
if not line:
return body
if _AGENT_VERSION_LINE_RE.search(body):
return body
lines = body.replace("\r\n", "\n").split("\n")
for i, ln in enumerate(lines):
if _DAILY_REPORT_TITLE_MARKER in ln:
lines.insert(i + 1, line)
return "\n".join(lines)
return body
def _fix_active_users_header_count(header_line: str, user_count: int) -> str:
stripped = header_line.rstrip()
if _ACTIVE_USERS_COUNT_RE.match(stripped):
return re.sub(
r"(\👥\s*АКТИВНЫЕ ПОЛЬЗОВАТЕЛИ\s*\()[^)]+(\))",
rf"\g<1>{user_count}\2",
stripped,
count=1,
)
return stripped
def ensure_server_line(body: str, host: Host | None) -> str:
server = host_server_line(host)
if not server or server == "unknown":
@@ -85,7 +120,10 @@ def ensure_server_line(body: str, host: Host | None) -> str:
lines = body.replace("\r\n", "\n").split("\n")
for i, line in enumerate(lines):
if "ЕЖЕДНЕВНЫЙ ОТЧЕТ" in line:
lines.insert(i + 1, f"🖥️ Сервер: {server}")
insert_at = i + 1
if insert_at < len(lines) and _AGENT_VERSION_LINE_RE.match(lines[insert_at].strip()):
insert_at += 1
lines.insert(insert_at, f"🖥️ Сервер: {server}")
return "\n".join(lines)
return f"🖥️ Сервер: {server}\n{body}"
@@ -116,6 +154,7 @@ def normalize_active_users_in_body(body: str) -> str:
user_lines.extend(split_active_user_tokens(cur))
i += 1
if user_lines:
out[-1] = _fix_active_users_header_count(out[-1], len(user_lines))
out.extend(user_lines)
continue
out.append(line)
@@ -126,6 +165,8 @@ def normalize_active_users_in_body(body: str) -> str:
def normalize_report_body(body: str, host: Host | None, platform: Platform) -> str:
"""Приводит текст отчёта (агент/SAC) к единому компактному виду."""
text = collapse_blank_lines(body.replace("\r\n", "\n"))
agent_version = host.product_version if host else None
text = ensure_agent_version_line(text, agent_version)
text = ensure_server_line(text, host)
text = normalize_active_users_in_body(text)
return collapse_blank_lines(text)
@@ -173,6 +214,11 @@ def build_report_body(
time_str = when_local.strftime("%d.%m.%Y %H:%M:%S")
top = list(stats.get("top_failed_ips") or [])[:5]
active_users = normalize_active_users_list(list(stats.get("active_users") or []))
agent_version = (
str(stats.get("agent_version") or stats.get("product_version") or host.product_version or "")
).strip()
if sac_generated and not agent_version:
agent_version = "sac"
if platform == "ssh":
title = "📊 ЕЖЕДНЕВНЫЙ ОТЧЕТ SSH МОНИТОРИНГА"
@@ -180,8 +226,10 @@ def build_report_body(
fail = int(stats.get("failed_logins", stats.get("failed_ssh", 0)))
sudo = int(stats.get("sudo_commands", 0))
bans = int(stats.get("active_bans", 0))
lines = [
title,
lines = [title]
if agent_version:
lines.append(format_agent_version_line(agent_version))
lines.extend([
f"🖥️ Сервер: {server}",
f"🕐 Время отчета: {time_str}",
"",
@@ -190,14 +238,16 @@ def build_report_body(
f" ❌ Неудачных попыток SSH: {fail}",
f" ⚠️ Команд через sudo: {sudo}",
f" 🚫 Активных банов (ipset): {bans}",
]
])
else:
title = "📊 ЕЖЕДНЕВНЫЙ ОТЧЕТ МОНИТОРИНГА WINDOWS"
ok = int(stats.get("successful_logins", stats.get("rdp_success", 0)))
fail = int(stats.get("failed_logins", stats.get("rdp_failed", 0)))
bans = int(stats.get("active_bans", 0))
lines = [
title,
lines = [title]
if agent_version:
lines.append(format_agent_version_line(agent_version))
lines.extend([
f"🖥️ Сервер: {server}",
f"🕐 Время отчета: {time_str}",
"",
@@ -205,7 +255,7 @@ def build_report_body(
f" ✅ Успешных RDP подключений: {ok}",
f" ❌ Неудачных попыток RDP: {fail}",
f" 🚫 Активных банов: {bans}",
]
])
lines.append("")
lines.extend(_section_top_ips(top))