# 03 — Критерии приёмки: Security-гейт (ORCH-022)

Формат: каждый критерий имеет чёткое условие **PASS/FAIL**. Привязка к
`01-brd.md` (BR-*) и `02-trz.md` (FR-*).

---

## A. Secret-scanning (FR-1, BR-1/BR-2)

### AC-1 — Подсаженный секрет блокирует гейт
- **PASS:** ветка с тестовым секретом (напр. фиктивный AWS-ключ формата `AKIA…` вне
  аллоулиста) → `security_status: FAIL`; гейт возвращает `(False, reason)`, причина
  называет секрет/файл.
- **FAIL:** секрет не обнаружен ИЛИ гейт зелёный при наличии секрета.

### AC-2 — Чистая ветка проходит
- **PASS:** ветка без секретов → `security_status: PASS`; `secrets_found: 0`;
  гейт возвращает `(True, …)`.
- **FAIL:** ложное срабатывание (FAIL на чистой ветке).

### AC-3 — Аллоулист подавляет заведомо-безопасное (BR-13)
- **PASS:** совпадение, явно занесённое в версионируемый аллоулист (напр. плейсхолдер в
  `.env.example` / фикстура теста), **не** даёт FAIL.
- **FAIL:** аллоулист игнорируется и даёт ложный FAIL.

---

## B. Dependency audit (FR-2, BR-3/BR-4)

### AC-4 — CVE уровня блокировки краснит гейт
- **PASS:** зависимость с известной `CRITICAL`/`HIGH` CVE (при пороге по умолчанию
  `HIGH`) → вклад в `security_status: FAIL`; `deps_blocking >= 1`.
- **FAIL:** блокирующая уязвимость не приводит к FAIL.

### AC-5 — Низкая severity = warning, не блок
- **PASS:** только `MEDIUM`/`LOW` уязвимости → `security_status: PASS`, при этом
  `deps_warning >= 1` и находки перечислены в теле артефакта.
- **FAIL:** `MEDIUM`/`LOW` блокирует продвижение.

### AC-6 — Порог блокировки конфигурируем (BR-10)
- **PASS:** при `ORCH_SECURITY_DEP_BLOCK_SEVERITY=CRITICAL` та же `HIGH`-уязвимость
  становится warning (не блок); при `=HIGH` — блок. Поведение детерминированно
  определяется флагом.
- **FAIL:** флаг не влияет на классификацию.

### AC-7 — Degrade при недоступном CVE-фиде
- **PASS:** недоступность фида обрабатывается по решению ADR детерминированно и
  протестированно (дефолт: fail-open + громкий warning, гейт не краснеет ложно).
- **FAIL:** недоступность фида даёт неконтролируемый красный/исключение.

---

## C. Вердикт и артефакт (FR-3, BR-6)

### AC-8 — Машинный вердикт только из frontmatter
- **PASS:** вердикт читается ТОЛЬКО из YAML-frontmatter `17-security-report.md`; проза с
  «PASS»/«FAIL» в теле не влияет на решение. Negative-токен (FAIL) авторитетен.
- **FAIL:** вердикт извлекается из тела/прозы.

### AC-9 — Битый/отсутствующий frontmatter → fail-closed на чтении
- **PASS:** нет frontmatter / битый YAML / нет поля `security_status` → `(False, reason)`
  (как `_parse_deploy_status`/`check_reviewer_verdict`).
- **FAIL:** битый артефакт трактуется как PASS.

### AC-10 — Артефакт создаётся с корректными полями
- **PASS:** после прогона существует `17-security-report.md` с валидным frontmatter
  (`security_status`, `secrets_found`, `deps_blocking`, `deps_warning`) и телом-списком.
- **FAIL:** артефакт не создан/без машинных полей.

---

## D. Откат и retry (FR-4, BR-5)

### AC-11 — Красный гейт → откат на development + developer-retry
- **PASS:** `FAIL` → стадия задачи становится `development`, enqueue `developer`,
  Plane-коммент + `notify_qg_failure`; счётчик developer-retry растёт.
- **FAIL:** при FAIL задача продвигается дальше / не откатывается.

### AC-12 — task_desc несёт дословную причину (ORCH-046-паттерн)
- **PASS:** `task_desc` для перезапущенного developer содержит конкретику находок
  (какие секреты/CVE), а не только ссылку на артефакт.
- **FAIL:** developer получает только ссылку без сути.

### AC-13 — Cap retry и эскалация
- **PASS:** после `MAX_DEVELOPER_RETRIES` (3) безуспешных фиксов — `set_issue_blocked` +
  Telegram-алерт; бесконечного отскока нет.
- **FAIL:** откат зацикливается без cap/эскалации.

---

## E. Условный раскат и устойчивость (FR-5/FR-6, BR-8/BR-9)

### AC-14 — Не-self репозиторий = no-op pass
- **PASS:** для repo, не входящего в scope и не self-hosting → гейт возвращает
  `(True, "security-gate N/A for <repo>")` мгновенно, конвейер такого репо не меняется.
- **FAIL:** гейт реально запускается/блокирует чужой репо при пустом scope.

### AC-15 — Kill-switch отключает гейт
- **PASS:** `ORCH_SECURITY_GATE_ENABLED=false` → гейт — no-op pass (`(True, …)`),
  поведение конвейера 1:1 как до ORCH-022.
- **FAIL:** при выключенном флаге гейт всё ещё блокирует.

### AC-16 — never-raise
- **PASS:** искусственный сбой (нет бинаря сканера / таймаут / исключение внутри) →
  `(False, reason)` без проброса исключения; `advance_stage` не падает, конвейер других
  задач/проектов не встаёт.
- **FAIL:** внутренняя ошибка пробрасывается/вешает движок.

### AC-17 — Таймаут ограничен
- **PASS:** сканирование, превысившее `ORCH_SECURITY_SCAN_TIMEOUT_S`, корректно
  прерывается → детерминированный вердикт (по политике degrade), без зависания.
- **FAIL:** сканер висит без таймаута.

---

## F. Инварианты и интеграция (BR-7/BR-12, TRZ §7)

### AC-18 — STAGE_TRANSITIONS/QG_CHECKS консистентны
- **PASS:** при варианте «под-гейт ребра» `STAGE_TRANSITIONS` не изменён; новый чек
  зарегистрирован в `QG_CHECKS`; `_run_qg` корректно его диспетчеризует. Все
  существующие тесты гейтов/стадий зелёные.
- **FAIL:** сломан реестр/переходы/существующие тесты.

### AC-19 — Гейт не деплоит/не рестартит прод
- **PASS:** код гейта не вызывает деплой-хук/рестарт прод-контейнера; только
  чтение/сканирование.
- **FAIL:** гейт инициирует рестарт/деплой.

### AC-20 — Документация обновлена в том же PR (BR-12)
- **PASS:** обновлены `CLAUDE.md` (артефакт 17-…), `docs/architecture/README.md`
  (таблица гейтов + реестр QG + раздел ORCH-022), `CHANGELOG.md`, `.env.example`
  (`ORCH_SECURITY_*`); заведён ADR `06-adr/ADR-001-*`.
- **FAIL:** функционал есть, документация/ADR не обновлены → reviewer обязан
  REQUEST_CHANGES (CLAUDE.md §6).

### AC-21 — End-to-end на тестовой задаче
- **PASS:** прогон на self-hosting-репо: грязная ветка (секрет/CVE) → откат на
  `development`; после фикса чистая ветка → гейт зелёный → конвейер идёт дальше; прод не
  затронут в процессе.
- **FAIL:** любой шаг E2E не воспроизводится.
