# 01 — BRD: Security-гейт (secret-scanning + аудит зависимостей перед мержем) Work Item: **ORCH-022** Приоритет: **★ высокий** Источник: предложение Стрим, одобрено Славой (2026-06-04). Стадия: analysis. --- ## 1. Бизнес-проблема Оркестратор — автономная мульти-агентная система: агенты (`developer`) пишут код **без человека-фильтра по умолчанию**. Перед мержем в `main` сейчас нет проверки на: - **утёкший секрет** — закоммиченный API-ключ / токен / пароль / приватный ключ; - **дырявую зависимость** — пакет с известной CVE; - (опционально) **базовую уязвимость кода** — типовой SAST-паттерн. Для автономной системы это критично: ошибку, которую в обычной команде «выловили бы глазами на ревью», здесь поймать некому. Утёкший в `git`-историю ключ или уязвимая зависимость может уехать в прод и обслуживать **все** проекты (общий инстанс, self-hosting). ### Прецеденты / связки - **PR #18** (`check_ci_green`: красный CI → возврат на `development`) — задаёт целевой паттерн поведения красного гейта. Security-гейт должен вести себя так же. - **Управление секретами** (CLAUDE.md §8): секреты живут только в `.env`/`.env.staging` на хосте, канон — `.env.example`. Гейт — это автоматический страж этого правила. --- ## 2. Цель Ввести **security-гейт перед слиянием ветки задачи в `main`**, который детерминированно (без LLM) проверяет diff/ветку на секреты и уязвимые зависимости и **блокирует продвижение** при нарушении порогов: красный security-гейт → **возврат на `development`** (developer-retry, как красный CI / merge-gate), задача **не уезжает в прод**. ### Бизнес-ценность - Структурно невозможно «тихо» влить секрет или известную CVE в прод автономной системы. - Самоприменение правила CLAUDE.md §8 (секреты не в гит) без участия человека. - Расширяет уже выстроенную линию автономных страховок (CI-гейт, merge-gate ORCH-043, staging-провенанс ORCH-058, post-deploy ORCH-021). --- ## 3. Объём (Scope) ### 3.1 В объёме (v1) — **предположение по умолчанию (A1)** 1. **Secret-scanning** — обязательный минимум гейта. Поиск закоммиченных секретов в ветке задачи / её diff относительно `main`. 2. **Dependency audit** — аудит зависимостей проекта на известные CVE. 3. **Машиночитаемый артефакт-вердикт** security-гейта (YAML-frontmatter — канон гейтов). 4. **Поведение красного гейта** = откат на `development` + developer-retry (cap `MAX_DEVELOPER_RETRIES = 3`), наблюдаемость (Telegram + Plane-коммент). 5. **Условный раскат** (kill-switch + scope репозиториев), **never-raise**, self-hosting (`orchestrator`) — первым. ### 3.2 Вне объёма (v1) — **предположение (A2), отдельные WI** - **SAST (semgrep)** — вынесен в follow-up WI: шумнее, требует policy-тюнинга правил; гейт проектируется с точкой расширения под него, но в v1 не включается. - **Полноценный мульти-стек** (JS/npm, Android) — см. A3 ниже; в v1 целевой стек — Python (сам оркестратор). Связь с ORCH-9/15 фиксируется как зависимость на будущее. - Ретроспективное сканирование уже существующей истории `main` (гейт смотрит вперёд — ветку перед мержем, не чистит прошлое). - Управление аллоулистом ложных срабатываний через UI/Plane (в v1 — файл в репозитории). ### 3.3 Зафиксированные предположения по умолчанию > ⚠️ Интерактивный опрос Owner на стадии анализа не дал ответа; ниже — > **дефолты по конвенциям проекта**. Любой из них Owner/архитектор может переопределить > (для A4 предусмотрены конфиг-флаги порогов). - **A1 (объём сканеров v1):** secret-scanning + dependency-audit. SAST отложен. - **A2 (SAST):** отложен в отдельный WI; гейт оставляет точку расширения. - **A3 (стек):** **Python-only сначала**, реально только для self-hosting (`is_self_hosting_repo` / scope-CSV), как ORCH-35/43/58. Прочие репо — no-op pass. Мульти-стек (детект стека по репо) — отдельный WI. - **A4 (пороги):** **секреты — всегда блок**; **зависимости — блок на HIGH/CRITICAL, warning на MEDIUM/LOW**. Пороги вынесены в конфиг (переопределяемы без редеплоя кода). --- ## 4. Заинтересованные стороны | Роль | Интерес | |------|---------| | Owner (Слава) | Прод-безопасность автономного конвейера; контроль порогов и раската. | | Стрим | Инициатор; снижение риска утечки/уязвимости в автономном режиме. | | Агент `developer` | Получает понятную причину красного гейта → быстрый фикс. | | Агент `reviewer` | Гейт снимает с него непосильную задачу «глазами ловить ключи». | | Все проекты на инстансе | Общий прод не должен получить секрет/CVE через одну задачу. | --- ## 5. Бизнес-требования | ID | Требование | Приоритет | |----|-----------|-----------| | BR-1 | Перед слиянием ветки задачи в `main` обязателен security-гейт (секреты + аудит зависимостей). | MUST | | BR-2 | Найден секрет (порог A4) → гейт **красный** → откат на `development`, в прод не уходит. | MUST | | BR-3 | Уязвимость зависимости уровня блокировки (порог A4) → гейт **красный** → откат на `development`. | MUST | | BR-4 | Уязвимость ниже порога блокировки → **warning**, продвижение не блокируется, но фиксируется в артефакте. | MUST | | BR-5 | Красный гейт ведёт себя как красный CI / merge-gate: откат на `development` + developer-retry (cap 3), затем эскалация (Telegram + Plane Blocked). | MUST | | BR-6 | Вердикт гейта — **машиночитаемый** (YAML-frontmatter артефакта), читается гейтом ТОЛЬКО из frontmatter (канон проекта), не из прозы. | MUST | | BR-7 | Гейт **детерминированный, без LLM** в критическом пути (как merge-gate / image-freshness). | MUST | | BR-8 | Гейт **never-raise**: внутренняя ошибка не роняет `advance_stage` и не вешает конвейер всех проектов. | MUST | | BR-9 | Условный раскат: глобальный kill-switch + scope-CSV репозиториев; пусто → реально только self-hosting (`orchestrator`), прочие репо — no-op pass. | MUST | | BR-10 | Пороги блокировки конфигурируемы (env-флаги, без редеплоя кода). | SHOULD | | BR-11 | Наблюдаемость: причина блокировки видна (Telegram + Plane-коммент + артефакт); проход — без шума. | MUST | | BR-12 | Документация (CLAUDE.md «Артефакты задачи», `docs/architecture/README.md` таблица гейтов, CHANGELOG, ADR) обновлена в том же PR. | MUST | | BR-13 | Аллоулист ложных срабатываний (заведомо-безопасные совпадения, напр. в `.env.example`, фикстуры тестов) поддерживается версионируемым файлом в репозитории. | SHOULD | | BR-14 | Точка расширения под SAST и мульти-стек заложена, но в v1 не активна (A2/A3). | SHOULD | --- ## 6. Ограничения и риски (бизнес-уровень) - **Self-hosting:** гейт исполняется внутри инстанса, который правит сам себя. Запрет на рестарт/падение прод-контейнера в рамках задачи (CLAUDE.md §self-hosting) сохраняется — гейт ничего не деплоит и не рестартит, только читает/сканирует. - **Ложные срабатывания** (false positives) могут зациклить откат `→ development` (прецедент ORCH-061 со staging-петлёй). Митигировано: cap retry=3 + аллоулист (BR-13) + конфигурируемые пороги (BR-10) + kill-switch (BR-9). - **Внешние БД уязвимостей** (CVE-фиды) — сетевая зависимость; недоступность фида не должна давать ложный красный (см. AC: degrade-поведение при недоступности фида — решение порога «fail-open vs fail-closed для аудита» закрепляется в acceptance + ADR). - **Стоимость/время** сканирования добавляется к каждому прогону задачи — должно быть ограничено таймаутом (как merge-retest). --- ## 7. Критерий успеха (бизнес) Ветка с подсаженным тестовым секретом и/или зависимостью с известной CRITICAL-CVE **не может** дойти до `main`/прода: гейт краснеет, задача откатывается на `development` с понятной причиной. Чистая ветка проходит гейт без задержек и без шума. Для не-self репозиториев конвейер не меняется (no-op). Прод-контейнер не рестартится гейтом. --- ## 8. Открытые вопросы (для архитектора / Owner) 1. **Размещение гейта** (решение архитектора): (а) на стадии `review`, либо (б) отдельный под-гейт перед мержем на ребре `deploy-staging → deploy` (где уже живёт merge-gate ORCH-043 / image-freshness ORCH-058). Требование BRD — «перед слиянием в `main`»; обе опции его удовлетворяют. См. 02-trz §4. 2. **Где запускается сканер**: новый job в `.gitea/workflows/ci.yml` (тогда вердикт может течь через существующий `check_ci_green`) **или** отдельный QG-чек/под-гейт в `src/qg`. Решение — архитектор (02-trz фиксирует требования к обоим путям). 3. **Аудит зависимостей при недоступном CVE-фиде:** fail-open (warning) или fail-closed (блок)? Дефолт-предложение — **fail-open с громким warning** (не плодить ложные завороты), закрепить в ADR. 4. **Выбор конкретных инструментов** (gitleaks vs trufflehog; pip-audit vs trivy) — технологическое решение архитектора; BRD фиксирует только функцию.