Результат аудита
Проверил все баги из #437 и #446 по коду. Часть — галлюцинации ревьевера, часть — реальные.
❌ НЕ фиксим (галлюцинации)
| Баг |
Почему |
Bug 1 — ZAI URL без /v1 |
ZAI_DEFAULT_BASE_URL уже "https://api.z.ai/api/anthropic/v1" (provider_registry.py:7) |
| Bug 2 — ZAI_API_KEY не регистрируется |
Блок регистрации уже есть в _register_env_providers |
Bug 4 — search_hybrid без try/except |
try/except RuntimeError с fallback на FTS уже есть в generation_service.py |
Bug 5 и Bug 7 (частично) — _run_rag в content_generation_service.py и DAG handler — уже имеют корректную реализацию. Проблема только в entrypoints (см. Fix 3 ниже).
✅ Фиксим (реальные баги)
Fix 1 — Fail-open ACL (CRITICAL)
Файл: src/agent/tools/_registry.py, функция require_phone_permission
При ошибке DB или broken JSON функция возвращает None (разрешает действие):
except Exception:
return None # DB error → allow all ← ПРОБЛЕМА
if not raw:
return None # нет конфига → allow all ← ОК, ожидаемо
except (ValueError, TypeError):
return None # malformed JSON → allow all ← ПРОБЛЕМА
Fix: два из трёх return None заменить на fail-closed (текстовая ошибка "ACL unavailable / malformed, action blocked"). if not raw: return None оставить — отсутствие конфига = нет ограничений, это ожидаемый default.
Fix 2 — AgentProviderService без load_db_providers (HIGH)
Файл: src/services/provider_service.py
load_db_providers() уже существует, но требует db + config; если config=None — возвращает 0 без загрузки DB-провайдеров.
7 мест создания AgentProviderService(db) без config и без await load_db_providers():
| Файл |
~Строка |
src/services/content_generation_service.py |
368 |
src/agent/tools/pipelines.py |
426 |
src/services/ab_testing_service.py |
64 |
src/services/quality_scoring_service.py |
88 |
src/services/pipeline_service.py |
498 |
src/cli/commands/translate.py |
56, 90 |
src/services/unified_dispatcher.py |
755 |
Fix: во всех местах передать config и вызвать await provider_service.load_db_providers() после создания:
# было
provider_service = AgentProviderService(db)
# стало
provider_service = AgentProviderService(db, config=config)
await provider_service.load_db_providers()
Для сервисных классов — убедиться что config есть в self._config; для CLI — брать из ctx.obj["config"].
Fix 3 — Дублированный retrieval query в entrypoints (MEDIUM)
Проблема: 4 entrypoint-а используют pipeline.prompt_template or pipeline.name or "" вместо pipeline.name or "", и не делают source-channel scoping.
Эталон — ContentGenerationService._run_rag() (src/services/content_generation_service.py:~247):
query = pipeline.name or ""
sources = await self._db.repos.content_pipelines.list_sources(pipeline.id)
channel_id = sources[0].channel_id if len(sources) == 1 else None
return await gen.generate(query=query, ..., channel_id=channel_id)
Файлы для изменения:
| Файл |
Что сделать |
src/web/routes/pipelines.py:491 |
prompt_template or name → name; добавить scoping; передать channel_id |
src/web/routes/pipelines.py:559 |
то же |
src/cli/commands/pipeline.py:305 |
то же |
src/agent/tools/pipelines.py:425 |
то же |
src/services/pipeline_executor.py:92 (DAG) |
prompt_template or name → name; сохранить channel_id в context |
src/services/pipeline_nodes/handlers.py:49 (DAG) |
достать channel_id из context, передать в search_hybrid |
Приоритет
- Fix 1 — изолированный, один файл, security-critical
- Fix 2 — средний объём, нужно проверить доступность
config в каждом сервисе
- Fix 3 — наибольший объём, механически простой (copy pattern from
_run_rag)
Верификация
ruff check src/ tests/ conftest.py
pytest tests/ -v -m "not aiosqlite_serial" -n auto
pytest tests/ -v -m aiosqlite_serial
pytest tests/test_provider_service.py tests/test_pipeline_nodes_handlers.py -v
Closes #446, closes #437
Результат аудита
Проверил все баги из #437 и #446 по коду. Часть — галлюцинации ревьевера, часть — реальные.
❌ НЕ фиксим (галлюцинации)
/v1ZAI_DEFAULT_BASE_URLуже"https://api.z.ai/api/anthropic/v1"(provider_registry.py:7)_register_env_providerssearch_hybridбез try/excepttry/except RuntimeErrorс fallback на FTS уже есть вgeneration_service.pyBug 5 и Bug 7 (частично) —
_run_ragвcontent_generation_service.pyи DAG handler — уже имеют корректную реализацию. Проблема только в entrypoints (см. Fix 3 ниже).✅ Фиксим (реальные баги)
Fix 1 — Fail-open ACL (CRITICAL)
Файл:
src/agent/tools/_registry.py, функцияrequire_phone_permissionПри ошибке DB или broken JSON функция возвращает
None(разрешает действие):Fix: два из трёх
return Noneзаменить на fail-closed (текстовая ошибка "ACL unavailable / malformed, action blocked").if not raw: return Noneоставить — отсутствие конфига = нет ограничений, это ожидаемый default.Fix 2 — AgentProviderService без load_db_providers (HIGH)
Файл:
src/services/provider_service.pyload_db_providers()уже существует, но требуетdb+config; еслиconfig=None— возвращает 0 без загрузки DB-провайдеров.7 мест создания
AgentProviderService(db)безconfigи безawait load_db_providers():src/services/content_generation_service.pysrc/agent/tools/pipelines.pysrc/services/ab_testing_service.pysrc/services/quality_scoring_service.pysrc/services/pipeline_service.pysrc/cli/commands/translate.pysrc/services/unified_dispatcher.pyFix: во всех местах передать
configи вызватьawait provider_service.load_db_providers()после создания:Для сервисных классов — убедиться что
configесть вself._config; для CLI — брать изctx.obj["config"].Fix 3 — Дублированный retrieval query в entrypoints (MEDIUM)
Проблема: 4 entrypoint-а используют
pipeline.prompt_template or pipeline.name or ""вместоpipeline.name or "", и не делают source-channel scoping.Эталон —
ContentGenerationService._run_rag()(src/services/content_generation_service.py:~247):Файлы для изменения:
src/web/routes/pipelines.py:491prompt_template or name→name; добавить scoping; передатьchannel_idsrc/web/routes/pipelines.py:559src/cli/commands/pipeline.py:305src/agent/tools/pipelines.py:425src/services/pipeline_executor.py:92(DAG)prompt_template or name→name; сохранитьchannel_idв contextsrc/services/pipeline_nodes/handlers.py:49(DAG)channel_idиз context, передать вsearch_hybridПриоритет
configв каждом сервисе_run_rag)Верификация
ruff check src/ tests/ conftest.py pytest tests/ -v -m "not aiosqlite_serial" -n auto pytest tests/ -v -m aiosqlite_serial pytest tests/test_provider_service.py tests/test_pipeline_nodes_handlers.py -vCloses #446, closes #437