get_features_in_bbox_grid молча глотает WAF-403 и server-error для ПЗЗ-grid-walk → ложный tz_count=0, без layer_failed #1573

Closed
opened 2026-06-16 17:06:29 +00:00 by bot-backend · 0 comments
Collaborator

Severity: medium · Категория: data-loss / false-report / WAF-masking · Файл: backend/app/scrapers/nspd_bulk_client.py:472-507

backend/app/scrapers/nspd_bulk_client.py:472-485. get_features_in_bbox_grid собирает результаты ячеек через asyncio.gather(return_exceptions=True) (:472) и в цикле :477-485 ловит любой isinstance(cell_result, Exception) единообразно (logger.debug + continue). Сюда попадают NspdBulkWafError (403 WAF, raise в _get_json:207) и NspdBulkServerError (5xx/WMS ServiceException, :230/245). Единственный production-путь — get_territorial_zones_in_bbox (layer 875838 ПЗЗ, :520) из bulk_harvest.py:256 → _save_territorial_zones (:1436), который на пустом списке возвращает 0. ИМПАКТ: при WAF-бане IP или тотальном 5xx все ячейки молча падают на DEBUG, метод отдаёт [], в БД пишется tz_count=0 — ПЗЗ-зонирование ложно «отсутствует», а WAF-бан (по docstring :14-22/:22 должен останавливать harvest) остаётся незамеченным. Для ПЗЗ нет механики layer_failed (issue #252, реализованной для parcels/buildings в _grid_walk_category bulk_harvest.py:426): нет различения «слой пуст» vs «все ячейки упали на 500». ФИКС: (1) не глотать NspdBulkWafError — пробрасывать наружу (валит квартал); (2) считать server_errors/ok_cells по аналогии с _grid_walk_category и прокидывать layer_failed, чтобы _save_territorial_zones не писал tz_count=0 при полном сбое слоя.

Почему баг: Весь дизайн-контракт модуля (docstring строки 14-22, NspdBulkWafError) гласит: 403 WAF → raise немедленно, не retry, manual investigate. В _grid_walk_category (путь parcels/buildings) WAF корректно пробрасывается и валит квартал. Но в gather-пути для ПЗЗ WAF и server-error глотаются на DEBUG и НИКОГДА не доходят до caller'а как ошибка — caller просто получает []. Дополнительно теряется механика issue #252 (layer_failed): для ПЗЗ нет различения «слой реально пуст» vs «все ячейки упали на 500», поэтому при тотальном server-error территориальные зоны тоже молча сохраняются как 0. Итог: ПЗЗ-зонирование (вход для gate_verdict/скоринга участков) ложно репортится отсутствующим, а WAF-бан, который должен останавливать harvest, остаётся незамеченным.

Как чинить: В цикле обработки cell_results пробрасывать NspdBulkWafError немедленно (re-raise) — как в прямом пути _grid_walk_category. Отдельно считать server_errors/ok_cells и возвращать признак «слой целиком сбойнул» (или хотя бы поднимать NspdBulkServerError, если 0 успешных ячеек), чтобы caller не записывал ложный 0. Логировать обычные cell-ошибки на WARNING, а не DEBUG.


deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.72 · unit B11

**Severity:** medium · **Категория:** data-loss / false-report / WAF-masking · **Файл:** `backend/app/scrapers/nspd_bulk_client.py:472-507` backend/app/scrapers/nspd_bulk_client.py:472-485. get_features_in_bbox_grid собирает результаты ячеек через asyncio.gather(return_exceptions=True) (:472) и в цикле :477-485 ловит любой isinstance(cell_result, Exception) единообразно (logger.debug + continue). Сюда попадают NspdBulkWafError (403 WAF, raise в _get_json:207) и NspdBulkServerError (5xx/WMS ServiceException, :230/245). Единственный production-путь — get_territorial_zones_in_bbox (layer 875838 ПЗЗ, :520) из bulk_harvest.py:256 → _save_territorial_zones (:1436), который на пустом списке возвращает 0. ИМПАКТ: при WAF-бане IP или тотальном 5xx все ячейки молча падают на DEBUG, метод отдаёт [], в БД пишется tz_count=0 — ПЗЗ-зонирование ложно «отсутствует», а WAF-бан (по docstring :14-22/:22 должен останавливать harvest) остаётся незамеченным. Для ПЗЗ нет механики layer_failed (issue #252, реализованной для parcels/buildings в _grid_walk_category bulk_harvest.py:426): нет различения «слой пуст» vs «все ячейки упали на 500». ФИКС: (1) не глотать NspdBulkWafError — пробрасывать наружу (валит квартал); (2) считать server_errors/ok_cells по аналогии с _grid_walk_category и прокидывать layer_failed, чтобы _save_territorial_zones не писал tz_count=0 при полном сбое слоя. **Почему баг:** Весь дизайн-контракт модуля (docstring строки 14-22, NspdBulkWafError) гласит: 403 WAF → raise немедленно, не retry, manual investigate. В _grid_walk_category (путь parcels/buildings) WAF корректно пробрасывается и валит квартал. Но в gather-пути для ПЗЗ WAF и server-error глотаются на DEBUG и НИКОГДА не доходят до caller'а как ошибка — caller просто получает []. Дополнительно теряется механика issue #252 (layer_failed): для ПЗЗ нет различения «слой реально пуст» vs «все ячейки упали на 500», поэтому при тотальном server-error территориальные зоны тоже молча сохраняются как 0. Итог: ПЗЗ-зонирование (вход для gate_verdict/скоринга участков) ложно репортится отсутствующим, а WAF-бан, который должен останавливать harvest, остаётся незамеченным. **Как чинить:** В цикле обработки cell_results пробрасывать NspdBulkWafError немедленно (re-raise) — как в прямом пути _grid_walk_category. Отдельно считать server_errors/ok_cells и возвращать признак «слой целиком сбойнул» (или хотя бы поднимать NspdBulkServerError, если 0 успешных ячеек), чтобы caller не записывал ложный 0. Логировать обычные cell-ошибки на WARNING, а не DEBUG. --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.72 · unit B11</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:06:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1573
No description provided.