151 lines
13 KiB
Markdown
151 lines
13 KiB
Markdown
# 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 фиксирует только функцию.
|