worker_ready (lifecycle.py:160-171) немедленно ре-enqueue'ит WAF-paused nspd_geo jobs, обходя 30-минутный WAF-cooldown из cleanup_zombies #1620

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

Severity: medium · Категория: concurrency/rate-limit · Файл: backend/app/workers/lifecycle.py:160-171

lifecycle.py:160-171 — UPDATE ... WHERE status IN ('running','paused') без порога по времени: jobs в status='paused' ре-enqueue'ятся при КАЖДОМ старте/редеплое воркера. Job переводится в 'paused' только после consecutive_waf>=8 (nspd_geo.py:486-501), т.е. NSPD-WAF уже жёстко забанил IP VPS. Периодический cleanup_zombies намеренно держит 'paused' минимум 30 мин (_ZOMBIE_PAUSED_THRESHOLD='30 minutes', nspd_geo.py:53; WHERE-условие nspd_geo.py:659-663), и его docstring (637-639) прямо говорит: «WAF-пауза (consecutive_waf>=8) живёт минимум 30 мин, иначе минутный beat сразу аннулировал бы защиту и worker снова долбил бы забаненный сервис». worker_ready полностью обходит этот cooldown — две resume-ветки применяют противоречивую политику к 'paused'. ИМПАКТ: каждый рестарт/редеплой воркера (рутинный docker-compose deploy-флоу) мгновенно воскрешает все WAF-paused jobs и отправляет воркер обратно на забаненный NSPD-endpoint с нулевым cooldown → продление/углубление IP-бана, ровно та защита, в которую вложен код (rate_ms throttle, consecutive_waf backoff, paused-cooldown), аннулируется. ФИКС: в worker_ready применить тот же 30-мин heartbeat-порог к 'paused' (и >threshold к 'running'), либо вовсе убрать nspd_geo-ветку из worker_ready и доверить resume только cleanup_zombies (beat-таск, который beat_schedule.py:9/225-227 уже называет «заменой нестабильного worker_ready»).

Почему баг: Every worker restart/redeploy (the normal Forgejo→SSH→docker-compose deploy flow, which happens routinely) immediately resurrects all WAF-paused jobs and re-enqueues them, sending the worker straight back at the banned NSPD endpoint with zero cooldown. This directly undoes the WAF-protection the codebase invests heavily in and can extend/deepen the IP ban. The two resume paths (cleanup_zombies vs worker_ready) apply contradictory policies to 'paused'.

Как чинить: Exclude 'paused' from worker_ready's immediate resume, or apply the same 30-min cooldown: WHERE status='running' OR (status='paused' AND heartbeat_at < NOW() - INTERVAL '30 minutes'). Let cleanup_zombies (which already encodes the correct per-status thresholds) own paused-job resumption.


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

**Severity:** medium · **Категория:** concurrency/rate-limit · **Файл:** `backend/app/workers/lifecycle.py:160-171` lifecycle.py:160-171 — UPDATE ... WHERE status IN ('running','paused') без порога по времени: jobs в status='paused' ре-enqueue'ятся при КАЖДОМ старте/редеплое воркера. Job переводится в 'paused' только после consecutive_waf>=8 (nspd_geo.py:486-501), т.е. NSPD-WAF уже жёстко забанил IP VPS. Периодический cleanup_zombies намеренно держит 'paused' минимум 30 мин (_ZOMBIE_PAUSED_THRESHOLD='30 minutes', nspd_geo.py:53; WHERE-условие nspd_geo.py:659-663), и его docstring (637-639) прямо говорит: «WAF-пауза (consecutive_waf>=8) живёт минимум 30 мин, иначе минутный beat сразу аннулировал бы защиту и worker снова долбил бы забаненный сервис». worker_ready полностью обходит этот cooldown — две resume-ветки применяют противоречивую политику к 'paused'. ИМПАКТ: каждый рестарт/редеплой воркера (рутинный docker-compose deploy-флоу) мгновенно воскрешает все WAF-paused jobs и отправляет воркер обратно на забаненный NSPD-endpoint с нулевым cooldown → продление/углубление IP-бана, ровно та защита, в которую вложен код (rate_ms throttle, consecutive_waf backoff, paused-cooldown), аннулируется. ФИКС: в worker_ready применить тот же 30-мин heartbeat-порог к 'paused' (и >threshold к 'running'), либо вовсе убрать nspd_geo-ветку из worker_ready и доверить resume только cleanup_zombies (beat-таск, который beat_schedule.py:9/225-227 уже называет «заменой нестабильного worker_ready»). **Почему баг:** Every worker restart/redeploy (the normal Forgejo→SSH→docker-compose deploy flow, which happens routinely) immediately resurrects all WAF-paused jobs and re-enqueues them, sending the worker straight back at the banned NSPD endpoint with zero cooldown. This directly undoes the WAF-protection the codebase invests heavily in and can extend/deepen the IP ban. The two resume paths (cleanup_zombies vs worker_ready) apply contradictory policies to 'paused'. **Как чинить:** Exclude 'paused' from worker_ready's immediate resume, or apply the same 30-min cooldown: WHERE status='running' OR (status='paused' AND heartbeat_at < NOW() - INTERVAL '30 minutes'). Let cleanup_zombies (which already encodes the correct per-status thresholds) own paused-job resumption. --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.72 · unit B42</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:21:04 +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#1620
No description provided.