Skip to content

fix plan: аудит #437/#446 — что фиксить и как #447

@axisrow

Description

@axisrow

Результат аудита

Проверил все баги из #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 namename; добавить 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 namename; сохранить channel_id в context
src/services/pipeline_nodes/handlers.py:49 (DAG) достать channel_id из context, передать в search_hybrid

Приоритет

  1. Fix 1 — изолированный, один файл, security-critical
  2. Fix 2 — средний объём, нужно проверить доступность config в каждом сервисе
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions