Commit Graph

32 Commits

Author SHA1 Message Date
Marker689
6e6f45ce03 fix: фаза 2 — критические фиксы
READМЕ: убрать NEXUS_REPOSITORIES, CREATED→UPDATED, go/npm/Gem→go/npm,
  добавить MAX_CONCURRENT_SCANS, CSV-экспорт, инструкцию по вебхукам Nexus
Dockerfile: uv pip install --system . (единый источник deps — pyproject.toml)
docker-compose: WEBHOOK_SECRET, SCAN_TIMEOUT_SECONDS
pyproject.toml: убрать deprecated [tool.ruff].select
config.py: default из DEFAULT_MAX_CONCURRENT_SCANS
constants.py: убрать GUARDDOG_ERRORS_KEY (мёртвый), .gem из PACKAGE_EXTENSIONS,
  LLM prompt: «Python»→«software»
queries.py: убрать return_total
Makefile: docker-up +--build, docker-down без -v, +docker-destroy,
  +docker-rebuild, убран typecheck
2026-05-10 07:23:43 +03:00
Marker689
8726b65808 refactor: реструктуризация — core/, db/, routes/, web/
guarddog_nexus/
├── core/          scanner, harvester, nexus, llm
├── db/            engine, models, queries
├── routes/        webhooks, api_*, web
└── web/           templates + static

- 11 файлов перемещено (git mv — сохранена история)
- Все импорты обновлены (~15 файлов)
- main.py, tests — исправлены пути
- 50/50 тестов, ruff clean
2026-05-10 07:17:41 +03:00
Marker689
22dc87851a fix: Go-пакеты со слешами в имени ломали роутинг
Использован :path в FastAPI-роутах, имя+версия парсятся из URL.
Шаблоны urlencode-ят имена пакетов при генерации ссылок.
2026-05-10 06:41:00 +03:00
Marker689
6523f55dcd feat: поддержка Go и npm экосистем
- setup-nexus.sh: создание go-proxy (proxy.golang.org) и npm-proxy (registry.npmjs.org)
- nexus_client.py: extract_go_info() и extract_npm_info() для парсинга путей
  Go:  packages/github.com/gorilla/mux/@v/v1.8.0.zip → name=github.com/gorilla/mux ver=v1.8.0
  npm: packages/lodash/-/lodash-4.17.21.tgz → name=lodash ver=4.17.21
- nexus_client.py: EXTRACTORS dict + extract_package_info() универсальный extractor
- webhooks.py: _detect_ecosystem() — определяет экосистему из asset.format
- harvester.py: использует extract_package_info() вместо extract_pypi_info()
- Всё в Docker-контейнере, на хосте ничего не ставится
- GuardDog поддерживает go и npm из коробки
2026-05-10 06:29:34 +03:00
Marker689
646a50d01a fix(ui): добавить name="status" на select + hx-include крос-связку
- select status-filter: добавлен name="status" (htmx берёт name, не id)
- search input + status select: взаимные hx-include
  (поиск включает статус, статус включает поиск)
2026-05-10 06:17:25 +03:00
Marker689
ab60d1944d fix(ui): фильтр-бар больше не в htmx-фрагменте — не дублируется
Фильтр-бар вынесен из _scans_table.html / _packages_table.html
в scans_list.html / packages_list.html — вне htmx target.
htmx заменяет только таблицу, фильтр остаётся на месте.
2026-05-10 06:14:10 +03:00
Marker689
c4c27deb79 fix(ui): исправить раздвоение интерфейса при htmx-фильтрации
Проблема: htmx через hx-target="#scans-table-container" получал
полную HTML-страницу (с <html>, <nav>, <head>) и вставлял её внутрь
существующей страницы → дублировался header.

Решение: шаблоны разделены на полные + фрагменты:
  - _scans_table.html — только filter-bar + таблица + пагинация
  - _packages_table.html — аналогично
  - web/routes.py: проверка HX-Request хедера → отдаём фрагмент
2026-05-10 06:08:24 +03:00
Marker689
d23abe8b4b feat: лимит конкурентных сканов через asyncio.Semaphore
- config.py: MAX_CONCURRENT_SCANS (default=4)
- harvester.py: глобальный _scan_semaphore оборачивает scan_package()
  — при N одновременных сканах, (N+1)-й будет ждать освобождения слота
  — download и SHA256 не лимитируются, только guarddog subprocess
- docker-compose.yml, .env.example: переменная добавлена
2026-05-10 05:52:23 +03:00
Marker689
c4dcd79ecd fix: защита от дубликатов сканов — UPDATED-only + per-URL мьютекс
- constants.py: RELEVANT_WEBHOOK_ACTIONS теперь только UPDATED
  (CREATED игнорируется, Nexs proxy шлёт UPDATED при обновл кэша)
- harvester.py: asyncio.Lock на каждый download_url
  — при параллельных вебхуках только первый пройдёт, остальные skipped
  — lock проверяется + DB re-check внутри критической секции
- tests: обновлены фикстуры (CREATED→UPDATED), добавлен тест ignores_created
2026-05-10 05:47:35 +03:00
Marker689
1343c3f415 refactor(ui): блочный дизайн + LLM-отчёт с цветовой индикацией
dashboard:
- Убран: severity ratio bar, Top Rules Triggered, Most Flagged Packages
- Заменены 6 stat-карточек на компактную stat-minibar
- 2-колоночная сетка: heatmap + Latest Flagged (с красной рамкой)
- Таблицы сжаты (.compact)

findings (scan/package detail):
- Findings всегда раскрыты как блоки (.finding-block)
- Убран accordion (details/summary) и toggle-all кнопка
- Код в тёмном блоке, кнопка Copy сверху

LLM-отчёт:
- Цветовая индикация по вердикту:
  - safe       → зелёный badge, зелёная рамка, лёгкий зелёный фон
  - suspicious → жёлтый badge, жёлтая рамка, лёгкий жёлтый фон
  - malicious  → красный badge, красная рамка, лёгкий красный фон
- Бейдж с вердиктом + severity rating в хедере
- Summary курсивом, analysis с pre-line для абзацев

Скан-инфо:
- scan-info-block с grid-раскладкой (8 полей)
- SHA256 компактным шрифтом
- Блок ошибки скана отдельно выделен

CSS:
- Удалены: .stats-grid, .stat-card, .severity-bar*, .top-rules-chart*,
  .finding-card*, .finding-details, .finding-header-row, .finding-summary-hint
- Добавлены: .stat-minibar, .dashboard-grid, .dash-block, .scan-info-*,
  .finding-block, .llm-{safe,suspicious,malicious}, .llm-badge-*,
  table.compact
- app.js: удалён toggleFindings()
2026-05-10 05:24:43 +03:00
Marker689
a754f91abf fix: устойчивый парсинг LLM-ответа — обработка markdown code blocks
- llm.py:  возвращён (нужен для structured output)
- Добавлен fallback-парсинг для ответов обёрнутых в ```json
- Устранён undefined-variable баг в except-блоке
2026-05-10 05:14:38 +03:00
Marker689
0a22c2cce8 fix: LLM таймаут + debug-лог для диагностики 2026-05-10 05:01:31 +03:00
Marker689
46e79ceab1 docs: добавить LLM-анализ в README
- Возможности: новый пункт про LLM
- Архитектура: LLM API на диаграмме
- Переменные: все 8 новых env-переменных в таблице
- Новый раздел LLM-анализ: описание, примеры конфигурации
  (OpenAI, Groq, Ollama), формат ответа
- API: добавить /findings/{id}/analyze, /export endpoints
- Структура: constants.py, queries.py, llm.py
2026-05-10 04:48:38 +03:00
Marker689
3404df0f28 fix: авто-миграция SQLite — добавление недостающих колонок из моделей
При добавлении нового поля в модель (report в Finding) старое create_all
не добавляет колонку в существующую БД → 500 ошибка.
Теперь _migrate() проверяет PRAGMA table_info и добавляет
недостающие колонки через ALTER TABLE
2026-05-10 04:45:31 +03:00
Marker689
cff15a5284 docs: добавить LLM-переменные в .env.example и docker-compose.yml
- .env.example: LLM_ENABLED, LLM_API_BASE, LLM_API_KEY, LLM_MODEL, LLM_TIMEOUT_SECONDS
- docker-compose.yml: прокидывает LLM-переменные в контейнер guarddog-nexus
2026-05-10 04:39:23 +03:00
Marker689
834138368a refactor: вынос хардкода + LLM-анализ finding'ов
## Часть A: Вынос хардкода
- Новый модуль constants.py — все magic strings, лимиты, severity, ключи
  (104 хардкод-значения централизованы)
- Новый модуль queries.py — общие SQL-запросы (build_scan_list_query,
  build_package_list_query, get_dashboard_stats)
  Убрана дупликация между api/*.py и web/routes.py (~90%)

- config.py: добавлены NLP_ENABLED, nexus_timeout, guarddog_binary,
  log_syslog_facility, LLM-переменные
- nexus_client.py: таймауты из конфига, SHA256_CHUNK_SIZE из constants
- scanner.py: error-ключи из constants, GUARDDOG_OUTPUT_FORMAT из constants
- webhooks.py: RELEVANT_WEBHOOK_ACTIONS, METADATA_PATTERNS, ignore-строки
  из constants
- logging_setup.py: конфигурируемый syslog facility, APP_PACKAGE из constants
- main.py: APP_NAME, APP_DESCRIPTION, APP_PACKAGE из constants
- models.py: поле report: JSON | None в Finding для LLM-отчётов
- harvester.py: авто-очистка tmpdir через finally; ERROR_MESSAGE_MAX_LENGTH
  из constants; PACKAGE_EXTENSIONS вместо SUPPORTED_EXTENSIONS (с .gem)
- api/*.py + web/routes.py: используют build_*_query из queries.py,
  константы для лимитов и сортировок
- tests/conftest.py: SEVERITY_WARNING, DEFAULT_ECOSYSTEM из constants

## Часть B: LLM-анализ finding'ов
- llm.py: клиент для OpenAI-совместимых API с промптом security-аналитика
- harvester.py: авто-триггер после flagged scan, сохранение report в БД
- api/findings.py: POST /{id}/analyze — ручной триггер
- web/routes.py: POST /api/v1/findings/{id}/analyze — HTMX-фрагмент
- _llm_report_fragment.html: шаблон фрагмента с вердиктом
- scan_detail.html, package_detail.html: кнопка Analyze with LLM
  (htmx-post, spinner, inline-замена на LLM-отчёт)
- style.css: стили для .llm-report .verdict-safe/suspicious/malicious

## Часть C: Тесты
- 50 тестов, все зелёные
- Линтер чистый
- Тесты используют constants где нужно
2026-05-10 04:37:07 +03:00
Marker689
c43e7c4c9b fix: критические баги и качество кода — полный аудит
Критические фиксы:
- main.py: монтировать /static из web/static/ (CSS не грузился совсем)
- api/scans.py: filtered total count (был всегда общий, игнорируя фильтры)
- web/routes.py: исправлен VALID_SORT_FIELDS (отсутствовали ключи packages)
- web/routes.py: filtered total count для web scans list
- package_detail.html: f.data.X вместо f.X (findings не отображались)

Чистка мёртвого кода:
- config.py: удалён _parse_repos и nexus_repositories (не использовались)
- web/routes.py: удалён completed_scans/failed_scans (не отображались)
- удалён мёртвый guarddog_nexus/static/style.css (67-байтный стаб)

Качество кода:
- web/routes.py: Jinja2 Environment кэшируется на уровне модуля
- Вынесен дублирующийся JS в web/static/app.js
- Вынесены дублирующиеся inline-стили в CSS-классы
- Исправлен duplicate class attribute в списках
- Удалены гигантские SVG из empty states

Тесты:
- 20 новых edge-case тестов (CSV export, search/filter/sort, 404, pagination)
- Добавлен sample_flagged_scan fixture
- Итого: 50 тестов, все зелёные
2026-05-10 03:46:05 +03:00
Marker689
6c8e89c95e fix: убрать неиспользуемый импорт text из packages.py 2026-05-10 03:17:32 +03:00
Marker689
97b89d3fdf ui: добавить экспорт в CSV для сканирований и пакетов
- api/scans.py: добавить /api/v1/scans/export endpoint с фильтрами
- api/packages.py: добавить /api/v1/packages/export endpoint с фильтрами
- scans_list.html: добавить кнопку Export CSV в filter bar
- packages_list.html: добавить кнопку Export CSV в filter bar
- CSV включает все поля с правильным форматированием
2026-05-10 03:16:58 +03:00
Marker689
d5df1d75b8 ui: улучшить карточки findings — сворачивание, копирование кода, breadcrumbs
- Добавить collapsible details/summary для findings
- Добавить кнопку Copy с feedback 'Copied!'
- Добавить toggle All (Expand/Collapse)
- Добавить breadcrumbs на detail-страницах
- Добавить spinner для scanning статуса на detail-страницах
- Добавить empty state для findings
- Добавить scripts block в base.html
2026-05-10 03:13:54 +03:00
Marker689
00424b494a ui: добавить поиск, фильтрацию и сортировку на списки
API:
- scans.py: добавить search, status, sort_by, sort_dir параметры
- packages.py: добавить search, sort_by, sort_dir параметры
- web/routes.py: передать новые параметры в шаблоны

UI:
- scans_list.html: search input (htmx debounce), status filter dropdown,
  sortable columns с hx-get, empty state
- packages_list.html: search input (htmx debounce), sortable columns,
  empty state
- pagination сохраняет все параметры фильтрации/сортировки
2026-05-10 03:12:26 +03:00
Marker689
d00cee3432 ui: улучшить дашборд — bar-графики, tooltips, empty states, spinner для scanning
- Заменить inline div-графики на styled bars с transition
- Добавить tooltips на heatmap
- Добавить empty state когда нет findings
- Добавить spinner для статуса scanning
- Добавить breadcrumbs на dashboard
- Добавить title block
2026-05-10 03:07:07 +03:00
Marker689
18d33cdfd7 ui: вынести CSS в отдельный файл, добавить sticky nav и title block
- Создать guarddog_nexus/web/static/style.css со всеми стилями
- Убрать inline <style> из base.html
- Добавить sticky header для навигации
- Добавить title block для кастомных заголовков страниц
- Добавить базовые анимации (pulse, spin, hover effects)
2026-05-10 03:05:55 +03:00
Marker689
42dcfe33b5 fix: SHA256-based dedup — same version different file now re-scans 2026-05-09 06:20:43 +03:00
Marker689
41a8745198 fix: async subprocess + httpx — no more event loop blocking during scans 2026-05-09 05:58:55 +03:00
Marker689
e577f1944c refactor: JSON data column for findings, code snippets captured and displayed 2026-05-09 05:52:10 +03:00
Marker689
e83167a938 feat: rich dashboard with severity bars, heatmap, most flagged, live poll 2026-05-09 05:35:36 +03:00
Marker689
d776d037e7 fix: real nexus webhook format, atomic dedup, tested live 2026-05-09 05:25:58 +03:00
Marker689
d73bb910fe fix: real-world tested — Docker stack + Nexus, verified full scan pipeline 2026-05-09 05:08:28 +03:00
Marker689
4bfead8d6e fix: scanner now handles real guarddog v2 JSON format 2026-05-09 04:55:58 +03:00
Marker689
4ce99d3c85 feat: guarddog-nexus — webhook-based PyPI scanner with web UI 2026-05-09 04:48:10 +03:00
Marker689
bdcc82807d init: guarddog-nexus project skeleton 2026-05-09 04:32:48 +03:00