work_item: ORCH-022
title: "Security-гейт: secret-scanning + dependency audit перед мержем"
notes: >
  План тестов для security-гейта. Чистая логика выносится в leaf-модуль
  src/security_gate.py (never-raise) — основной предмет unit-тестов (по образцу
  tests для merge_gate / image_freshness / post_deploy / staging_verdict).
  Интеграция врезки в advance_stage и условный раскат — integration-тесты.
  Имена модулей тестов финализирует разработчик/архитектор по факту реализации.

tests:
  # --- Secret-scanning (FR-1 / AC-1..AC-3) ---
  - id: TC-01
    type: unit
    description: "Подсаженный тестовый секрет в diff -> вердикт FAIL, secrets_found>=1, причина называет находку."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-02
    type: unit
    description: "Чистая ветка без секретов -> вердикт PASS, secrets_found=0."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-03
    type: unit
    description: "Совпадение из аллоулиста (плейсхолдер .env.example / фикстура) НЕ даёт FAIL."
    module: tests/test_security_gate.py
    expected: PASS

  # --- Dependency audit + пороги (FR-2 / AC-4..AC-7) ---
  - id: TC-04
    type: unit
    description: "CVE уровня HIGH/CRITICAL при пороге HIGH -> вклад в FAIL, deps_blocking>=1."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-05
    type: unit
    description: "Только MEDIUM/LOW уязвимости -> PASS, deps_warning>=1, находки в теле артефакта."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-06
    type: unit
    description: "Конфиг порога: severity=CRITICAL делает HIGH-CVE warning; severity=HIGH делает её блоком."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-07
    type: unit
    description: "Недоступный CVE-фид -> детерминированный degrade по политике ADR (дефолт fail-open + warning), без исключения и без ложного FAIL."
    module: tests/test_security_gate.py
    expected: PASS

  # --- Вердикт / парсер frontmatter (FR-3 / AC-8..AC-10) ---
  - id: TC-08
    type: unit
    description: "Вердикт читается ТОЛЬКО из YAML-frontmatter; проза PASS/FAIL в теле не влияет; negative-токен авторитетен."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-09
    type: unit
    description: "Нет frontmatter / битый YAML / нет поля security_status -> (False, reason) (fail-closed на чтении)."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-10
    type: unit
    description: "Артефакт 17-security-report.md создаётся с валидным frontmatter (security_status, secrets_found, deps_blocking, deps_warning) и телом-списком."
    module: tests/test_security_gate.py
    expected: PASS

  # --- never-raise / таймаут / условность (FR-5/FR-6 / AC-14..AC-17) ---
  - id: TC-11
    type: unit
    description: "Отсутствие бинаря сканера / внутреннее исключение -> (False, reason), исключение не пробрасывается (never-raise)."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-12
    type: unit
    description: "Превышение ORCH_SECURITY_SCAN_TIMEOUT_S -> корректное прерывание и детерминированный вердикт, без зависания."
    module: tests/test_security_gate.py
    expected: PASS
  - id: TC-13
    type: unit
    description: "check_security_gate: не-self репо при пустом scope -> (True, 'security-gate N/A for <repo>') мгновенно."
    module: tests/test_qg_security.py
    expected: PASS
  - id: TC-14
    type: unit
    description: "check_security_gate: ORCH_SECURITY_GATE_ENABLED=false -> no-op pass (True)."
    module: tests/test_qg_security.py
    expected: PASS
  - id: TC-15
    type: unit
    description: "Новый чек зарегистрирован в QG_CHECKS и корректно диспетчеризуется _run_qg."
    module: tests/test_qg_security.py
    expected: PASS

  # --- Откат / retry в stage_engine (FR-4 / AC-11..AC-13) ---
  - id: TC-16
    type: integration
    description: "security_status FAIL -> advance_stage откатывает на development, enqueue developer, Plane-коммент + notify_qg_failure."
    module: tests/test_stage_engine_security_gate.py
    expected: PASS
  - id: TC-17
    type: integration
    description: "task_desc перезапущенного developer содержит дословную причину находок (ORCH-046-паттерн), не только ссылку."
    module: tests/test_stage_engine_security_gate.py
    expected: PASS
  - id: TC-18
    type: integration
    description: "После MAX_DEVELOPER_RETRIES (3) -> set_issue_blocked + Telegram-алерт; бесконечного отскока нет."
    module: tests/test_stage_engine_security_gate.py
    expected: PASS
  - id: TC-19
    type: integration
    description: "security_status PASS -> advance_stage продвигает конвейер штатно (без отката, без шумных нотификаций)."
    module: tests/test_stage_engine_security_gate.py
    expected: PASS

  # --- Инварианты / интеграция (BR-7/BR-12 / AC-18..AC-19) ---
  - id: TC-20
    type: integration
    description: "При варианте 'под-гейт ребра' STAGE_TRANSITIONS не изменён; существующие тесты стадий/гейтов остаются зелёными."
    module: tests/test_stages.py
    expected: PASS
  - id: TC-21
    type: integration
    description: "Гейт не вызывает деплой-хук/рестарт прод-контейнера (self-hosting safety)."
    module: tests/test_stage_engine_security_gate.py
    expected: PASS
