# 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 ")` мгновенно, конвейер такого репо не меняется. - **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 не воспроизводится.