0.136.3

Fixed

  • Глобальный SSRF whitelist в БД + UI (known limitation из #164): pre-call SSRF-валидация (ResolveAndValidateAPIBase / validateLoopbackOrSSRF) в advanced.go, connectivity.go, model_list.go ранее использовала глобальный ssrfGuard.Load() без whitelist — UI-кнопки «проверить подключение» / список моделей провайдера на приватном IP показывали ✗ api_base rejected by security policy, а в логах сыпались startup-WARN’ы. Теперь админ может редактировать CIDR-whitelist через UI: Settings → Система → «Безопасность / SSRF», textarea (по CIDR на строку). Настройка хранится в settings под ключом ssrf_whitelist (миграция не нужна — создаётся при первом сохранении), применяется при старте процесса (restart-required). Один guard покрывает все точки SSRF-проверки: pre-call валидацию (4 места) И dial-time на chat-пути (через providers.SetSSRFGuard). Дефолт для новых инсталляций: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, ::1/128 (все приватные + loopback). Audit-log смены настройки: slog.Info("ssrf_whitelist updated") с actor, previous, raw_request, new_normalized (truncate 1KB).
  • Эндпоинты: GET /api/v1/system/security (любой авторизованный) и PUT /api/v1/system/security (RequireGlobalAdmin). PUT парсит textarea (split по \n/,/пробелам), валидирует каждый CIDR через netip.ParsePrefix, нормализует через Masked() (так 192.168.1.0/16192.168.0.0/16), при невалидном → HTTP 400 invalid_cidr с указанием бракованного токена. Пустой whitelist допустим (означает «блокировать все приватные»).
  • Frontend: типы SecurityConfig/SecurityUpdateResponse в types.ts, методы api.system.security.get/update в endpoints.ts, компонент SecurityCard.svelte (textarea + «Сохранить» + «Сбросить к дефолту» + toast «требуется перезапуск» + индикатор невалидных записей), подключён в settings/system/+page.svelte.

Security

  • Audit-log на security-critical write (ocr review): смена ssrf_whitelist логируется через slog.Info с actor (UserID из auth-mw), previous raw-значением, raw_request (что оператор реально ввёл — для forensics), и new_normalized (что сохранилось). Значения truncate’ятся до 1KB против раздувания логов.
  • Невалидные токены в startup ignored с WARN (ocr review): LoadSSRFWhitelist при старте логирует slog.Warn("ssrf_whitelist: ignoring invalid CIDR(s) at startup", ...) вместо fmt.Printf — survives log aggregation. GET /system/security показывает invalid-список оператору.