Files
ripe-cidr-collector/docs/analysis-2026-09-21.md
T
ayurishchevandClaude Sonnet 5 7e3b4526f3 Record the production deployment on port 18000
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>
2026-09-21 11:45:46 +03:00

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 Нет репозитория git. Закрыт
2 Версии в requirements.txt не закреплены. Базовый образ python:3.11-slim не закреплён по дайджесту (осознанно). Закрыт
3 Пустой список после порчи базы. Остаются не покрытые случаи: ручное удаление файла базы (порчи нет, пустая база создаётся без метки) и порча внутри файла (503 при чтении, восстановление вручную). Закрыт, остаток описан
4 MikroTik и FRR не проверены на реальном ПО. Не закрыт
5 Токен идёт по HTTP открытым текстом. Осознанный выбор
6 Один общий токен, без ротации и аудита. Не закрыт
7 Тестов минимум, что соответствует правилам проекта. Осознанно
8 POST /collect без ограничения частоты: повторные запросы во время сбора пропускаются, но защиты от нагрузки на RIPE нет (при этом запросы к RIPEstat теперь идут с повторами). Не закрыт
9 Журнал diff и состояние источников: на боевом развёртывании с шестью ASN и расписанием база и ответы малы (десятки КБ, миллисекунды); поведение во времени (сутки и более, TTL, рост журнала) ещё предстоит наблюдать. Частично закрыт
10 Копии базы лежат на том же томе, что и база: защита от порчи файла, но не от потери тома. Не закрыт (описан в README)
11 Нет активных оповещений: о сбое источников можно узнать только опросом /health или из лога. Не закрыт

Наблюдения

# Наблюдение Состояние
1 Боевое развёртывание не выполнено. Выполнено 2026-09-21 (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 Сообщение «data saved» после каждой транзакции. Вместо него итоговая строка запуска. Закрыто
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. Новое

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

  1. Боевое развёртывание выполнено (порт 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. Нужен отдельный план с откатом.
  2. Обновить граф (/graphify . --update, документы выгружать целиком) и при желании поставить хук после коммита.
  3. Уведомления (webhook, Telegram) на основе журнала и состояния источников: закрывает риск 11.
  4. Архитектурный рефакторинг: settings.py (пути и умолчания), разделение db.py и api_server.py; снимает наблюдения 10-11.
  5. По мере необходимости: ограничение частоты 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).