Risks 1-3 closed, observations 2 and 5 closed, new observations on module growth, stale knowledge graph and Docker image clutter; next step is the run on real data. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
17 KiB
Анализ проекта: сделано и осталось (2026-09-21, актуализация после наблюдаемости)
Состояние после 17 доработок (план и итоги каждой лежат в docs/): надёжность и безопасность, тесты в контейнере, форматы вывода, разделение процессов, управление ASN/FQDN через API, контейнер приложения, SQLite, POST /collect, GET /addresses/diff, репозиторий git, закрепление версий, резервные копии и автовосстановление, защита ввода и данных, защита от пустой выдачи, исправления ревью 5-10, защита от пустых копий, наблюдаемость. Предыдущая версия этого файла описывала состояние после восьми доработок. Отчёт ревью: review-2026-09-21.md (находки 1-11 закрыты).
Проект: 7 модулей Python, 1719 строк (db.py 544, cidr_collector.py 386, api_server.py 381, collector_daemon.py 191, formatters.py 115, storage.py 70, healthcheck.py 32), 30 тестов (27 функций, 5 файлов и conftest.py), 37 документов в docs/ (17 планов, 17 итогов, 2 анализа, ревью), 9 коммитов, ветка main синхронизирована с origin (artstore.rxmsk.ru).
Что изменилось с предыдущей версии этого файла
- Закрыты риски: 1 (нет git), 2 (версии не закреплены), 3 (пустой список после порчи базы).
- Закрыты наблюдения: 2 (
/healthне видел сбоев источников) и 5 (сообщение «data saved» без изменений); наблюдения 10 и 11 (структура модулей) переосмыслены, наблюдение 3 ухудшилось, добавлено наблюдение 13. - Из «Не сделано» выполнено: автоматическая резервная копия, diff, повторные запросы к RIPE;
/metricsисключён из плана решением пользователя. - Новое: восстановление из копии, состояние источников (
/sources), фильтрация DNS-адресов, защита от пустой выдачи и пустых копий, схема базы версии 3, ревью по графу знаний (11 находок). - Метрики: строк кода 1719 (было 1235), тестов 30 (было 18), документов 37 (было 20).
Сделано
| Направление | Результат |
|---|---|
| Токен на изменяющие запросы | X-API-Key на POST/DELETE, без токена запись отключена (503); сравнение по байтам, любой неверный ключ - 401. Чтение открыто намеренно. |
| TTL, атомарная запись, защита от порчи | TTL (ttl_days), атомарная запись JSON и транзакции SQLite, битые файлы уходят в *.corrupt-*. |
Форматы вывода, агрегация CIDR, ip_version |
nftables, mikrotik, bird, frr. |
| Разделение сборщика и API | Отдельный демон, singleton, heartbeat, /health по status.json. |
| Управление ASN и FQDN через API | Добавление, удаление, purge, старение данных удалённых источников. |
| Контейнер приложения | Dockerfile (все модули корня, проверка импорта при сборке) и docker-compose.yml: два сервиса, том, non-root, read-only, healthcheck. |
| SQLite | Таблица addresses, WAL, автоматическая миграция из JSON, транзакции; схема версии 3 (журнал изменений, состояние источников). |
POST /collect |
Токен, ответ 202, запрос демону файлом (опрос каждые 5 с), объединение запросов, 503 без живого демона. |
GET /addresses/diff?since= |
Журнал изменений на триггерах, курсор или время, 410 за горизонтом, X-Changes-Cursor в /addresses; строгий разбор since. |
| Репозиторий и версии | git, origin; requirements с точными версиями и constraints.txt (полный pip freeze). |
| Резервные копии и восстановление | Задание backup (онлайн-копия, quick_check, ротация backup_keep); при порче базы восстановление из последней исправной копии; last_restore в /health. |
| Защита от пустой выдачи | Потеря базы без копий или восстановление из пустой копии при настроенных источниках: метка db_recreated.json, 503 на /addresses и /addresses/diff до нового сбора; пустая база не копируется. |
| Данные DNS и внешний источник | Фильтр глобальных адресов (allow_non_global_ips), повторы запросов к RIPEstat с sourceapp и потолком Retry-After. |
| Наблюдаемость | Состояние каждого источника (таблица source_status), блок sources и degraded в /health, GET /sources, итоговая строка запуска в логе. |
| Ревью и граф знаний | Отчёт ревью (11 находок, все закрыты), граф graphify-out/ (вне git и образа). |
| Тесты | 30 проверок, запуск в контейнере, изоляция файлов состояния (conftest.py). |
Не сделано
| Направление | Статус |
|---|---|
| Запуск на реальных данных | Не начато (см. наблюдение 1); следующий шаг |
| Уведомления (webhook, Telegram) | Не начато; основа (журнал, /health, /sources) есть |
Метрики Prometheus (/metrics) |
Исключены из плана решением пользователя; при необходимости - отдельная доработка |
Ограничение частоты POST /collect |
Не начато |
| Архитектурный рефакторинг | Не начато: вынос путей в settings.py, разделение api_server.py, cidr_collector.py и db.py |
| Копии вне сервера | Не начато: копии лежат на том же томе, что и база (вынос описан в README) |
| TLS перед API | Не начато (решение пользователя: порт наружу без TLS) |
Остаточные риски
| # | Риск | Статус |
|---|---|---|
| 1 | Закрыт | |
| 2 | requirements.txt не закреплены.python:3.11-slim не закреплён по дайджесту (осознанно). |
Закрыт |
| 3 | Закрыт, остаток описан | |
| 4 | MikroTik и FRR не проверены на реальном ПО. | Не закрыт |
| 5 | Токен идёт по HTTP открытым текстом. | Осознанный выбор |
| 6 | Один общий токен, без ротации и аудита. | Не закрыт |
| 7 | Тестов минимум, что соответствует правилам проекта. | Осознанно |
| 8 | POST /collect без ограничения частоты: повторные запросы во время сбора пропускаются, но защиты от нагрузки на RIPE нет (при этом запросы к RIPEstat теперь идут с повторами). |
Не закрыт |
| 9 | Журнал diff и состояние источников проверены только на копиях и тестах: размер и нагрузка на реальных данных неизвестны. | Не закрыт |
| 10 | Копии базы лежат на том же томе, что и база: защита от порчи файла, но не от потери тома. | Не закрыт (описан в README) |
| 11 | Нет активных оповещений: о сбое источников можно узнать только опросом /health или из лога. |
Не закрыт |
Наблюдения
| # | Наблюдение | Состояние |
|---|---|---|
| 1 | Изменения не применены к реальным данным. В каталоге проекта нет ripe.db; data.json (6 ASN) и fqdn_data.json (4 имени) остались в старом формате; всё проверено только на копиях. Первый запуск на боевых данных выполнит миграцию сразу до схемы версии 3: last_seen старых записей станет равным времени миграции, журнал diff и состояние источников начнутся пустыми (клиентам стартовать с X-Changes-Cursor), первые запуски сбора создадут состояние источников. |
Без изменений |
| 2 | /health не видит сбоев источников.source_failure_threshold (по умолчанию 3): при суточном расписании FQDN это три дня до degraded. |
Закрыто |
| 3 | Безымянные образы Docker: 21 на хосте. Часть - от пересборок тестового образа ripe-tests при разработке, на хосте есть и чужие (docker image prune затронет все). |
Ухудшилось (было 3) |
| 4 | Повреждённый config.json переименовывается при чтении; первый успешный POST /asns после этого создаст файл без остальных источников, расписания и ttl_days. |
Без изменений |
| 5 | Закрыто | |
| 6 | Структура README: разделы 8 (Docker) и 9 (SQLite) в конце, разделы 1-4 описывают ручную установку; за время доработок README вырос до 540 строк. Стоит перестроить: Docker и быстрый старт в начало, ручная установка ниже. | Без изменений |
| 7 | google.com есть в fqdn_data.json, но не входит в конфигурацию: его адрес после миграции истечёт через 90 дней. |
Без изменений |
| 8 | Ручной сбор стартует не мгновенно, а в пределах 5 секунд (интервал опроса демона). | Без изменений |
| 9 | Логи APScheduler о плановых запусках скрыты (чтобы опрос запросов каждые 5 с не засорял лог); остаются сообщения приложения. | Без изменений |
| 10 | Общая точка отказа хранилища (по графу): главные узлы session() (22 связи), get_addresses() (15), load_full_config() (14), _recover() (14). Развязка через один тип StorageError сохраняется, но db.py (544 строки) стал самым крупным модулем и совмещает схему, восстановление, копии, журнал и состояние источников. |
Переосмыслено |
| 11 | Рост модулей и цикл зависимостей: db.py берёт пути и настройки из cidr_collector.py отложенным импортом внутри функций; api_server.py (381 строка) и cidr_collector.py (386) совмещают по несколько ролей. Пока работает, но следующий эндпоинт или задание усугубит. |
Ухудшилось |
| 12 | Граф знаний устарел и не заменяет проверку. Последнее построение (527 узлов, 1029 связей) было до доработки «наблюдаемость» (код db.py, cidr_collector.py, api_server.py, тесты и документы не отражены); хук обновления после коммита не установлен. Изолированных узлов 36 (описания без связи с кодом), расход токенов на построение не учтён (нули). |
Требует обновления |
| 13 | Порог degraded для FQDN: имя, разрешившееся только в неглобальные адреса (без allow_non_global_ips), через три запуска даёт degraded (no_global_addresses); источник, вернувший 0 адресов корректным ответом, degraded не вызывает, виден только в /sources. |
Новое |
Рекомендуемый порядок
- Запуск на реальных данных (главный шаг). Перед запуском: копия
config.json,data.json,fqdn_data.jsonвне каталога проекта и вне тома (миграция переименует оригиналы в*.migrated-*, но копия на случай ошибки обязательна). Затемdocker compose up -dс переносом файлов в том (порядок в README), проверка/health,/sources,/addressesи/addresses/diff, первый ручной сбор черезPOST /collect, оценка размера базы и журнала, выбор порогаsource_failure_threshold. Нужен отдельный план с откатом. - Обновить граф (
/graphify . --update, документы выгружать целиком) и при желании поставить хук после коммита. - Уведомления (webhook, Telegram) на основе журнала и состояния источников: закрывает риск 11.
- Архитектурный рефакторинг:
settings.py(пути и умолчания), разделениеdb.pyиapi_server.py; снимает наблюдения 10-11. - По мере необходимости: ограничение частоты
POST /collectи ротация токена (риски 6, 8), проверка MikroTik и FRR на реальном ПО (риск 4), вынос копий за пределы тома (риск 10), TLS-прокси при внешнем доступе (риск 5), перестройка README (наблюдение 6),docker image prune(наблюдение 3).
Связанные документы
plan-*.md/summary-*.md(по 17): reliability-security, tests-in-container, output-formats, process-split, asn-fqdn-api, app-container, sqlite-storage, collect-endpoint, diff-endpoint, git-init, pin-dependencies, db-backup, input-hardening, loss-guard, review-fixes-5-10, empty-backup-guard, observability.- Ревью:
review-2026-09-21.md; предыдущий анализ:analysis-2026-09-20.md. - Граф:
graphify-out/GRAPH_REPORT.md,graphify-out/graph.html(локально, вне git).