Repository navigation
Releases: DrFaustos/techsupp_diagtool
Releases · DrFaustos/techsupp_diagtool
Release list
v1.32.29
v1.32.28
Релиз 1.32.28: история в CI целиком, бинарь из прогона
SSH Диагностика сервера v1.1.1
[1.1.1] — 2026-10-10
Добавлено
- Тесты backend-модулей (
tests/test_metrics.py,tests/test_files.py,
tests/test_webcheck.py): 40 проверок без реального SSH (черезFakeSSH).
Покрытиеwebcheck.py39%→100%,metrics.py60%→98%,files.py59%→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.py89%→100%,panels.py87%→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.py28%→100%,gui_fastpanel.py36%→100%,
gui_themes.py69%→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.py25%→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.py13%→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.py19%→100%, общее 89%→92%. Прогон: 585 passed.
SSH Диагностика сервера v1.1.0
[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=0postfix означает лишь «принято, не дошло»: итог
отчёт берёт из записи лога по точному получателю (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
[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
[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без ошибок.