nspd_lite.fetch_geoportal / nspd_client._http_get_json: json.loads на HTTP 200 не обёрнут → WAF-челлендж со статусом 200 даёт JSONDecodeError мимо autoretry harvest_quarter #1614

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

Severity: medium · Категория: retry / error-classification · Файл: backend/app/services/scrapers/nspd_lite.py:113-123

Файлы: backend/app/services/scrapers/nspd_lite.py:113-116 и backend/app/services/scrapers/nspd_client.py:272-275.

В обоих try-блоках ловятся только urllib.error.HTTPError и URLError. json.loads(body) на успешном (HTTP 200) ответе не защищён. Если WAF/прокси NSPD отдаёт HTML-челлендж или пустое тело со статусом 200 (а не 403/429), json.loads бросает json.JSONDecodeError (подкласс ValueError) — это НЕ NspdLiteWafError и НЕ NspdLiteError.

Импакт: harvest_quarter настроен autoretry_for=(NspdLiteWafError,) (nspd_sync.py:264) и re-raise'ит только NspdLiteWafError (357-367). Сырое JSONDecodeError проходит в generic except Exception (nspd_sync.py:369-393) → строка дампа помечается постоянным harvest_error БЕЗ ретрая, хотя это та же transient/WAF-ситуация, что и закрытый #252. Путь активен: search_by_quarter использует fetch_geoportal (nspd_client.py:354) и _http_get_json (418/468/624).

Фикс: обернуть json.loads в обоих helper'ах в try и при JSONDecodeError на 200-ответе бросать NspdLiteWafError (или NspdLiteError, если тело явно не WAF), чтобы transient-сбой ретраился, а не оседал как permanent harvest_error.

Почему баг: harvest_quarter (nspd_sync.py:264) настроен autoretry_for=(NspdLiteWafError,). Сырое JSONDecodeError попадает в generic except Exception (nspd_sync.py:369), пишется как постоянный harvest_error БЕЗ ретрая — хотя это та же transient/WAF-ситуация, что и закрытый #252. Остаётся непокрытый класс transient-сбоя: WAF, отвечающий 200+HTML вместо 403, не ретраится и портит строку дампа ошибкой.

Как чинить: Обернуть json.loads в try/except json.JSONDecodeError и поднимать NspdLiteError (или NspdLiteWafError при детекте challenge-маркеров / Content-Type text/html), чтобы retry-политика срабатывала. Применить в обоих местах (nspd_lite и nspd_client).


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

**Severity:** medium · **Категория:** retry / error-classification · **Файл:** `backend/app/services/scrapers/nspd_lite.py:113-123` Файлы: backend/app/services/scrapers/nspd_lite.py:113-116 и backend/app/services/scrapers/nspd_client.py:272-275. В обоих try-блоках ловятся только urllib.error.HTTPError и URLError. `json.loads(body)` на успешном (HTTP 200) ответе не защищён. Если WAF/прокси NSPD отдаёт HTML-челлендж или пустое тело со статусом 200 (а не 403/429), json.loads бросает json.JSONDecodeError (подкласс ValueError) — это НЕ NspdLiteWafError и НЕ NspdLiteError. Импакт: harvest_quarter настроен autoretry_for=(NspdLiteWafError,) (nspd_sync.py:264) и re-raise'ит только NspdLiteWafError (357-367). Сырое JSONDecodeError проходит в generic `except Exception` (nspd_sync.py:369-393) → строка дампа помечается постоянным harvest_error БЕЗ ретрая, хотя это та же transient/WAF-ситуация, что и закрытый #252. Путь активен: search_by_quarter использует fetch_geoportal (nspd_client.py:354) и _http_get_json (418/468/624). Фикс: обернуть json.loads в обоих helper'ах в try и при JSONDecodeError на 200-ответе бросать NspdLiteWafError (или NspdLiteError, если тело явно не WAF), чтобы transient-сбой ретраился, а не оседал как permanent harvest_error. **Почему баг:** harvest_quarter (nspd_sync.py:264) настроен autoretry_for=(NspdLiteWafError,). Сырое JSONDecodeError попадает в generic except Exception (nspd_sync.py:369), пишется как постоянный harvest_error БЕЗ ретрая — хотя это та же transient/WAF-ситуация, что и закрытый #252. Остаётся непокрытый класс transient-сбоя: WAF, отвечающий 200+HTML вместо 403, не ретраится и портит строку дампа ошибкой. **Как чинить:** Обернуть json.loads в try/except json.JSONDecodeError и поднимать NspdLiteError (или NspdLiteWafError при детекте challenge-маркеров / Content-Type text/html), чтобы retry-политика срабатывала. Применить в обоих местах (nspd_lite и nspd_client). --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.85 · unit B35</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:19:53 +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#1614
No description provided.