Files
ripe-cidr-collector/docs/analysis-2026-09-21.md
T
ayurishchevandClaude Sonnet 5 bcf8156085 Initial commit: RIPE CIDR/FQDN collector
Collector daemon, FastAPI server (addresses, diff, collect, sources),
SQLite storage with change journal, Docker Compose deployment,
tests, documentation and project rules.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 07:29:38 +03:00

90 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Анализ проекта: сделано и осталось (2026-09-21, сверка с графом)
Состояние после восьми доработок: надёжность и безопасность, тесты в контейнере, форматы вывода, разделение процессов, управление ASN/FQDN через API, контейнер приложения, SQLite, `POST /collect`, `GET /addresses/diff`. Предыдущий анализ: `analysis-2026-09-20.md`. Планы и итоги лежат рядом в `docs/`.
Проект: 7 модулей Python (API, сборщик, демон, БД, форматы, хранилище, healthcheck), 1235 строк, 18 тестов (15 функций с параметризацией) в 5 файлах, 20 документов в `docs/`.
**Граф знаний** (`graphify-out/`, построен по коду и `docs/`): 315 узлов, 643 связи, 13 сообществ. Использован для сверки: узлы-«хабы», связи между модулями и документами, изолированные узлы. Все выводы из графа ниже проверены по исходникам.
## Что изменилось с предыдущей версии этого файла
- **Выполнено:** `GET /addresses/diff` (журнал изменений на триггерах SQLite, курсор, `410` за горизонтом, заголовок `X-Changes-Cursor`). Из «Не сделано» убран diff; уведомления остались.
- **Исправлено по сверке:**
- Безымянных образов Docker не 65, а 3 (всего образов 31). Наблюдение 3 снято.
- Предположение, что в демоне не ловится `sqlite3.Error`, не подтвердилось: `run_job` перехватывает любое исключение сбора и пишет его в `last_error`. Пробела нет.
- Метрики: строк кода 1235 (было 1102), тестов 18 (было 16).
- **Новое:** `graphify-out/` (1,2 МБ) не был исключён из `.gitignore` и `.dockerignore`, то есть попадал бы в образ. Исправлено, в README добавлен пункт о графе.
## Сделано
| Направление | Результат |
|---|---|
| Токен на изменяющие запросы | `X-API-Key` на `POST`/`DELETE`, без токена запись отключена (503). Чтение открыто намеренно. |
| TTL, атомарная запись, защита от порчи | TTL (`ttl_days`) на SQLite. Битые JSON и база уходят в `*.corrupt-*`, API отвечает 503. |
| Форматы вывода, агрегация 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 (оригиналы сохраняются), транзакции, чтение без блокировок. |
| `POST /collect` | Токен, ответ 202, запрос демону файлом `collect_request.json` (опрос каждые 5 с), объединение запросов, пропуск наложения, `503` без живого демона. |
| `GET /addresses/diff` | Журнал `changes` (триггеры, схема версии 2), итоговый эффект вместо истории, срок хранения `changes_retention_days` (30 дней), курсор или время, `410` за горизонтом. Проверено тестами и на копии базы версии 1. |
| Граф знаний | `graphify-out/`: интерактивный граф, отчёт, JSON; исключён из git и образа. |
| Тесты | 18 проверок, запуск в контейнере. |
## Не сделано
| Направление | Статус |
|---|---|
| Автоматическая резервная копия базы | Есть только команда в README (`sqlite3 ".backup"`), заданий в демоне нет |
| Метрики `/metrics`, алерты | Не начато |
| Уведомления о изменениях (webhook, Telegram) | Не начато; основа (журнал) есть |
| Повторные попытки запросов к RIPE | Не начато |
| TLS перед API | Не начато (решение пользователя: порт наружу без TLS) |
## Остаточные риски
| # | Риск | Статус |
|---|---|---|
| 1 | Нет репозитория git, истории изменений нет. | Не закрыт |
| 2 | Версии в `requirements.txt` не закреплены, это влияет и на образ. | Не закрыт |
| 3 | После порчи базы API отдаёт пустой список, пока сборщик не наполнит новую базу; автовосстановления из копии нет. Курсоры diff после пересоздания базы недействительны (`410`), клиент делает полную выгрузку. | Не закрыт |
| 4 | MikroTik и FRR не проверены на реальном ПО. | Не закрыт |
| 5 | Токен идёт по HTTP открытым текстом. | Осознанный выбор |
| 6 | Один общий токен, без ротации и аудита. | Не закрыт |
| 7 | Тестов минимум, что соответствует правилам проекта. | Осознанно |
| 8 | `POST /collect` без ограничения частоты: повторные запросы во время идущего сбора пропускаются, но защиты от нагрузки на RIPE нет. | Не закрыт |
| 9 | Журнал diff проверен только на копиях и тестах: размер и нагрузка на реальных данных неизвестны. | Не закрыт (новое) |
## Наблюдения
| # | Наблюдение | Состояние |
|---|---|---|
| 1 | **Изменения не применены к реальным данным.** В каталоге проекта нет `ripe.db`, `data.json` и `fqdn_data.json` остались в старом формате; всё проверено только на копиях. Первый запуск на боевых данных выполнит миграцию до схемы версии 2: `last_seen` старых записей станет равным времени миграции, журнал diff начнётся пустым (импорт в него не пишется), клиентам стартовать с `X-Changes-Cursor`. | Без изменений |
| 2 | **`/health` не видит сбоев источников.** Недоступный RIPE или DNS пишется в лог, задание считается успешным (`last_error` отражает только исключение всего сбора). | Без изменений |
| 3 | ~~Мусор от сборок: 65 безымянных образов.~~ Сейчас 3 безымянных образа. | Снято |
| 4 | **Повреждённый `config.json`** переименовывается при чтении; первый `POST /asns` после этого создаст файл без остальных источников, расписания и `ttl_days`. | Без изменений |
| 5 | **Логи:** сообщение «data saved» пишется после каждой транзакции, даже без изменений (`cidr_collector.py:152,206`). | Без изменений |
| 6 | **Структура README:** разделы 8 (Docker) и 9 (SQLite) дописаны в конец, разделы 1-4 описывают ручную установку. Стоит перестроить: Docker в начало, ручная установка ниже. | Без изменений |
| 7 | **`google.com`** в данных не входит в конфигурацию, его адрес удалится через 90 дней после миграции. | Без изменений |
| 8 | **Ручной сбор стартует не мгновенно**, а в пределах 5 секунд (интервал опроса демона). | Без изменений |
| 9 | **Логи APScheduler о плановых запусках скрыты** (чтобы опрос запросов каждые 5 с не засорял лог); остаются сообщения самого приложения. | Без изменений |
| 10 | **Общая точка отказа хранилища (по графу).** Главные узлы: `load_json()` (19 связей), `session()` (17), `StorageError` (16). Это осознанная развязка: одно исключение скрывает JSON и SQLite от API, демона и CLI (проверено по исходникам: `api_server.py:94,192`, `collector_daemon.py:79,102,147`, `cidr_collector.py:265`). Но любое изменение `storage.py`/`db.py` затрагивает все три процесса, покрытие тестами здесь важнее всего. | Новое |
| 11 | **`api_server.py` растёт (320 строк, связность сообщества 0,06 по графу):** схемы, проверки, все эндпоинты в одном модуле; после diff стал больше. Разделять пока не нужно, но при следующем эндпоинте стоит вынести схемы и разбор параметров. | Новое |
| 12 | **Граф не заменяет проверку.** 19 изолированных узлов (например, описания эндпоинтов в README) не связаны с обработчиками в коде: это ограничение семантической выгрузки, а не обязательно пробел в документации. Расход токенов на построение в `cost.json` не записан (нули). Документы `analysis-*.md` сами входят в граф, поэтому он частично отражает выводы анализа, а не независимую оценку. | Новое |
## Рекомендуемый порядок
1. **Гигиена и резервные копии:** `git init` и первый коммит (после этого можно поставить хук графа), закрепление версий, ежедневное задание демона `db_backup` (`.backup` с хранением нескольких копий) и автовосстановление из последней копии при порче.
2. **Наблюдаемость:** учёт ошибок по каждому источнику (`last_success`, число ошибок) в `status.json` и `/health`, затем `/metrics` для Prometheus и повторные попытки запросов к RIPE.
3. **Развёртывание на реальных данных:** запуск через compose с миграцией текущих файлов (наблюдение 1), оценка размера журнала (риск 9).
4. **TLS-прокси** перед API, если появится внешний доступ.
5. **Уведомления** (webhook, Telegram): демон после сбора считает diff по журналу и отправляет непустой результат.
Обновлять граф после доработок: `/graphify . --update`.
## Связанные документы
- `plan-*.md` / `summary-*.md`: reliability-security, tests-in-container, output-formats, process-split, asn-fqdn-api, app-container, sqlite-storage, collect-endpoint, diff-endpoint.
- Предыдущий анализ: `analysis-2026-09-20.md`.
- Граф: `graphify-out/GRAPH_REPORT.md`, `graphify-out/graph.html`.