Files
ripe-cidr-collector/docs/plan-empty-backup-guard.md
T
ayurishchevandClaude Sonnet 5 ab89c87321 Do not trust empty backups when sources are configured
Restoring a backup with no data while sources are configured now sets the
db_recreated.json marker (503 until data is collected), and the backup job
skips copying an empty database in that state. Adds finding 11 to the review.

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

29 lines
5.2 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.
# План: защита от восстановления из пустой копии (находка 11)
Источник: трассировка `_recover()` по графу знаний и проверка запуском (см. `docs/review-2026-09-21.md`, находка 11).
## Проблема
`_recover` ставит на место повреждённой базы самую свежую исправную копию, но не смотрит на её содержимое. Если копия пуста (ночное задание `backup` сработало до первого сбора или во время его сбоев), а источники в `config.json` настроены, то после порчи базы API отвечает `200 []` без метки: та же угроза, что в находке 1 (потребитель может принять пустой список за истину), только через восстановление. Подтверждено запуском: копия пустой базы -> порча -> `/addresses` даёт `200 []`, метки нет.
## Дизайн
- **Признак «пусто несмотря на источники»:** `db.empty_despite_sources(conn)`: в базе нет ни одного значения, а в `config.json` настроен хотя бы один ASN или FQDN. Сначала проверяется число значений (конфиг не читается, если данные есть); нечитаемый конфиг при пустой базе считается «пусто» (блокировка по умолчанию).
Критерий намеренно общий, а не по типам: копия, где есть ASN, но нет адресов FQDN (например, все адреса отфильтрованы как неглобальные), не должна вечно держать выдачу в ожидании.
- **Восстановление:** после успешного `_restore_backup` при `empty_despite_sources` пишется та же метка `db_recreated.json` (с полем `reason`). Дальше работает уже существующая защита: `/addresses` и `/addresses/diff` дают `503` с `Retry-After`, `/health` показывает `degraded` и `db_recreated`, сборщик снимает метку, когда данные собраны. Восстановление копии с данными метку не ставит.
- **Задание `backup`:** пустую базу при настроенных источниках не копирует: `backup_database` возвращает `None` (не ошибка: статус задания остаётся успешным, в лог пишется сообщение), ротация не выполняется, существующие копии не затрагиваются. Так пустые копии не вытесняют хорошие за `backup_keep` дней и не появляются вовсе. Пустая база без источников копируется как раньше.
## Изменения
1. `db.py`: `empty_despite_sources`; `recreated_pending` использует общий разбор конфигурации; метка ставится в `_recover` (общая функция записи метки для обеих веток); `backup_database` возвращает `None` для пустой базы при источниках.
2. `collector_daemon.py`: `run_backup` обрабатывает `None` (сообщение в лог).
3. `README.md`: разделы о резервной копии и автовосстановлении.
4. `docs/review-2026-09-21.md`: находка 11; итоги в `docs/summary-empty-backup-guard.md`.
5. Тесты (1 новый, всего 28): пустая база при настроенных источниках копию не создаёт, копия с данными восстанавливается без метки, пустая копия (снятая, когда источников не было) при появлении источников даёт метку и `503`-состояние.
## Не входит
Тип-специфичное ожидание при восстановлении (см. выше); копии вне сервера; удаление уже существующих пустых копий (при необходимости - вручную из `backups/`).
## Проверка
Тесты в контейнере; повтор запуска, воспроизводившего проблему: восстановление из пустой копии при настроенном источнике теперь даёт `503`, метка есть, после появления данных выдача возобновляется; копия с данными - без метки.
## Откат
Убрать проверку в `_recover` и `backup_database` (возврат к предыдущему коммиту); схема данных не затрагивается, метку можно удалить вручную.