# GuardDog Nexus Интеграция [GuardDog](https://github.com/DataDog GuardDog) (сканер уязвимостей пакетов PyPI) с [Sonatype Nexus Repository Manager]. Автоматически сканирует Python-пакеты, хранящиеся в Nexus, на наличие уязвимостей, вредоносного кода и подозрительных паттернов при каждом обновлении или добавлении пакета. ## Возможности - **Автоматическое сканирование** по вебхукам Nexus при создании/обновлении пакетов - **Поддержка нескольких экосистем** — PyPI, Go, npm (любой формат через прокси-репозитории Nexus) - **REST API** для просмотра результатов сканирования, уязвимостей, статистики и экспорта в CSV - **Веб-интерфейс** с дашбордом, таблицами сканирований и фильтрацией по уязвимостям - **LLM-анализ** — автоматический разбор каждой уязвимости через OpenAI-совместимые API (опционально, настраивается) - **Дедупликация** по URL и SHA256 — один и тот же пакет сканируется один раз - **Структурированное логирование** в формате JSON с опциональной отправкой в syslog - **Docker Compose** для развёртывания приложения, Nexus и настройки в одном стеке ## Архитектура ``` Nexus ──(webhook)──> GuardDog Nexus ──(REST API)──> Веб-интерфейс │ ├──> GuardDog CLI (сканирование) ├──> LLM API (анализ уязвимостей) ├──> SQLite (хранилище результатов) └──> REST API (данные для UI + экспорт CSV) ``` ## Быстрый старт ### Требования - Docker и Docker Compose - Python 3.10+ (для локальной разработки) ### Развёртывание в Docker ```bash # Скопируйте файл конфигурации cp .env.example .env # Отредактируйте .env при необходимости # NEXUS_PASSWORD=<ваш_пароль_администратора_Nexus> # Запустите стек make docker-up ``` После запуска доступны: | Сервис | URL | Порт | |--------|-----|------| | GuardDog Nexus | http://localhost:8080 | 8080 | | Sonatype Nexus | http://localhost:8081 | 8081 | ### Локальная разработка ```bash # Установите зависимости make install dev # Настройте переменные окружения cp .env.example .env export $(cat .env | xargs) # Запустите приложение python -m guarddog_nexus.main ``` ## Переменные окружения | Переменная | По умолчанию | Описание | |------------|-------------|----------| | `NEXUS_URL` | `http://localhost:8081` | URL Sonatype Nexus | | `NEXUS_USERNAME` | `admin` | Имя пользователя Nexus | | `NEXUS_PASSWORD` | _(обязательно)_ | Пароль пользователя Nexus | | `DATABASE_PATH` | `data/guarddog.db` | Путь к SQLite-базе данных | | `HOST` | `0.0.0.0` | Хост для прослушивания | | `PORT` | `8080` | Порт для прослушивания | | `LOG_LEVEL` | `INFO` | Уровень логирования | | `LOG_SYSLOG_HOST` | _(пусто)_ | Хост syslog для отправки логов | | `LOG_SYSLOG_PORT` | `514` | Порт syslog | | `WEBHOOK_SECRET` | _(пусто)_ | Секрет для HMAC-подписи вебхуков | | `SCAN_TIMEOUT_SECONDS` | `300` | Таймаут сканирования одного пакета | | `TEMP_DIR` | `/tmp/guarddog-nexus` | Временная директория для загрузки пакетов | | `GUARDDOG_BINARY` | `guarddog` | Путь к бинарнику GuardDog | | `NEXUS_DOWNLOAD_TIMEOUT_SECONDS` | `120` | Таймаут загрузки пакета из Nexus | | `NEXUS_API_TIMEOUT_SECONDS` | `30` | Таймаут запросов к Nexus REST API | | `MAX_CONCURRENT_SCANS` | `4` | Максимум одновременных сканирований GuardDog | | `LOG_SYSLOG_FACILITY` | `local0` | Syslog facility (local0–local7) | | `LLM_ENABLED` | `0` | `1` — включить LLM-анализ уязвимостей | | `LLM_API_KEY` | _(пусто)_ | API-ключ (OpenAI / Groq / Ollama / etc.) | | `LLM_API_BASE` | `https://api.openai.com/v1` | Базовый URL OpenAI-совместимого API | | `LLM_MODEL` | `gpt-4o-mini` | Название модели | | `LLM_TIMEOUT_SECONDS` | `30` | Таймаут запроса к LLM | | `LLM_MAX_CONCURRENT_ANALYSES` | `2` | Максимум одновременных LLM-анализов | ## Настройка Nexus ### Создание репозитория 1. Убедитесь, что в Nexus создан репозиторий `pypi-proxy` (прокси на `https://pypi.org`) 2. Настройте вебхук Nexus для отправки событий на `http://:8080/webhooks/nexus` 3. Используйте `scripts/setup-nexus.sh` для автоматической настройки (требует `curl`) ### Вебхуки GuardDog Nexus принимает вебхуки от Nexus при событии `UPDATED` (срабатывает при обновлении кэша прокси-репозитория). Для валидации вебхуков установите `WEBHOOK_SECRET` в `.env` — подпись проверяется через HMAC-SHA256. > **Примечание:** Вебхуки доступны в Nexus Pro. В Nexus Repository Manager 3 Community Edition можно использовать плагин [nexus-blobstore-webhook](https://github.com/sonatype-nexus-community/nexus-blobstore-webhook) или настроить вебхуки вручную через административную панель. ### Настройка вебхуков в Nexus 1. В административной панели Nexus перейдите в **System → Capabilities** 2. Создайте capability типа **Webhook: Repository** 3. Укажите **URL:** `http://guarddog-nexus:8080/webhooks/nexus` (замените хост если нужно) 4. Выберите тип события: **Repository → Asset → Updated** 5. В фильтре репозиториев выберите: `pypi-proxy`, `go-proxy`, `npm-proxy` 6. Если задан `WEBHOOK_SECRET`, укажите тот же секрет в поле **Secret Key** > Для локальной разработки без реальных вебхуков можно отправлять тестовые запросы вручную: > ```bash > curl -X POST http://localhost:8080/webhooks/nexus \ > -H "Content-Type: application/json" \ > -d '{"action":"UPDATED","repositoryName":"pypi-proxy","asset":{"format":"pypi","name":"/packages/pkg/1.0/pkg-1.0.tar.gz","downloadUrl":"http://nexus:8081/repository/pypi-proxy/packages/pkg/1.0/pkg-1.0.tar.gz"}}' > ``` ## REST API ### Сканирования | Метод | Путь | Описание | |-------|------|----------| | GET | `/api/v1/scans` | Список сканирований (пагинация, фильтр `flagged`) | | GET | `/api/v1/scans/stats` | Статистика: общее количество, уязвимые пакеты, топ правил | | GET | `/api/v1/scans/{id}` | Детали конкретного сканирования с результатами | | GET | `/api/v1/scans/export` | Экспорт сканирований в CSV | ### Пакеты | Метод | Путь | Описание | |-------|------|----------| | GET | `/api/v1/packages` | Список уникальных пакетов (пагинация, фильтр по экосистеме) | | GET | `/api/v1/packages/{name}/{version}` | Все сканирования и уязвимости для пакета | | GET | `/api/v1/packages/export` | Экспорт пакетов в CSV | ### Уязвимости | Метод | Путь | Описание | |-------|------|----------| | GET | `/api/v1/findings` | Список уязвимостей (фильтр по правилу, severity, scan_id) | | POST | `/api/v1/findings/{id}/analyze` | Запустить LLM-анализ уязвимости | ### Здоровье | Метод | Путь | Описание | |-------|------|----------| | GET | `/health` | Проверка работоспособности | ## Веб-интерфейс | Страница | URL | Описание | |----------|-----|----------| | Дашборд | `/` | Статистика, графики, топ уязвимых пакетов | | Сканирования | `/scans` | Таблица всех сканирований с фильтрацией | | Детали сканирования | `/scans/{id}` | Результаты одного сканирования | | Пакеты | `/packages` | Таблица уникальных пакетов | | Детали пакета | `/packages/{name}/{version}` | История сканирований и уязвимости пакета | ## Структура проекта ``` guarddog-nexus/ ├── guarddog_nexus/ # Основной пакет │ ├── main.py # Точка входа FastAPI │ ├── config.py # Конфигурация из переменных окружения │ ├── constants.py # Централизованные константы │ ├── logging_setup.py # JSON-логирование + syslog │ ├── core/ # Ядро: сканер, harvester, LLM │ │ ├── scanner.py # Интеграция с GuardDog CLI │ │ ├── harvester.py # Пайплайн: загрузка → скан → сохранение │ │ ├── nexus.py # HTTP-клиент + extractor'ы pypi/go/npm │ │ └── llm.py # LLM-клиент (OpenAI-совместимый) │ ├── db/ # База данных │ │ ├── engine.py # Async SQLAlchemy + миграции │ │ ├── models.py # ORM-модели (Scan, Finding) │ │ └── queries.py # Общие SQL-запросы │ ├── routes/ # Роутеры FastAPI │ │ ├── webhooks.py # Приём вебхуков Nexus │ │ ├── api_scans.py # REST API: сканирования │ │ ├── api_packages.py # REST API: пакеты │ │ ├── api_findings.py # REST API: уязвимости │ │ └── web.py # Веб-интерфейс (Jinja2 + htmx) │ └── web/ # Статика и шаблоны │ ├── templates/ # Jinja2-шаблоны │ └── static/ # CSS, JS ├── tests/ # Тесты pytest ├── scripts/ # Вспомогательные скрипты ├── docker-compose.yml # Стек Docker Compose ├── Dockerfile # Образ приложения └── pyproject.toml # Зависимости и настройки ``` ## Команды Makefile | Команда | Описание | |---------|----------| | `make install` | Установка зависимостей проекта | | `make dev` | Установка зависимостей для разработки | | `make test` | Запуск тестов | | `make lint` | Проверка кода через Ruff | | `make format` | Форматирование кода через Ruff | | `make docker-build` | Сборка Docker-образа | | `make docker-up` | Пересборка и запуск стека (`up -d --build`) | | `make docker-down` | Остановка стека | | `make docker-destroy` | Остановка стека с удалением всех данных (`-v`) | | `make docker-logs` | Просмотр логов стека | | `make docker-rebuild` | Полная пересборка (down + build + up) | | `make clean` | Очистка артефактов сборки | ## Безопасность - Вебхуки поддерживают HMAC-SHA256 подпись через `WEBHOOK_SECRET` - Nexus-клиент использует BasicAuth для аутентификации - Результаты сканирования хранятся в локальной SQLite-базе - Временные файлы пакетов удаляются после сканирования ## LLM-анализ GuardDog Nexus может автоматически анализировать каждую найденную уязвимость через LLM (языковую модель). При включении (`LLM_ENABLED=1`) каждый flagged скан получает AI-разбор: насколько угроза реальна, что делает подозрительный код, рекомендации. ### Как работает 1. **Автоматический режим:** после завершения скана с уязвимостями GuardDog Nexus отправляет каждую находку в LLM, сохраняет отчёт в БД и включает его в syslog-событие 2. **Ручной режим:** в веб-интерфейсе на странице сканирования у каждой уязвимости есть кнопка «Analyze with LLM» — нажатие отправляет запрос и показывает вердикт inline ### Поддерживаемые провайдеры Любой OpenAI-совместимый API. Примеры конфигурации: ```bash # OpenAI LLM_ENABLED=1 LLM_API_KEY=sk-... LLM_API_BASE=https://api.openai.com/v1 LLM_MODEL=gpt-4o-mini # Groq (быстрее, бесплатный тир) LLM_ENABLED=1 LLM_API_KEY=gsk_... LLM_API_BASE=https://api.groq.com/openai/v1 LLM_MODEL=llama-3.3-70b-versatile # Локальный Ollama LLM_ENABLED=1 LLM_API_KEY=ollama LLM_API_BASE=http://host.docker.internal:11434/v1 LLM_MODEL=llama3.2 ``` ### Формат ответа LLM возвращает JSON с полями: - `verdict` — `safe` / `suspicious` / `malicious` - `summary` — вердикт в одно предложение - `analysis` — подробный разбор (2–3 абзаца) - `severity_rating` — `low` / `medium` / `high` / `critical` Без LLM (`LLM_ENABLED=0`) весь остальной функционал работает как обычно. ## Лицензия MIT