Files
ros_control/docs/reviews/2026-09-28-1243-codebase-review.md
T
ayurishchevandClaude Opus 5.5 0bda0038d0 Остаток п. 9 ревью: синхронная БД вне event loop, повторное ревью
Повторное ревью кодовой базы: docs/reviews/2026-09-28-1243-codebase-review.md
(статус 12 замечаний, новые замечания 13–16).

Остаток п. 9 (docs/changes/022):
- 14 async-функций API, UI и сервисов больше не обращаются к SQLite
  напрямую — через asyncio.to_thread; jobs.start_jobs стал async (БД в
  потоке, create_task в event loop); ops._conn для подключения к устройству;
- тест-линтер по AST: в async def нет прямых вызовов функций с
  session_scope — защита от регресса.

Тесты: 29 из 29. Стенд: задачи и актор событий в порядке, параллельные
запросы не ждут медленного устройства, боевые данные не изменены.
Ручная проверка UI пользователем на момент коммита не подтверждена.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 17:12:44 +03:00

7.8 KiB

Ревью кодовой базы ros_control — 2026-09-28 12:43 MSK

Повторное ревью. Состояние на коммит c407972. Тесты: 28/28 проходят. Предыдущее ревью: 2026-09-27-codebase-review.md (коммит 26dd1f8).

Итог

Из 12 замечаний предыдущего ревью закрыто 10 (одно — частично), открыто 2. Закрыты разделы «Безопасность», «Корректность и согласованность», «Производительность и масштабирование»; раздел «Эксплуатация» не менялся.

Изменение Коммит Пункты
018-correctness-consistency 123b5ab 5, 6, 7
019-performance-scaling ba8ac7b 8, 9 (частично), 10
020-custom-select-menus 6b5c521 — (доработка UI по запросу)
021-security-hardening c407972 1, 2, 3, 4

Статус замечаний предыдущего ревью

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

№ Замечание Приоритет Статус Подтверждение в коде
1 Небезопасные значения секретов по умолчанию Высокий ✅ 021 app/config.py::insecure_settings; проверка первым шагом в app/main.py::lifespan — при пустых, change-me или коротких секретах (API_TOKEN, SESSION_SECRET ≥ 32, ADMIN_PASSWORD ≥ 12) и невалидном SECRET_KEY приложение не стартует
2 Вход в UI без защиты от перебора Высокий ✅ 021 app/ui/routes.py::login: 5 неверных за 10 минут → IP заблокирован на 10 минут (429, пароль не проверяется); auth.locked пишется один раз
3 Сессионная cookie без флага Secure Средний ✅ 021 SESSION_COOKIE_SECURE → SessionMiddleware(https_only=…); по умолчанию выключен, за TLS — включить
4 Открытый редирект в /ui/move Низкий ✅ 021 app/ui/routes.py::_safe_next — только локальный путь; применён в /ui/move и групповом удалении бэкапов

Корректность и согласованность

№ Замечание Приоритет Статус Подтверждение в коде
5 Одиночное удаление бэкапа в обход сервиса Средний ✅ 018 app/ui/routes.py::backup_delete → backups.delete_many([key])
6 Две системы миграций Низкий ✅ 018 db._migrate удалён; колонки старой схемы — migrations._add_legacy_columns при user_version < 1
7 Синхронная групповая смена канала Средний ✅ 018 Задачи set_channel; PUT /api/v1/batch/channel → 202 {"job_ids"}

Производительность и масштабирование

№ Замечание Приоритет Статус Подтверждение в коде
8 Каждое открытие «Бэкапов» перечитывает весь бакет Средний ✅ 019 app/services/backups.py::bucket_objects — кэш на BACKUPS_CACHE_TTL, счётчик поколений, invalidate() после бэкапа и удаления, refresh=1
9 Синхронная БД в async-обработчиках Низкий 🟡 019, частично 44 обработчика стали def; фоновые записи — asyncio.to_thread; SQLite WAL + busy_timeout. Остаток — см. «Открытые замечания», п. 9
10 Состояние в памяти процесса Низкий ✅ 019 app/process_lock.py — flock на <файл БД>.lock в lifespan; README «Ограничения»

Эксплуатация

№ Замечание Приоритет Статус Подтверждение в коде
11 Нет healthcheck, логирование не настроено Низкий ❌ Открыт Нет HEALTHCHECK в Dockerfile и docker-compose.yml; логирование нигде не настраивается
12 Тесты в одном файле Низкий ❌ Открыт, растёт tests/test_app.py: 570 → 753 строки, 20 → 28 тестов

Открытые замечания

№ Замечание Где Приоритет
9 Остаток синхронной работы с БД в async-коде: groups.list_groups() и devices.list_devices() в async-обработчике страницы «Бэкапы»; devices.get_conn() (чтение и расшифровка пароля) app/services/backups.py::search, app/services/ops.py::run_backup Низкий
11 Нет healthcheck; логирование не настроено Dockerfile, docker-compose.yml, app/main.py Низкий
12 Тесты в одном файле, файл растёт tests/test_app.py Низкий

Новые замечания

№ Замечание Где Приоритет
13 Копирование БД в режиме WAL не описано: копия файла БД без -wal может быть неполной; нужен sqlite3 .backup или копирование вместе с -wal README.md Средний
14 За reverse-proxy блокировка входа видит один IP прокси (нет настройки доверенных прокси и разбора X-Forwarded-For); ограничение описано в README app/ui/routes.py::login Низкий (прокси сейчас нет)
15 refresh=1 остаётся в адресе страницы «Бэкапы» после «Обновить список» — повторные перезагрузки идут мимо кэша app/ui/routes.py::backups_page Низкий
16 Стенд запускается на порту 8001 через override-файл вне репозитория: порт 8000 на хосте занят посторонним процессом (telemetry_web); штатный docker-compose.yml без override не стартует. Порт не параметризован docker-compose.yml, окружение хоста Низкий (окружение)

Проверка UI

Ручная проверка интерфейса пользователем по изменениям 019–021 не подтверждена (отмечено в summary.md и сообщениях коммитов). Особенно важно для 020 (выпадающие списки): автотестов JS в проекте нет.

Рекомендуемый порядок

  1. Изменение 022: п. 11 (HEALTHCHECK, базовая настройка логов), остаток п. 9, п. 13 (копирование БД в README), п. 15.
  2. П. 16 — параметризовать порт в docker-compose.yml (${HTTP_PORT:-8000}) или освободить порт 8000 на хосте.
  3. П. 12 — разбить тесты по модулям отдельным изменением (только структура тестов).
  4. П. 14 — при появлении reverse-proxy: доверенные прокси и реальный IP клиента.