Прогон 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>
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"}
]