13 KiB
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)
- Secret-scanning — обязательный минимум гейта. Поиск закоммиченных секретов
в ветке задачи / её diff относительно
main. - Dependency audit — аудит зависимостей проекта на известные CVE.
- Машиночитаемый артефакт-вердикт security-гейта (YAML-frontmatter — канон гейтов).
- Поведение красного гейта = откат на
development+ developer-retry (capMAX_DEVELOPER_RETRIES = 3), наблюдаемость (Telegram + Plane-коммент). - Условный раскат (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)
- Размещение гейта (решение архитектора): (а) на стадии
review, либо (б) отдельный под-гейт перед мержем на ребреdeploy-staging → deploy(где уже живёт merge-gate ORCH-043 / image-freshness ORCH-058). Требование BRD — «перед слиянием вmain»; обе опции его удовлетворяют. См. 02-trz §4. - Где запускается сканер: новый job в
.gitea/workflows/ci.yml(тогда вердикт может течь через существующийcheck_ci_green) или отдельный QG-чек/под-гейт вsrc/qg. Решение — архитектор (02-trz фиксирует требования к обоим путям). - Аудит зависимостей при недоступном CVE-фиде: fail-open (warning) или fail-closed (блок)? Дефолт-предложение — fail-open с громким warning (не плодить ложные завороты), закрепить в ADR.
- Выбор конкретных инструментов (gitleaks vs trufflehog; pip-audit vs trivy) — технологическое решение архитектора; BRD фиксирует только функцию.