Skip to content

Releases: DrFaustos/techsupp_diagtool

v1.32.29

Choose a tag to compare

@github-actions github-actions released this 29 Oct 06:39

Релиз 1.32.29: состояние службы решает код возврата

v1.32.28

Choose a tag to compare

@github-actions github-actions released this 28 Oct 21:04

Релиз 1.32.28: история в CI целиком, бинарь из прогона

SSH Диагностика сервера v1.1.1

Choose a tag to compare

@DrFaustos DrFaustos released this 10 Oct 16:01

[1.1.1] — 2026-10-10

Добавлено

  • Тесты backend-модулей (tests/test_metrics.py, tests/test_files.py,
    tests/test_webcheck.py): 40 проверок без реального SSH (через FakeSSH).
    Покрытие webcheck.py 39%→100%, metrics.py 60%→98%, files.py 59%→98%;
    общее 60%→64%. Проверяются определение панели, статусы служб (имя=статус),
    сетевой отчёт с NAT-разбором, запись/чтение файлов с бэкапом, grep по
    логам с флагом контекста, SSL-срок и разбор WHOIS.
  • Тесты ssh_client.py (tests/test_ssh_client.py): 19 проверок с
    подменённым paramiko — подключение по паролю и ключу (пароль стирается из
    объекта после connect/failure), RejectPolicy против MITM, разбор
    AuthenticationException/SSHException/прочих ошибок, is_alive, чтение
    stdout/stderr по потокам, отмена через cancel_event, close(). Покрытие
    модуля 13%→92%, общее 64%→66%.
  • Тесты gui_swap.py (tests/test_gui_swap.py): 10 проверок логики swap
    без Tk — проверка свободного места перед созданием файла (df -m, отмена при
    нехватке и при нечисловом выводе), порядок fallocate → chmod 600 → mkswap → swapon, попадание STDERR упавшей команды в отчёт, идемпотентность fstab
    (существующая запись /swapfile не дублируется) и ветка ошибки записи.
    AST-гард подтверждает, что тяжёлые операции уходят в _run_simple (фон), а
    не выполняются в mainloop. Покрытие модуля 12%→71%, общее 66%→67%.
  • Докрыты dns.py и panels.py (в существующих tests/test_dns.py,
    tests/test_panels.py): 20 проверок ранее не затронутых веток — herror и
    прочие исключения socket в локальном резолвинге, пустой ответ dig -x,
    разбор systemd-resolve с фолбэком на resolvectl, сбой бэкапа и ошибка
    SFTP при смене резолверов, rc != 0 у mgrctl, kill_core с оставшимся
    процессом, отключение панели, отсутствие php*-fpm при перезапуске стека.
    Покрытие dns.py 89%→100%, panels.py 87%→100%, общее 67%→68%.
  • Тесты gui_output.py (tests/test_gui_output.py): 20 проверок по выводу
    и строке ввода без Tk (мок виджета/логгера). Маскирование секретов: = и
    : с пробелами, варианты passwd/pass, сохранение регистра ключа,
    token/api_key/API-KEY/secret, несколько секретов в одной строке,
    вложенный ключ (dbpassword=), пустая строка и None; проверка, что значение
    не остаётся в тексте после маски. Отдельно — что в файл лога уходит
    ЗАМАСКИРОВАННЫЙ текст, а в виджет сырой, и что «мёртвый» логгер не рвёт
    вывод. Плюс навигация по истории (↑/↓, выход вперёд с очисткой строки)
    и автодополнение по истории. Покрытие модуля 27%→50%, общее 68%→71%.
  • Тесты gui_profiles.py (tests/test_gui_profiles.py): 22 проверки
    профилей и истории подключений без Tk (мок StringVar, Combobox, диалогов):
    чтение отсутствующего/битого файла → пустой список без падения; сохранение
    файла профиля с правами 0600 и сообщение об ошибке при сбое записи;
    пустой IP блокируется сохранением, отмена имени профиля прерывает запись;
    загрузка неизвестного профиля — no-op, отсутствующие ключи берутся по
    умолчанию; удаление только после подтверждения; история подключений — новая
    запись в начало, дубликат переносится, а не повторяется, ограничение 10
    записей, порт хранится строкой. Покрытие модуля 24%→94%.
  • Тесты меню панелей и тем (tests/test_gui_isp.py,
    tests/test_gui_fastpanel.py, tests/test_gui_themes.py): 56 проверок без Tk
    и без SSH (класс-хост переопределяет _run_in_thread — поток не запускается,
    вызов записывается; messagebox подменяется на уровне модуля). Обработчики
    run_isp_*/run_fp_*: без подключения — молчание; «Нет» в подтверждении —
    команда не уходит; «Да» — в фон отправляется ровно нужная функция из
    panels.py с кнопкой и checker. Гард состава меню: разделитель ISPmanager
    отделяет разрушительные действия (Kill core, отключение). Отчёты FastPanel
    уходят с cache_key, перезапуски — без кеша (состояние «до перезапуска»
    из кеша врёт). Темы: палитра для всех тёмных имён; detect_system_theme на
    двойнике subprocess (тёмная/светлая GTK-тема, сбой gsettings, бинарник не
    найден, таймаут ≤2 с — mainloop зависнуть не может); переключение темы,
    «битая» тема → messagebox и прежняя current_theme; toggle_theme в обе
    стороны. Покрытие gui_isp.py 28%→100%, gui_fastpanel.py 36%→100%,
    gui_themes.py 69%→98%, общее 71%→73%.
  • Тесты меню «🧩 Битрикс» (tests/test_gui_bitrix.py): 50 проверок без Tk
    и без SSH (тот же класс-хост; threading подменён двойником, у которого
    Thread().start() выполняет target сразу — фоновая проверка стала
    детерминированной). Отчёты уходят с cache_key, действия, меняющие сервер,
    — только после подтверждения и без кеша; тест отправки почты спрашивает
    адрес ДО ухода в фон, срезает пробелы и передаёт адрес отдельным аргументом
    после checker, отмена/пустой адрес ничего не отправляют. Отдельно гонка
    _detect_bitrix/disconnect: _set_bitrix_menu_visible(True) без соединения
    меню не показывает; исключение при детекте гасится, меню остаётся скрытым.
    Гард состава меню: разделитель отделяет просмотр от действий. Покрытие
    gui_bitrix.py 25%→100%.
  • Тесты кнопок диагностики и диалога анализа логов доступа
    (tests/test_gui_checks.py): 35 проверок. Одиночные отчёты — аргументы и
    cache_key; run_full передаёт панель и progress_cb, который докладывает
    этапы через лог. _ask_domain: начальное значение — первый домен из
    get_domains, при падении get_domains диалог открывается пустым;
    отмена/пустой домен — SSH-запрос не уходит. Диалог _open_access_dialog
    проверяется с фабрикой-заглушкой tk/tb/ttk, подменённой на уровне
    модуля: валидация домена, Топ-Х (нечисловое → 10) и даты (текст → ошибка,
    месяц 13 → ошибка), блокировка кнопок на время анализа и статус по
    завершении, сохранение отчёта в файл, отмена выбора файла и ошибка записи.
    Покрытие gui_checks.py 13%→98%, общее 73%→79%.
  • Тесты gui_runner.py (tests/test_gui_runner.py): 39 проверок без Tk и
    без реальных потоков. Подключение: пустой IP, разбор порта с фолбэком на 22,
    отказ при _busy и при активном соединении, реквизиты доходят до
    ServerChecker, пароль стирается из формы после успеха, detect_panel
    зовётся только при panel='auto', история подключений и комбобокс
    обновляются, при неудаче кнопка разблокируется. Фоновые задачи: кеш 60 с
    (свежий показывается без потока с пометкой, устаревший пересобирается),
    аргументы доходят до цели, исключение цели превращается в «❌ Ошибка: …»,
    регресс закрытого окна (root.after бросает — флаг _busy всё равно
    освобождается), reset_cancel/cancel на мёртвом канале не срывают задачу.
    Отправка команд: история, очистка поля, STDOUT, STDERR при rc != 0,
    «(нет вывода)», exit/quit → disconnect без SSH-запроса. Дисконнект: во
    время операции — отказ, иначе закрытие, сброс кнопок и меню панелей/Битрикса.
    Покрытие gui_runner.py 19%→100%, общее 89%→92%. Прогон: 585 passed.

SSH Диагностика сервера v1.1.0

Choose a tag to compare

@DrFaustos DrFaustos released this 10 Oct 11:43

[1.1.0] — 2026-10-10

Добавлено

  • Меню «🧩 Битрикс ▾» для серверов с BitrixVM — появляется в тулбаре после
    подключения, если на сервере найдены /opt/webdir и /home/bitrix:
    состояние сертификатов dehydrated (остаток дней, последние строки
    dehydrated_update.log) и перевыпуск dehydrated -c; отчёт по MySQL под
    Битрикс (hit ratio buffer pool, «дефолтные 128M») и тюнинг-файл
    /etc/my.cnf.d/bitrix-tuning.cnf с расчётом innodb_buffer_pool_size от RAM
    (40%, округление до chunk 128M); проверка доступа к базе по dbconn.php
    (пароль не попадает ни в командную строку, ни в отчёт — только через
    временный файл 0600); параметры и модули PHP; задание cron.sh (агенты);
    состояние postfix и глубина очереди mailq.
  • «Топ-таблицы базы (размер)» в том же меню: TOP-20 по DATA_LENGTH + INDEX_LENGTH из information_schema (база берётся из реквизитов dbconn.php,
    пароль — по-прежнему временным файлом 0600) плюс подсказки по таблицам,
    которые в Битриксе разрастаются именно мусором (b_user_session,
    b_cache_tag, b_stat_hit, b_log, b_sale_basket). Чистку делает штатными
    механизмами админки: ручное DELETE из b_cache_tag ломает инкрементальный
    кеш, поэтому кнопкой удаление не вынесено — только отчёт и рекомендации.
  • «Права файлов сайта» в том же меню — типичное «распаковали архив под root,
    сайт упал»: проверка владельцев всего /home/bitrix/www (должен быть
    bitrix:bitrix), счётчик world-writable файлов (-perm -o+w) и запись в
    каталогах, без которых Битрикс не работает (bitrix/cache,
    bitrix/managed_cache, bitrix/data, upload, bitrix/php_interface).
    «Права файлов: починить» (с подтверждением) возвращает bitrix:bitrix,
    ставит 755 каталогам и 644 файлам и добавляет upload запись группой;
    действие прерывается, если группы bitrix в системе нет.
  • «Кеш: Redis / Memcached» в том же меню — бэкенд кеша в .settings.php
    ищется как строковый литерал (слово в комментарии не считается), для
    redis/memcached проверяются systemd-юниты (в CentOS — redis, в Debian —
    redis-server) и redis-cli ping, плюс размеры bitrix/cache,
    bitrix/managed_cache, bitrix/merged_cache; «бэкенда нет — всё пишется в
    файлы» отдельно подсвечивается как главная причина тормозов на нагруженном
    сайте.
  • «Cron-агенты: установить в crontab» — дописывает в crontab root ровно ту
    строку, которую рекомендует отчёт (общий литерал CRON_LINE): с бэкапом
    crontab через common.save_crontab_backup, без дублей (задание ищется по
    полному пути cron.sh) и с обязательной проверкой после записи — rc=0, но
    строки в crontab нет, считается ошибкой.
  • «Права на базу (SHOW GRANTS)» и «Права на базу: выдать недостающие» в том
    же меню. Привилегии читаются под учёткой из dbconn.php через
    CURRENT_USER(), а не по DBHost: в mysql.user записан хост-паттерн
    (%, %.site.ru), и GRANT на другую строку учётки создал бы вторую учётку,
    ничего не починив. Отчёт сверяет набор с минимумом ядра Битрикса
    (GRANT_REQUIRED: DML + DDL + EXECUTE/TRIGGER/EVENT), различает
    ALL PRIVILEGES на *.* и на базу, выбрасывает USAGE (вход есть — делать
    нечего) и отдельно подсвечивает «права остались на другой базе»
    (переименовали/перенесли сайт) и правки по отдельным таблицам. Выдача — с
    подтверждением, одним GRANT недостающего на {DBName}.* под root-доступом
    (/root/.my.cnf), только после ident_safe() (имена вне
    [A-Za-z0-9_$%.-] в SQL не подставляются) и с обязательным перечитыванием:
    прав после выдачи меньше стало — сообщение честное, а не «готово».
  • «Почта: отправить тестовое письмо» в том же меню. Адрес спрашивается
    диалогом и валидируется строгой регуляркой ДО любой команды на сервере
    (он попадает в заголовок To: и в grep по логу). Письмо уходит в
    sendmail -t, но rc=0 postfix означает лишь «принято, не дошло»: итог
    отчёт берёт из записи лога по точному получателю (to=<адрес>) —
    status=sent (с подсказкой про SPF/PTR/спам-фильтр), status=bounced,
    «письмо в очереди» или «записи нет нигде — смотри /var/log/mail.log»
    (Debian пишет туда, а не в maillog).

Изменено

  • Действия ISPmanager собраны в раскрывающееся меню. Восемь кнопок в двух
    рядах заменены одним 🛠 ISPmanager ▾: панель помещается в одну строку и не
    переполняется на узком экране. Состав и обработчики прежние; разрушительные
    действия (Kill core, Отключить панель) отделены разделителем. Диалоги
    подтверждения сохранены.
  • Меню показывается только при определённой панели и блокируется при
    отключении — состоянием одного элемента вместо восьми кнопок.
  • Добавлено меню действий FastPanel (🛠 FastPanel ▾): состояние панели и
    её стека (nginx/php-fpm/mysql, веб-интерфейс :8888, nginx -t), последние
    строки логов панели (/var/log/fastpanel2, /var/log/fastpanel),
    перезапуск службы панели и перезапуск веб-стека с обязательным nginx -t
    перед ним. Поддерживаются оба поколения: юниты fastpanel2-engine и
    fastpanel, версии php-fpm вида php8.2-fpm.

Исправлено

  • Сводный отчёт собирал системные метрики дважды. Этапы «Метрики системы» и
    «Файрвол» звали get_metrics() каждый сам — ~9 SSH-запросов повторялись
    подряд в одном прогоне. metrics_report/firewall_report теперь принимают
    готовый словарь (metrics=None — собирают сами, поведение одиночных кнопок
    не изменилось), а full_diagnostic_report собирает его один раз (лениво, на
    первом этапе) и переиспользует на втором. Имена этапов строятся из STAGES:
    раньше список не использовался нигде, а комментарий обещал индикатор
    «1/8 … 8/8» при четырёх реальных этапах — теперь прогресс честный («1/4»).
  • tests/test_reports.py (новый, 8 проверок). Сводный отчёт раньше не
    тестировался вовсе. Проверки считают фактические SSH-команды (df -h,
    ufw status, __svc_status — ровно по разу за прогон), соответствие
    прогресса списку STAGES и что падение progress_cb не рвёт отчёт.
    Заглушка FakeSSH получила host/port — их печатает заголовок отчёта.
  • SSL-отчёт Битрикса врал про перевыпуск на исправном сервере. Задание
    dehydrated искалось только в crontab -l (root spool), а в BitrixVM webdir
    чаще пишет его в /etc/cron.d/ или периодические каталоги — отчёт печатал
    «перевыпускать придётся вручную» там, где перевыпуск штатно работает. Теперь
    find_dehydrated_cron читаем root crontab отдельно и одним grep -rlF dehydrated проходим /etc/cron.d, cron.hourly, cron.daily, cron.weekly,
    cron.monthly (по содержимому — находит и cron.d-файл, и скрипт-обёртку);
    предупреждение «придётся вручную» выводится, только когда задания нет нигде.
  • AST-страховка tests/test_gui_smoke.py не считала объявлением распаковку
    self.a, self.b = ... и считала такой атрибут «потерянным». Разбор целей
    присваивания вынесен в add_self_targets и покрывает кортежи, списки и

Проверено

  • venv/bin/python -m pytest tests/ -q — 274 passed (из них 25 GUI-проверок под Xvfb).
  • Бинарник собран PyInstaller 6.22.3 по ServerDiagnostic.spec (onefile) и запущен
    под Xvfb: окно создаётся, mainloop держится, трейсов (в т.ч. ::msgcat::mcmset)
    в stderr нет; раскладка Tcl-модулей .tm в _internal/tcl8/<версия>/ закрыта
    tests/test_spec_tcl.py.

SSH Диагностика сервера v1.0.1

Choose a tag to compare

@DrFaustos DrFaustos released this 09 Oct 13:01

[1.0.1] — 2026-10-09

Исправлено

  • Бинарник не запускался на машинах без системного Tcl: на старте окно падало
    с ::msgcat::mcmset: invalid command name (трейс через ttkbootstrap).
    package require msgcat не находил модуль: PyInstaller раскладывает Tcl-модули
    (.tm) плоско в _tcl_data/tcl8/, а механизм tm ищет их в tcl8/<версия>/
    рядом с каталогом _internal. Спека теперь кладёт msgcat, http, platform
    и tcltest и туда тоже. На машине с установленным tcl-tk баг был не виден —
    там msgcat подхватывался из системы, поэтому релиз 1.0.0 «на developer-машине
    работал».

Проверено

  • Воспроизведение: бандл 1.0.0 с закрытым (tmpfs) /usr/share/tcltk падает 1-в-1
    с трейсом пользователя; бандл 1.0.1 в тех же условиях держит окно.
  • tests/test_spec_tcl.py — 3 проверки раскладки .tm в спеке (всего 148 тестов).
    Тест исполняет преамбулу спеки, поэтому работает и без PyInstaller (в CI он не
    ставится): при отсутствии пакета подставляется стаб collect_all, а без Tcl-
    модулей в окружении проверки скипаются вместо падения прогона.

SSH Диагностика сервера v1.0.0

Choose a tag to compare

@DrFaustos DrFaustos released this 09 Oct 10:19

[1.0.0] — 2026-10-09

Первый публичный релиз: инструмент закрывает полный цикл работы техподдержки —
подключение к серверу, диагностика, внесение правок, проверка результата.

Добавлено

  • Подключение по SSH: по паролю или приватному ключу, переключение между серверами
    без перезапуска, автоопределение панели управления (FastPanel / ISPmanager / без панели).
  • Профили серверов (JSON с правами 0600) и история подключений.
  • Полная диагностика одним отчётом: диски и inodes, память, CPU/load, службы,
    веб-конфиг, статусы служб — с прогрессом по этапам и возможностью отменить задачу.
  • Дополнительные проверки: SSL-сертификат (срок действия), WHOIS домена,
    доступность портов, grep по логам, анализ доступа и OOM.
  • DNS: проверка A / NS / PTR и смена резолверов с автоматическим учётом systemd-resolved.
  • Администрирование: замена IP в конфигурационных файлах, перезапуск служб,
    редактор конфигов, бэкапы правок в /root/tech_support.
  • Управление ISPmanager из окна программы.
  • Swap: создание и удаление файла подкачки, правка fstab.
  • Файловый менеджер по SFTP: навигация по каталогам, правка текстовых файлов,
    скачать/загрузить.
  • Интерактивный терминал: история команд по стрелкам, поиск в выводе по Ctrl+F,
    копирование и сохранение отчёта, шпаргалка команд.
  • Темы интерфейса на ttkbootstrap с автоопределением тёмной/светлой темы системы.
  • Маскирование секретов в окне вывода и в сохраняемых отчётах.
  • Оформление репозитория: LICENSE (MIT), CONTRIBUTING.md, SECURITY.md,
    шаблоны issues и pull request в .github/.
  • CI: прогон pytest под Xvfb на каждый push/PR; Dependabot для pip и actions.
  • Сборка standalone-бинарника через PyInstaller (команда и обязательные флаги —
    в README, готовый файл — в Releases).
  • Тесты: 145 тестов, включая статический AST-слой, который ловит потерю метода
    или атрибута при переносе кода между gui*.py.

Изменено

  • gui.py разбит на mixin-модули: 1942 строки → 565 (gui_themes, gui_profiles,
    gui_output, gui_runner, gui_checks, gui_swap, gui_dns, gui_admin,
    gui_isp, gui_files). DiagnosticApp собираётся наследованием, публичный API
    (get_theme_colors, DARK_THEMES, LIGHT_THEMES) реэкспортируется из gui.py.
  • diagnostic.py разбит на common / metrics / logs / dns / files / panels /
    reports; фасад сохранён для обратной совместимости импортов.
  • Все удалённые команды переведены на checker.run() с проверкой кода возврата.
  • Кнопки интерфейса разбиты на несколько рядов — в один ряд они не помещались.

Исправлено

  • Занятость не «залипает» после закрытия окна во время фоновой задачи: флаг сбрасывается
    первым, все колбэки идут через безопасный пост в UI-поток.
  • del active_checker в finally убивал фоновый поток после каждой задачи
    (UnboundLocalError на последующих командах).
  • cancel_event сбрасывается перед каждой задачей — после одной отмены переставали
    запускаться все остальные команды.
  • Статусы служб больше не «съезжают»: формат имя=статус вместо позиционного списка.
  • Бэкап конфигов при замене IPv6 и корректные проверки кода возврата диагностики.
  • Команда сборки исполняемого файла: без PIL._tkinter_finder окно падало на старте
    с invalid command name "PyImagingPhoto".
  • Тест навигации файлового менеджера был неустойчив: event_generate('<Return>')
    без when='tail' не доходил до обработчика, пока X-фокус не передан новому окну,
    и под оконным менеджером разработчика таблица оставалась ['etc'] (6 падений из
    40 прогонов). Под Xvfb в CI событийный фокус отдаётся без WM, поэтому дефект там
    не проявлялся. Теперь навигация в тесте ждёт результат по дедлайну.

Безопасность

  • Валидация IPv4/IPv6 в операции замены IP — закрыта возможность инъекции команды
    через поле адреса (добавлены тесты на инъекции).
  • Пароль очищается из памяти сразу после установки соединения.
  • Логи с ротацией и правами 0600; секреты маскируются в выводе и в отчётах.
  • Профили серверов сохраняются с правами 0600.

Проверено

  • python -m pytest tests/ -q — 145 passed.
  • Синтаксис совместим с Python 3.7+ (проверено ast.parse(feature_version=(3, 7))
    на всех модулях проекта).
  • Бинарник Linux x86_64 собран PyInstaller 6.22.3 и запущен: окно создано,
    работает в mainloop без ошибок.