Диагностика¶
Каталог симптом → причина → fix. Обновляйте при появлении новых кейсов.
Hub: запуск и базовая работа¶
Backend в crash-loop¶
| Признак в логах | Причина | Fix |
|---|---|---|
JWT_SECRET not set |
Переменная не задана / пустая | Задать в .env или helm values |
dial tcp ...:5432: connect: connection refused |
БД недоступна | Проверить postgres-контейнер, DB_HOST |
password authentication failed for user "securityhub" |
Неверный DB_PASSWORD |
Сверить с тем, что задано в postgres |
goose: failed to apply migration |
Конфликт миграций | См. логи goose; обычно — расхождение версий backend/БД |
panic: ... |
Баг | Reissue в трекер; приложите stacktrace |
Frontend 502 Bad Gateway¶
| Что | Проверка |
|---|---|
| Backend стартанул? | docker compose ps backend — Up? |
| Backend отвечает на 8082? | curl http://localhost:8082/version |
| Frontend nginx видит backend? | Проверить REACT_APP_API_URL build-arg + entrypoint inject |
| Reverse-proxy (nginx/traefik) корректен? | nginx -t, логи /var/log/nginx/error.log |
"Версия: dev" в UI¶
Образ собран без version build-args (баг билда на стороне поставщика). Попросите перевыпуск образа.
Миграции не применяются¶
docker compose exec postgres psql -U securityhub securityhub -c \
"SELECT version_id, tstamp FROM goose_db_version ORDER BY tstamp DESC LIMIT 5;"
- Если таблицы нет — goose не запустился. Логи backend → искать
goose - Если есть, но новые миграции не накатились — проверьте, что в
backend/migrations/есть новые файлы - Если зависло — посмотрите
SELECT * FROM pg_stat_activity WHERE state='active'— возможно, миграция длинная
Loading forever в UI после логина¶
| Причина | Fix |
|---|---|
| Frontend не может загрузить чанки (вылетел 404) | Проверить, что вся статика в frontend-dist/ доступна (curl -I) |
API возвращает 401 на /api/v1/users/me |
JWT истёк или подпись не проверяется. Сверьте JWT_SECRET между backend и worker |
| CORS error | ALLOWED_ORIGINS не включает frontend-domain |
Auth / Keycloak¶
"Login failed" после редиректа из Keycloak¶
| Признак | Причина | Fix |
|---|---|---|
URL: /auth/keycloak/callback?error=invalid_client |
KEYCLOAK_CLIENT_SECRET неверный |
Сверить в Keycloak → Clients → Credentials |
404 на token exchange |
KEYCLOAK_TOKEN_URL указан неправильно (или auto-discovery вернул internal URL) |
Задать KEYCLOAK_TOKEN_URL явно (HTTPS!) |
JWT signature invalid |
KEYCLOAK_JWKS_URL устарел или указывает не на тот realm |
Очистить кэш JWKS (рестарт backend); задать KEYCLOAK_JWKS_URL явно |
Audience mismatch |
В KC_AUDIENCES нет нужного значения |
Добавить или настроить Audience mapper в Keycloak |
Transparent SSO: внешний JWT отклоняется¶
Чек-лист:
FEATURE_SECURITY_HUB_INTEGRATION=trueKC_JWKS_URLдоступен из backend (curlиз контейнера)KC_ISSUERточно совпадает сissв JWT (включая trailing slash)KC_AUDIENCESсодержитaudиз JWTexpвалидный (часы синхронизированы)
Декодировать JWT (без подписи):
Jira¶
Создание задачи: 401 Unauthorized¶
- Cloud Jira: пароль — это API token, не пароль аккаунта
- Self-hosted: PAT истёк (Jira DC)
- Проверить вручную:
curl -u username:token <jira>/rest/api/2/myself
Создание: 403 Forbidden¶
Bot не имеет permission Create Issue в нужном project_key. Проверьте Project → Permissions.
Transition not allowed¶
initial_transition_chain пытается перевести задачу по статусу, недоступному в текущем процессе Jira. Посмотрите Project → Workflow в интерфейсе Jira: какие переходы разрешены из статуса, в котором задача оказалась после создания.
Перенос статуса из Jira не работает¶
| Симптом | Fix |
|---|---|
| Worker не запускается | FEATURE_JIRA_REVERSE_SYNC=true задан? Worker рестартован? |
| Worker идёт, но ничего не обновляется | reverse_sync_done_statuses совпадает с реальными статусами Jira? Default — Done/Closed/Resolved/Fixed |
SSRF blocked |
Self-hosted Jira в LAN → JIRA_ALLOW_LOCAL_DIAL=true |
Автоматически закрылось лишнее¶
Сначала проверьте, что все три условия действительно были выполнены — без любого из них закрытие не должно происходить:
FEATURE_AUTO_VERIFY_FIXES=true— на всей установке;- признак
auto_verify_fixes_enabled— в настройках проекта; verify_fixes=true— в параметрах конкретной загрузки.
Затем проверьте кворум: закрытие должно происходить только после
AUTO_VERIFY_ABSENT_THRESHOLD последовательных проверок, давших
«отсутствует» (по умолчанию 3). Текущее состояние счётчика хранится в поле
auto_verify_absent_streak каждой находки — любое обнаружение сбрасывает его
в ноль.
-- Что закрылось за период и с каким счётчиком отсутствий
SELECT id, title, current_status, auto_verify_absent_streak, updated_at
FROM findings
WHERE current_status = 'fixed'
AND updated_at BETWEEN '2026-06-01' AND '2026-06-02'
ORDER BY updated_at;
Перед откатом
Массовый откат состояний — необратимая операция, затрагивающая сроки
устранения и связанные задачи в трекере. Сделайте резервную копию базы,
выполните запрос сначала как SELECT, убедитесь в объёме выборки — и
только потом меняйте состояния. Возвращать следует в то состояние, в
котором находка была до закрытия (обычно confirmed или in_progress),
а не в несуществующее open.
Если условия из списка выше не выполнялись, а закрытие всё равно произошло — это дефект, и его стоит зафиксировать до отката, сохранив выборку.
Notifications¶
Уведомления не приходят¶
# Глубина очереди > 0? Worker крутит?
# 2. Логи
docker compose logs worker | grep -i notif
# 3. dry-run проверка
# В env: NOTIFICATIONS_DRY_RUN=true → перезапустить worker
# Логи должны показать сообщение, которое было бы отправлено
| Симптом | Fix |
|---|---|
| Очередь пустая, но events происходят | Notification rules не настроены в Project → Notifications |
| Очередь растёт, не уменьшается | Worker не запущен (docker compose ps worker) |
| Telegram: 400 Bad Request | Chat ID формат: для каналов -100..., для групп — отрицательный |
| Telegram: chat not found | Бот не добавлен в чат |
| Mattermost: 400 / 404 | Webhook удалён в Mattermost — пересоздайте |
SARIF Upload¶
Сканер работает, но находки НЕ появляются в Hub (404 page not found при upload)¶
Симптом в логах DomainScope (или другого сканера):
zap sarif upload failed — находки НЕ доставлены в Hub error="404 — маршрут или продукт не найден ..."
Сканер находит уязвимости, но загрузка SARIF возвращает 404. page not found — это
ответ Hub на несматченный маршрут, почти всегда это misconfig, а НЕ отсутствие ресурса:
*_SARIF_API_ENDPOINTсодержит/api/v1. Endpoint должен быть корнем Hub (https://hub.example.com), клиент сам дописывает/api/v1/products/<id>/reports. С хвостом/api/v1путь удваивается → 404. (Клиент DomainScope НЕ стрипает хвостовой/api/v1— он строит URL черезurl.JoinPath(baseURL, "/api/v1/products/..."), поэтому endpoint обязан быть корнем без/api/v1. Любой хвост/api/v1в endpoint'е приведёт к удвоению пути и 404.)*_SARIF_PRODUCT_IDпустой или указывает на несуществующий в Hub продукт. В Helm проверьте, чтоsarifProductIdзарезолвился (umbrella прокидывает UUID default-продукта через secret). Пустой product_id раньше молча схлопывал URL.
Проверка из пода сканера:
# Должно вернуть 202/4xx с JSON, а НЕ "404 page not found":
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
-H "X-API-Key: $DOMAINSCOPE_SARIF_API_TOKEN" -F file=@/dev/null \
"$DOMAINSCOPE_SARIF_API_ENDPOINT/api/v1/products/$DOMAINSCOPE_SARIF_PRODUCT_ID/reports"
Стартовый лог сканера (sarif upload configured) печатает api_endpoint,
product_id_set, auto_upload — сверьте их сразу после старта.