Plan and summary of the containerized deployment (six ASNs, three FQDNs, token in .env, published on all interfaces, backups on the volume) and the updated analysis. The .env file stays out of git. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
18 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 закрыты).
Тестовый запуск на копиях боевых файлов с реальным ASN 62041 описан в summary-real-data-run.md; боевое развёртывание в контейнерах на порту 18000 выполнено 2026-09-21 (summary-production-deploy.md, работает по расписанию).
Проект: 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, итоговая строка запуска в логе. |
| Боевое развёртывание | Compose на 192.168.5.9:18000 (доступ открыт для всех, токен в .env), шесть ASN и три FQDN, миграция боевых файлов без потерь, плановый запуск проверен; копии на томе (summary-production-deploy.md). |
| Ревью и граф знаний | Отчёт ревью (11 находок, все закрыты), граф graphify-out/ (вне git и образа). |
| Тесты | 30 проверок, запуск в контейнере, изоляция файлов состояния (conftest.py). |
Не сделано
| Направление | Статус |
|---|---|
| Уведомления (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 и состояние источников: на боевом развёртывании с шестью ASN и расписанием база и ответы малы (десятки КБ, миллисекунды); поведение во времени (сутки и более, TTL, рост журнала) ещё предстоит наблюдать. | Частично закрыт |
| 10 | Копии базы лежат на том же томе, что и база: защита от порчи файла, но не от потери тома. | Не закрыт (описан в README) |
| 11 | Нет активных оповещений: о сбое источников можно узнать только опросом /health или из лога. |
Не закрыт |
Наблюдения
| # | Наблюдение | Состояние |
|---|---|---|
| 1 | summary-production-deploy.md); ниже - исходное описание. Миграция боевых файлов проверена в изолированном стенде на их копиях (summary-real-data-run.md: без потерь, сбор AS62041 и восстановление на реальных данных работают). В каталоге проекта нет 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. |
Новое |
Рекомендуемый порядок
Боевое развёртываниевыполнено (порт 18000, шесть ASN); далее - наблюдение: 03:00 плановый сбор FQDN, 04:30 первая плановая копия, суточный просмотр/healthи/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).