# Security Go-Live Gate — процедура прогона и формат вердикта

Подробная пошаговая процедура для скила `security-go-live` (#73).
Цель — один воспроизводимый прогон перед каждым выходом портала в интернет.

---

## Гарды

**IS8 — цель по умолчанию локальная.** Все динамические проверки (Nuclei, ZAP)
направляются на локальную или тестовую копию портала (`127.0.0.1`). Боевой
(`crm.bp-gr.ru` или любой публичный IP) — только по явной команде заказчика:
«сканируй прод» / «сканируй боевой».

**IS7 — граница с `audit-portal`.** `security-go-live` — security-only gate:
выдаёт GO/NO-GO по безопасности. Он не заменяет 14-фазный `audit-portal`
(тесты, схема, UI-smoke, a11y, coverage, bundle и пр.). Перед первым
production-деплоем рекомендуется прогнать `audit-portal` **и** `security-go-live`
как два отдельных прогона; при плановых go-live (хотфикс/фича) — достаточно
`security-go-live`.

---

## Шаг 1 — Статика (static analysis)

Запустить последовательно. Каждый инструмент фиксирует результат в разделе
отчёта.

### 1.1 gitleaks — поиск секретов в истории

```powershell
# Полная история
.\bin\gitleaks.exe detect --source . --log-opts "--all"
# Только staged/unstaged (перед коммитом)
.\bin\gitleaks.exe protect --staged
```

Ожидаемо: **0 утечек**. Любой leak = NO-GO (critical).

### 1.2 Semgrep — статический анализ кода

```powershell
npm run sast
```

Ожидаемо: **0 critical/high**. Medium — предупреждение (не блокер).

### 1.3 Ward — Laravel config / env / deps / code

Ward (#70) — Go-бинарь, замена заброшенного Enlightn. Сканирует:
`.env` (8 проверок), `config/*.php` (13 проверок), зависимости Composer
(через OSV.dev), код (секреты, injection, XSS, debug-артефакты, crypto,
CORS/CSRF/mass-assignment, auth).

```powershell
# Если Ward установлен (pending — нет тегов-релизов, pin по commit SHA)
.\bin\ward.exe scan --path app/
```

Если Ward **не установлен** (pending `docs/security/ward-setup.md`) — отметить
в отчёте как `PENDING` и продолжить. Ward — не блокер установки gate,
но должен быть установлен до первого реального go-live.

Ожидаемо: **0 critical**. High — разобрать вручную. Ошибки конфигурации
(APP_DEBUG=true, слабые ключи, открытые CORS) = NO-GO если critical.

### 1.4 Trail of Bits — глубокий on-demand аудит (#39)

Вызывается вручную перед первым публичным релизом или при значительных
изменениях security-периметра. Не требуется при каждом хотфиксе.

```
/differential-review:diff-review   # если ревьюим конкретный diff
/audit-context-building:audit-context   # для supply-chain аудита
```

Результаты фиксируются в `docs/security/trail-of-bits-YYYY-MM-DD.md`.

---

## Шаг 2 — ПДн / 152-ФЗ

Вызвать скил `pdn-152fz-audit` (#71).

```
/pdn-152fz-audit
```

Прогнать оба режима:

- **Режим 1 (технический):** RLS на таблицах ПДн, маскирование pg_anonymizer,
  отсутствие phone/email в логах, pg_anonymizer в дампах.
- **Режим 2 (соответствие 152-ФЗ):** хранение в РФ, согласия, права субъекта
  (`pd_subject_requests`), журнал обработки (`pd_processing_log`), уведомление РКН.

Итог: список нарушений (если есть). Нарушения Режима 1 уровня critical (ПДн
в открытых логах/Sentry) = NO-GO.

---

## Шаг 3 — Угрозы (threat model)

Вызвать скил `threat-model` (#72) или открыть последний файл
`docs/security/threat-model-YYYY-MM-DD.md`.

Цель: убедиться, что **топ-приоритетные угрозы из STRIDE** закрыты контрмерами
(rate-limit на login, HMAC на webhook, Sanctum token-auth, CSRF, RLS).

Если актуальная модель угроз отсутствует (нет файла за последние 30 дней) —
запустить `threat-model` перед динамикой.

---

## Шаг 4 — Динамика (dynamic analysis, локальная цель)

> **IS8:** по умолчанию цель — локальная копия. Убедиться, что приложение
> запущено: `php artisan serve` → `http://127.0.0.1:8000`.

### 4.1 Nuclei — широкое сканирование (#69)

Nuclei установлен как CLI-бинарь `bin/nuclei.exe` (MIT, projectdiscovery,
v3.8.0). **Не MCP-сервер.**

**Квирки native-Windows (обязательно соблюдать):**

1. **Цель — `127.0.0.1`, НЕ `localhost`.** Резолвер Nuclei не разрешает
   `localhost` на этой машине — цель будет пропущена (квирк зафиксирован в
   `docs/security/nuclei-setup.md`).
2. **Низкий rate-limit для dev-сервера.** `php artisan serve` однопоточный;
   без ограничений Nuclei перегружает его ложными connection-ошибками.
   Всегда использовать `-rate-limit 20 -c 5`.

```powershell
# Стандартный прогон (medium+)
bin\nuclei.exe -u "http://127.0.0.1:8000" `
  -rate-limit 20 -c 5 -timeout 5 -duc `
  -severity medium,high,critical

# Только технологический стек (быстрый smoke)
bin\nuclei.exe -u "http://127.0.0.1:8000" -tags tech `
  -rate-limit 20 -c 5 -timeout 5 -duc
```

Если `bin/nuclei.exe` отсутствует — отметить `PENDING` и продолжить.
Детали установки: `docs/security/nuclei-setup.md`.

Ожидаемо: **0 critical/high**. Medium — разобрать вручную.

### 4.2 ZAP — глубокое DAST (#68)

ZAP (#68) — официальный MCP add-on (`zaproxy/zap-extensions`, Apache-2.0),
alpha v0.1.0. Требует Java 17+ и запущенного ZAP-демона.

Если ZAP **не установлен** (pending Java) — отметить `PENDING` и продолжить.
Детали: `docs/security/zap-setup.md` (когда будет создан).

```
# Через ZAP MCP (когда ZAP установлен)
# 1. Запустить ZAP-демон: zaproxy -daemon -port 8080 -config api.key=<key>
# 2. Spider
ZapStartSpiderTool(url="http://127.0.0.1:8000", contextId=...)
# 3. Active scan
ZapStartActiveScanTool(url="http://127.0.0.1:8000", contextId=...)
# 4. Отчёт
ZapGenerateReportTool(...)
```

Ожидаемо: **0 critical/high**. Medium — разобрать вручную.
Critical/high из ZAP active scan = NO-GO.

---

## Шаг 5 — Сбор находок и вердикт

### Severity → статус

| Severity | Источник | Статус gate |
|---|---|---|
| critical | любой инструмент | **NO-GO** (блокер) |
| high | любой инструмент | **NO-GO** (блокер) |
| medium | любой инструмент | Предупреждение (не блокирует go-live, фиксируется) |
| low / info | любой инструмент | Информационно |
| PENDING | ZAP / Ward / Nuclei не установлены | Условный GO — инструменты должны быть установлены до публичного деплоя |

### Формат отчёта

```
=== SECURITY GO-LIVE REPORT ===
Дата: YYYY-MM-DD
Версия схемы: vX.XX
Commit: <git rev-parse HEAD>
Цель: http://127.0.0.1:<port> (локальная копия)

--- ШАГ 1: СТАТИКА ---
gitleaks: OK (0 утечек) / FAIL (<N> утечек)
Semgrep:  OK (0 critical/high) / FAIL (<список>)
Ward:     OK / FAIL (<список>) / PENDING (не установлен)
Trail of Bits: OK / SKIP (не применимо к этому прогону)

--- ШАГ 2: ПДн / 152-ФЗ ---
pdn-152fz-audit Режим 1: OK / FAIL (<список>)
pdn-152fz-audit Режим 2: OK / ПРЕДУПРЕЖДЕНИЯ (<список>)

--- ШАГ 3: УГРОЗЫ ---
threat-model: ЗАКРЫТЫ (файл docs/security/threat-model-YYYY-MM-DD.md)
Незакрытые топ-угрозы: <список или "нет">

--- ШАГ 4: ДИНАМИКА ---
Nuclei:   OK (0 critical/high) / FAIL (<список>) / PENDING (не установлен)
ZAP:      OK (0 critical/high) / FAIL (<список>) / PENDING (не установлен)

=== ВЕРДИКТ: GO ✅ / NO-GO ❌ ===
Блокеры (critical/high):
  - <инструмент>: <описание> — <рекомендация>
  (или "Блокеров нет")

Предупреждения (medium):
  - <инструмент>: <описание>
  (или "Предупреждений нет")

PENDING-инструменты (должны быть закрыты до публичного деплоя):
  - Ward #70: установка — docs/security/ward-setup.md
  - ZAP #68: установка — docs/security/zap-setup.md (pending Java)
  (или "Все инструменты установлены")
=== END ===
```

---

## Типичные блокеры и действия

| Находка | Источник | Действие |
|---|---|---|
| APP\_DEBUG=true | Ward / Semgrep | Исправить `.env` перед деплоем |
| Секрет в git-истории | gitleaks | Rotate + `git filter-repo`; НЕ деплоить |
| ПДн в логах Laravel | pdn-152fz-audit | Убрать из LogChannel + Sentry scrubbing |
| CSRF отключён | Ward | Проверить `VerifyCsrfToken` middleware |
| Слабый APP\_KEY | Ward | `php artisan key:generate` |
| Критическая CVE в зависимости | Semgrep / Ward | `composer update` или `npm update` |
| SQL injection / XSS | ZAP / Nuclei | Исправить код, перепрогнать |
| Незакрытая STRIDE-угроза | threat-model | Реализовать контрмеру или принять риск с заказчиком |
