220 lines
7.1 KiB
Markdown
220 lines
7.1 KiB
Markdown
|
|
# CVExplorer
|
|||
|
|
|
|||
|
|
CVExplorer — утилита для анализа **запущенных Docker-контейнеров**:
|
|||
|
|
|
|||
|
|
- извлекает зависимости приложения (из контейнера **или** по ссылке на исходники)
|
|||
|
|
- сравнивает версии зависимостей с базой уязвимостей **OSV.dev**
|
|||
|
|
- cоздаёт отчет
|
|||
|
|
- отправляет отчёт по выбранным каналам (WIP)
|
|||
|
|
|
|||
|
|
> На текущем этапе анализ выполняется по **манифестам зависимостей**.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Возможности
|
|||
|
|
|
|||
|
|
- Сканирует **запущенные** контейнеры.
|
|||
|
|
- Два пути извлечения зависимостей:
|
|||
|
|
1. из контейнера (если манифесты присутствуют)
|
|||
|
|
2. из репозитория по `source_url` (если контейнер содержит только собранный бинарник)
|
|||
|
|
- Сравнивает найденные версии зависимостей с OSV.dev
|
|||
|
|
- Фильтрует вывод по минимальной серьёзности (например, скрыть `LOW`).
|
|||
|
|
- Есть файл конфигурации для гибкой настройки вывода
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Поддерживаемые манифесты
|
|||
|
|
|
|||
|
|
**Python:**
|
|||
|
|
- `requirements*.txt`
|
|||
|
|
- `Pipfile`
|
|||
|
|
- `pyproject.toml`
|
|||
|
|
- `poetry.lock`
|
|||
|
|
|
|||
|
|
**Node.js:**
|
|||
|
|
- `package.json`
|
|||
|
|
- `package-lock.json`
|
|||
|
|
- `yarn.lock`
|
|||
|
|
- `pnpm-lock.yaml`
|
|||
|
|
|
|||
|
|
**Go:**
|
|||
|
|
- `go.mod`
|
|||
|
|
- `go.sum`
|
|||
|
|
|
|||
|
|
**Rust:**
|
|||
|
|
- `Cargo.toml`
|
|||
|
|
- `Cargo.lock`
|
|||
|
|
|
|||
|
|
**Java:**
|
|||
|
|
- `pom.xml`
|
|||
|
|
- `build.gradle`, `build.gradle.kts`
|
|||
|
|
|
|||
|
|
**.NET:**
|
|||
|
|
- `*.csproj`, `*.fsproj`
|
|||
|
|
- `packages.config`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Требования
|
|||
|
|
|
|||
|
|
- Python 3.10+ (рекомендуется 3.11+)
|
|||
|
|
- Docker Engine / Docker Desktop запущен
|
|||
|
|
- `git` в системе (для анализа по `source_url`)
|
|||
|
|
|
|||
|
|
Python-зависимости:
|
|||
|
|
- `docker`
|
|||
|
|
- `tqdm` (опционально, для прогресс-бара)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Установка
|
|||
|
|
|
|||
|
|
### 1) Клонировать проект
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
git clone https://g.lair.moe/Chest/CVExplorer
|
|||
|
|
cd CVExplorer
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2) Создать виртуальное окружение
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python -m venv .venv
|
|||
|
|
source .venv/bin/activate
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3) Поставить зависимости
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pip install -U pip
|
|||
|
|
pip install docker
|
|||
|
|
pip install tqdm # опционально для прогресс-бара
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Запуск
|
|||
|
|
|
|||
|
|
Основной способ:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python run.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Альтернативно (если используешь пакетный запуск):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python -m cvexplorer.main
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> Утилита анализирует **запущенные** контейнеры. Убедись, что нужные сервисы запущены.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Как работает извлечение зависимостей?
|
|||
|
|
|
|||
|
|
Для каждого контейнера:
|
|||
|
|
|
|||
|
|
1. CVExplorer ищет файлы манифестов внутри контейнера (например, `package.json`, `go.mod`).
|
|||
|
|
2. Если манифестов нет, CVExplorer пытается взять `source_url` из OCI labels:
|
|||
|
|
- `org.opencontainers.image.source`
|
|||
|
|
- `org.opencontainers.image.url`
|
|||
|
|
- (и т.п.)
|
|||
|
|
3. Если `source_url` найден — репозиторий клонируется, выбирается commit (если есть `org.opencontainers.image.revision`) и парсятся манифесты в репо.
|
|||
|
|
4. Дальше зависимости дедуплицируются и отправляются в OSV.dev.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Конфигурация
|
|||
|
|
|
|||
|
|
CVExplorer читает конфиг из файла **`cvexplorer_config.json`** в рабочей директории.
|
|||
|
|
Если файла нет или он некорректный — используются значения по умолчанию.
|
|||
|
|
|
|||
|
|
### Пример `cvexplorer_config.json`
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"output": {
|
|||
|
|
"group_by_service": true,
|
|||
|
|
"sections": {
|
|||
|
|
"show_id_status": false,
|
|||
|
|
"show_ports": false,
|
|||
|
|
"show_language": false,
|
|||
|
|
"show_revision": false,
|
|||
|
|
"show_deps_list": false,
|
|||
|
|
"show_code_files": false,
|
|||
|
|
"show_errors": false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"vulns": {
|
|||
|
|
"min_severity": "MEDIUM",
|
|||
|
|
"include_unknown": true,
|
|||
|
|
"max_affected_deps_to_show": 8,
|
|||
|
|
"max_vuln_ids_to_show": 10
|
|||
|
|
},
|
|||
|
|
"osv": {
|
|||
|
|
"enabled": true,
|
|||
|
|
"chunk_size": 250,
|
|||
|
|
"hydrate_details": true,
|
|||
|
|
"max_pages": 5,
|
|||
|
|
"timeout_sec": 30
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Параметры `output`
|
|||
|
|
|
|||
|
|
- `group_by_service` — группировать контейнеры по сервису (Compose/имя/образ).
|
|||
|
|
- `sections.*` — включение/выключение блоков вывода:
|
|||
|
|
- `show_id_status` — ID/статус/created
|
|||
|
|
- `show_ports` — используемые порты
|
|||
|
|
- `show_language` — ЯП
|
|||
|
|
- `show_revision` — commit SHA
|
|||
|
|
- `show_deps_list` — печатать списки зависимостей (но их может быть ооооочень много)
|
|||
|
|
- `show_code_files` — найденные `main/app/index` файлы с кодом
|
|||
|
|
- `show_errors` — ошибки извлечения
|
|||
|
|
|
|||
|
|
### Параметры `vulns`
|
|||
|
|
|
|||
|
|
- `min_severity` — минимальная серьёзность для отображения: `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`.
|
|||
|
|
- `include_unknown` — показывать ли уязвимости с неизвестной серьёзностью.
|
|||
|
|
- `max_affected_deps_to_show` — сколько «самых проблемных» пакетов показывать.
|
|||
|
|
- `max_vuln_ids_to_show` — сколько ID уязвимостей выводить в примере.
|
|||
|
|
|
|||
|
|
### Параметры `osv`
|
|||
|
|
|
|||
|
|
- `enabled` — включить/выключить сравнение с OSV.dev.
|
|||
|
|
- `chunk_size` — размер batch-запроса (актуально при сотнях зависимостей).
|
|||
|
|
- `hydrate_details` — догружать ли детали уязвимостей (нужно для фильтрации по severity best-effort).
|
|||
|
|
- `max_pages` — ограничение пагинации.
|
|||
|
|
- `timeout_sec` — таймаут запросов.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Прогресс-бар
|
|||
|
|
|
|||
|
|
Если поставить `tqdm`, появится прогресс-бар для:
|
|||
|
|
- сканирования контейнеров
|
|||
|
|
- batch-запросов OSV
|
|||
|
|
|
|||
|
|
Установка:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pip install tqdm
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Troubleshooting
|
|||
|
|
|
|||
|
|
### Нет прав на Docker
|
|||
|
|
|
|||
|
|
Если ошибки про доступ к Docker socket — запусти от пользователя с доступом к Docker или настрой группу `docker`.
|
|||
|
|
|
|||
|
|
### В контейнере нет манифестов
|
|||
|
|
|
|||
|
|
Это нормально для «собранных» образов. Тогда нужен `source_url` в OCI labels.
|
|||
|
|
Если `source_url` отсутствует — CVExplorer сможет показать только метаданные контейнера.
|
|||
|
|
Ручное добавление ссылки на знакомые вам проекты через конфигурацию — **WIP**
|
|||
|
|
---
|