Files
portal/docs/superpowers/specs/2026-06-17-go-live-security-gate-spec.md
T
Дмитрий b65066f17c docs(security): go-live security gate отчёт 17.06 + уроки прогона в wall-guide
Прогон security-go-live на main, локальная цель 127.0.0.1:8000 — вердикт NO-GO.
Блокеры: pg_anonymizer не установлен (ПДн в дампах), F-P1 (телефоны лидов не
вычищаются по сроку), P0 из STRIDE (SAAS_ADMIN_TEST_BYPASS / SSRF webhooks-test /
открытые ручки). Nuclei чисто (1 info php). Semgrep/ZAP — PENDING.

Гайд стены: новый раздел уроков — читать контекст до печати плана, запасной
канал вставки в чат, недетерминизм судьи и рассинхрон указателя F-J.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 14:34:39 +03:00

9.1 KiB

Спека — Go-Live Security Gate (пред-прод прогон безопасности)

Цель

Один воспроизводимый прогон безопасности портала Лидерра перед выходом в интернет: статический анализ, проверка персональных данных (152-ФЗ), модель угроз и динамическое сканирование локальной копии — с единым собранным вердиктом GO / NO-GO и письменным отчётом. Цель прогона — текущая ветка main на локальной копии 127.0.0.1:8000; боевой контур не трогается.

Охват и гарды

Контракт. Прогон — security-only: выдаёт GO/NO-GO только по безопасности и не заменяет сквозной аудит портала (тесты/схема/UI/a11y/coverage). Все динамические проверки направлены строго на локальную копию 127.0.0.1 — боевой адрес не сканируется (гард IS8). Прогон не правит продуктовый код и не коммитит; единственная запись — файл отчёта в docs/security/.

Edge-cases. Если инструмент не установлен (ZAP без Java, Ward/Nuclei отсутствуют) — шаг фиксируется как PENDING, прогон продолжается, итог — «условный GO» с пометкой обязательной установки до публичного деплоя. Если локальный сервер не поднят — динамические шаги (Nuclei/ZAP) дают PENDING, а не ложный «чисто».

Конвенция. Severity → статус: critical/high любого инструмента = NO-GO; medium = предупреждение (фиксируется, не блокирует); low/info = информационно.

Критерий. Прогон считается выполненным, когда все пять шагов отработали (или отмечены PENDING с причиной) и собран отчёт с явным вердиктом GO/NO-GO, перечнем блокеров, предупреждений и PENDING-инструментов.

Шаг 1 — Статика

Контракт. Последовательно: gitleaks (секреты в истории), Semgrep (статика кода), Ward (конфиг/.env/зависимости/код Laravel). Каждый фиксирует результат в отчёте.

Edge-cases. gitleaks: учебная фикстура секрет-сканера — в allowlist gitleaks, не считается утечкой. Рабочее дерево содержит незакоммиченные правки параллельной сессии (карточка сделки F1/F2) — статика видит их; находки из незавершённого кода помечаются как таковые.

Конвенция. gitleaks: любая реальная утечка = NO-GO (critical). Semgrep: 0 critical/high ожидаемо, medium — предупреждение. Ward: 0 critical; APP_DEBUG=true/ APP_ENV=local на dev-копии — ожидаемы (не боевой .env), фиксируются как info.

Критерий. Три инструмента отработали, их вывод разнесён по severity в отчёт.

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

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

Edge-cases. Известный долг F-P1 — deals.phones[] не вычищаются по сроку хранения — проверяется и явно отражается в вердикте (см. {#D6}).

Конвенция. Нарушение Режима 1 уровня critical (ПДн в открытых логах/Sentry) = NO-GO. Замечания Режима 2 — предупреждения, если не critical.

Критерий. Оба режима отработали, список нарушений (или «нет») в отчёте.

Шаг 3 — Угрозы STRIDE

Контракт. Навык threat-model — проверить, что топ-приоритетные STRIDE-угрозы закрыты контрмерами: rate-limit на вход, HMAC на webhook, Sanctum token-auth, CSRF, RLS. Известный долг F-T2 — /api/admin/* без app-гейта авторизации — проверяется явно (см. {#D6}).

Edge-cases. Если актуальной модели угроз за последние 30 дней нет — модель строится заново в этом прогоне.

Конвенция. Незакрытая топ-угроза = блокер либо принятый с владельцем риск; середина — предупреждение.

Критерий. Перечень незакрытых топ-угроз (или «нет») в отчёте.

Шаг 4 — Динамика

Контракт. Цель — локальная копия http://127.0.0.1:8000 (гард IS8). Nuclei — широкое сканирование известных уязвимостей; ZAP — глубокое DAST (active scan).

Edge-cases (обязательны). Nuclei на native-Windows: цель строго 127.0.0.1 (не localhost — резолвер пропустит), низкий темп -rate-limit 20 -c 5 для однопоточного php artisan serve. ZAP требует Java 17 + запущенного демона — при отсутствии шаг = PENDING. Сервер должен быть поднят до сканирования.

Конвенция. critical/high из Nuclei/ZAP = NO-GO; medium — разбор вручную (предупреждение).

Критерий. Динамические сканеры отработали по локальной цели (или PENDING с причиной), находки — в отчёт по severity.

Шаг 5 — Вердикт и отчёт

Контракт. Собрать находки всех шагов в один отчёт docs/security/ с заголовком, датой, версией схемы, commit, целью и блоками по пяти шагам, завершаемый строкой вердикта GO/NO-GO.

Edge-cases. Любой PENDING-инструмент → вердикт «условный GO» с явным перечнем того, что обязано быть установлено до публичного деплоя.

Конвенция. Структура отчёта повторяет канон гейта: блоки ШАГ 1..4, затем === ВЕРДИКТ === с тремя списками — блокеры (critical/high), предупреждения (medium), PENDING-инструменты.

Критерий. Файл отчёта существует, содержит явный вердикт и три списка.

Известные долги для явной проверки

Контракт. Прогон обязан явно подтвердить или закрыть два interim-NO-GO из предыдущего доменного аудита: F-T2 (/api/admin/* без app-гейта авторизации) и F-P1 (152-ФЗ: deals.phones[] не вычищаются по сроку хранения).

Edge-cases. Если за время после аудита долг закрыт кодом — прогон это подтверждает фактом (нашли гейт/очистку), а не «по памяти».

Конвенция. Открытый F-T2 или F-P1 = блокер вердикта, пока не закрыт или не принят владельцем как осознанный риск.

Критерий. В отчёте по каждому из двух долгов — статус «закрыт фактом X» либо «открыт, блокер».

[
  {"id":"vc1","kind":"EXTRACTED","ref":".claude/skills/security-go-live/references/gate.md","anchor":"IS8 — цель по умолчанию локальная"},
  {"id":"vc2","kind":"EXTRACTED","ref":"docs/Tooling_v8_3.md","anchor":"security-go-live — go-live security-gate"}
]