Files
ripe-cidr-collector/docs/plan-loss-guard.md
T
ayurishchevandClaude Sonnet 5 0155fd3f38 Withhold addresses after the database is recreated without a backup
When ripe.db is corrupted and no valid backup exists, a new empty database
is created with a db_recreated.json marker; /addresses and /addresses/diff
answer 503 until the collector gathers data again, /health reports
db_recreated. Tests now isolate all state files via conftest.

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

6.1 KiB
Raw Blame History

План: защита от пустой выдачи после потери базы (находка 1 ревью)

Источник: docs/review-2026-09-21.md, находка 1 (высокая); риск 3 анализа.

Проблема

Если ripe.db испорчена и исправной копии нет, первый запрос получает 503, а затем создаётся новая пустая база, и /addresses отвечает 200 []. Потребитель (роутер, файрвол), забирающий список по расписанию, может принять пустой список за истину и стереть свои правила. /health при живом демоне показывает ok при counts = 0.

Дизайн

  • Признак потери. Когда база пересоздана из-за порчи без копий, db._recover пишет файл-метку db_recreated.json в DATA_DIR (время, путь карантина, текст ошибки). Метка ставится только в этом случае: чистая установка (базы ещё не было) и восстановление из копии её не создают.
  • Сразу рабочее соединение. _recover больше не бросает StorageError в этом случае, а создаёт новую базу и возвращает соединение (демон продолжает сбор, /health и записи работают). Журнал изменений новой базы сдвигается так же, как при восстановлении из копии (RESTORE_JOURNAL_JUMP): курсоры старой базы дают 410. Общий код сброса журнала выносится из _restore_backup.
  • Что блокируется. Пока данные не собраны заново, GET /addresses и GET /addresses/diff отвечают 503 с заголовком Retry-After и пояснением; остальные эндпоинты работают. Проверка идёт по запрошенным типам:
    • блокируется тип, для которого в config.json есть источники, но в базе по нему нет ни одного значения;
    • тип без источников (например, нет ни одного FQDN) не блокируется и отдаёт законный пустой список.
  • Снятие метки. В конце каждого запуска сбора (ASN, FQDN, в том числе через CLI) вызывается db.settle_recreated: если ни один сконфигурированный тип не пуст, файл-метка удаляется. Снять блокировку вручную (принять пустую выдачу) можно, удалив db_recreated.json.
  • /health. Поле db_recreated: null или {"at": ..., "pending": true|false} (без путей: это же закрывает связанную находку 6 для нового поля). Пока блокировка активна, статус degraded.
  • Устойчивость. Проверка метки читает только файл и базу; если config.json нечитаем, блокировка сохраняется (fail closed).

Изменения

  1. cidr_collector.py: RECREATED_FILE, вызов db.settle_recreated в обоих run_collection.
  2. db.py: метка и создание новой базы в _recover, _reset_journal (общий код с _restore_backup), recreated_pending(conn, kinds), settle_recreated(conn).
  3. api_server.py: проверка в /addresses и /addresses/diff (503 + Retry-After), поле db_recreated и статус в /health.
  4. README.md: раздел «Automatic restore» (поведение без копий, ручное снятие метки), /health.
  5. .gitignore/.dockerignore: db_recreated.json.
  6. Тесты (2 новых, один существующий обновляется; всего 24): БД (порча без копий: соединение рабочее, метка записана, старый курсор 410; метка снимается при появлении данных и не мешает, если источников нет); API (/addresses и /addresses/diff дают 503, /health degraded с db_recreated, после появления данных 200 и метка снята; тип без источников не блокируется). Существующая проверка «без копий -> StorageError» в test_restore_from_backup заменяется на новое поведение.

Не входит

  • Чистая установка без базы по-прежнему отдаёт пустой список (терять нечего).
  • Удаление файла базы вручную не распознаётся как потеря (порчи нет): пустая база создаётся без метки. Возможное продолжение: при отсутствии базы и наличии копий восстанавливаться из них.
  • Порча внутри файла, обнаруженная при чтении, по-прежнему даёт 503 и восстанавливается вручную.

Проверка

Тесты в контейнере; вручную в отдельных процессах: порча ripe.db без копий при работающих API и демоне -> /addresses 503, /health degraded, после сбора 200 с данными и метка удалена; повтор в Docker Compose (общий том).

Откат

Убрать проверку в API и запись метки в _recover (возврат к предыдущему коммиту): схема базы не меняется, файл db_recreated.json можно удалить.