Repository navigation
Agent Reference
Повний довідник CLI-агента local-agent (репозиторій pycve-agent): способи запуску, всі ключі, режими, формати виводу з усіма варіантами, поведінка кешу й сортування. Для першого знайомства почніть із Getting Started, для типових продакшн-сценаріїв — з Operations.
Самодостатній бінарник — без Python на хості (CLI ідентичний local-agent, додатково відповідає на --version версією збірки):
./pycve-agent-linux-x86_64 --rules-base-url https://host/rulesБінарники збираються Nuitka в Docker — див. packaging/nuitka/README.md у репозиторії агента. Стандартний варіант потребує glibc ≥ 2.34 (Ubuntu 22.04+, Debian 12+); для старих систем — зокрема focal і bullseye — є legacy-варіант із вимогою glibc ≥ 2.14. На Ubuntu/Debian обом варіантам, як і Python-обгортці, потрібен dpkg ≥ 1.16.2 (див. Operations).
Portable-обгортка — без venv і встановлення (потрібен лише Python 3.8+):
./run-local-agent.sh --rules-base-url https://host/rules
/opt/pycve-agent/run-local-agent.sh --rules-base-url https://host/rulesПрямий запуск із checkout-а:
PYTHONPATH=src python3 -m local_agent.cli --rules-base-url https://host/rulesВстановлений пакет (entrypoint local-agent):
local-agent --rules-base-url https://host/rules- Агент визначає
platformіreleaseз/etc/os-release, версію ядра — черезuname; на Ubuntu додатково трек і повну версію збірки ядра, на Debian — версію збірки зuname -v(див. Rule Format). Для RHEL-сімейства використовується majorVERSION_ID(10.2→10). - Завантажує рулсет
<rules-base-url>/<release>.jsonдля Ubuntu/Debian або<rules-base-url>/<platform><release>.jsonдля RPM-платформ і кешує його у--cache-path. - Якщо доступний
<rules-base-url>/cve-priority.json, кешує і його — в окремий файл із суфіксом.priority. - Матчить правила по локальному ядру та пакетах (
dpkg-query/Debian ordering абоrpm/RPM EVR ordering). На Ubuntu/Debian правила прив'язані до source-пакетів, тому агент зіставляє їх зі встановленими binary-пакетами через${source:Package}і порівнює source-версію (див. Rule Format). Пакети, які dpkg знає, але файлів яких на диску немає (станrcпісляapt removeбез purge,pn), не враховуються — за другою літерою${db:Status-Abbrev}. Якщо встановлено кілька версій, а вразлива лише старіша, агент перевіряє, чи це залишок (див. Rule Format). Для цього потрібен root: без нього такий збіг лишається звичайною знахідкою. - Шукає процеси, які після оновлення досі виконують видалений код (див. нижче).
- Друкує підсумок у stdout і завершується з відповідним exit code. Логи йдуть у stderr, тому
2>/dev/nullлишає тільки результат.
Priority-файл використовується виключно для сортування та анотацій у виводі — applicability визначається лише рулсетом (див. Priority).
| Ключ | Дефолт | Опис |
|---|---|---|
--rules-base-url |
http://127.0.0.1:8080 |
Базовий URL каталогу зі static JSON-рулсетами. |
--cache-path |
/tmp/local-agent-ruleset.json |
Файл кешу рулсету; priority кешується поруч із суфіксом .priority. |
--timeout-seconds |
5.0 |
Таймаут HTTP-запиту до static host. |
--allow-expired-cache |
false |
Дозволити протермінований кеш, якщо свіжий fetch не вдався. |
--os-release-path |
/etc/os-release |
Звідки визначати platform і release. |
--platform |
авто | Ручний override для platform. |
--release |
авто | Ручний override для release codename. |
--kernel-version |
авто (uname) |
Ручний override версії ядра. |
--kernel-only |
false |
Лишити тільки kernel-клас збігів (kernel_version, kernel_package_version). |
--packages-only |
false |
Лишити тільки package-клас збігів (package_version). |
--fixed-only |
false |
Лишити тільки precise-збіги з published fixed version. |
--cve-limit |
5 |
Максимум CVE-збігів у stdout; додатне ціле. |
--show-all-cves |
false |
Вивести всі знайдені CVE; має пріоритет над --cve-limit. |
--log-level |
INFO або $LOG_LEVEL
|
Рівень логування. |
Лишає тільки kernel_version і kernel_package_version matches:
- kernel-проблема →
VULNERABLE ... kernel ...(exit code залежить від priority, див. нижче); - якщо є лише package-проблеми →
OK; - package-CVE в цьому режимі ігноруються;
- процеси зі старим кодом не перевіряються.
Лишає тільки package_version matches:
- package-проблема →
VULNERABLE ... package ...(exit code залежить від priority, див. нижче); - якщо є лише kernel-проблеми і немає процесів зі старим кодом →
OK; - kernel-CVE в цьому режимі ігноруються.
За замовчуванням агент показує і precise version-based, і advisory-збіги. --fixed-only відсікає advisory:
- CVE з
match_mode = versionзалишаються; - CVE з
match_mode = advisoryприбираються з результатів; - комбінується з
--kernel-onlyабо--packages-only; - процеси зі старим кодом лишаються, бо оновлення вже встановлено.
Порівняння версій бачить пакет на диску, а не код у пам'яті. Якщо пакет оновлено, але служба не перезапущена, вона далі виконує стару вразливу версію. Агент вважає це відкритою вразливістю: такий хост не може бути OK, доки процес не перезапустять.
Як це визначається:
- агент читає
/proc/*/mapsі шукає видалені файли з виконуваними відображеннями (xу правах); - враховуються лише системні шляхи:
/lib*,/usr/lib*,/usr/libexec,/bin,/sbin,/usr/bin,/usr/sbin. Так відсіюютьсяmemfd,/dev/zero, сегменти/SYSV…, дані на кшталтlocale-archiveі програми поза системними каталогами; - перевірка працює лише для локального хоста. З
--platform,--releaseабо--kernel-versionвона не виконується, бо такі запуски описують інший хост.
Обмеження:
- Агент не може назвати CVE такого процесу, бо стара версія пакета вже невідома. Тому код виходу тут базовий,
2. - Без root процеси інших користувачів не видно. Агент друкує попередження
WARNING: restart check incomplete, run as root, а код виходу через це не змінюється. - Назва процесу береться з
/proc/<pid>/comm, тому обрізається до 15 символів (systemd-timesyn).
Exit code відображає найвищий priority серед знайдених збігів, а не тип перевірки (kernel/package — це видно тільки з тексту повідомлення). Priority береться з cve-priority.json (поле priority у записі CVE); is_kev і ручний override (is_manual) на сервері вже підіймають priority до critical, тож окремо їх на боці агента не треба враховувати.
| Код | Статус | Значення |
|---|---|---|
0 |
OK |
жодне правило не заматчилось і немає процесів зі старим кодом |
1 |
ERROR |
перевірку виконати не вдалося |
2 |
VULNERABLE |
є збіг з priority low/medium/unknown (або priority payload недоступний), або є процеси зі старим кодом |
3 |
VULNERABLE_HIGH |
є збіг з priority high
|
4 |
VULNERABLE_CRITICAL |
є збіг з priority critical (включно з KEV і ручним override) |
Якщо збігів декілька — береться найвищий priority серед них (той самий збіг, що йде першим у виводі після сортування).
Збіги з [leftover] у цьому виборі не беруть участі. Якщо знайдено лише такі збіги, exit code дорівнює 2 незалежно від їхнього priority.
Процеси зі старим кодом дають щонайменше 2. Якщо CVE дають вищий код, лишається вищий.
Формат однаковий для всіх платформ: одна CVE — один рядок. Нижче — всі варіанти stdout, які може дати поточна версія агента. Це корисно, якщо ви парсите вивід зовнішнім тулінгом.
OK: no matching CVE rules found
ERROR: <message>
Цей блок завжди друкується першим, а --cve-limit його не обрізає:
VULNERABLE: <count> processes still run old code after a package update, restart required
- <process> (pid <pid>): <file>, <file>
Для одного процесу перший рядок має вигляд VULNERABLE: 1 process still runs old code after a package update, restart required. Якщо є й CVE, далі йде їхній звичайний вивід зі своїм рядком VULNERABLE:.
Без root наприкінці виводу додається рядок:
WARNING: restart check incomplete, run as root
<CVE> (<title>) on <platform> <release>: <частина>; <частина> [priority: <priority>, known exploited]
-
(<title>)є лише в CVE з ручним title. - Частин стільки, скільки різних пакетів чи ядер зачіпає CVE. Частини ядра йдуть першими, а частини з
[leftover]останніми. -
[priority: ...]один на рядок. Його немає, якщо priority-файл недоступний або в ньому немає цієї CVE.known exploitedдодається, якщоis_kev = true.
Точні збіги:
package <package_name> <package_version>
package <package_name> (binaries: <binary>, <binary>) <package_version>
package <package_name>, <package_name> <package_version>
package <package_name> <package_version> [leftover]
kernel package <kernel_package_version> for kernel <kernel_version>
kernel <kernel_version>
kernel <kernel_version> (build <build_version>)
Збіги без опублікованого виправлення (advisory):
advisory package <package_name> <package_version> (<status>, no fixed version)
advisory package <package_name> (binaries: <binary>, <binary>) <package_version> (<status>, no fixed version)
advisory kernel package <kernel_package_version> (<package_name> <status>, no fixed version)
advisory kernel <kernel_version> (track <package_name> <status>, no fixed version)
Як читати ці варіанти:
-
(binaries: ...)друкується, якщо source-пакет із правила встановлений під іншими binary-іменами. Це саме ті пакети, які треба оновити:package glibc (binaries: libc-bin, libc6, locales) 2.35-0ubuntu3.15. - Кілька імен через кому означають пакети без source-пакета (наприклад, RPM) в однаковому стані й однієї версії:
package kernel-tools, kernel-tools-libs 0:6.12.0-211.7.3.el10_2. Пакети з(binaries: ...)не об'єднуються. -
[leftover]означає, що вразлива лише старіша встановлена версія і її ніхто не використовує (умови). Уbinariesтакої частини входять лише пакети цієї версії. -
(build <build_version>)друкується на Ubuntu, якщо порівнювалась повна версія збірки.
Якщо знайдено рівно одне правило, друкується один рядок:
VULNERABLE: CVE-2026-31431 on ubuntu focal: kernel 5.4.0-92 [priority: critical, known exploited]
VULNERABLE: <unique CVE count> unique CVEs found from <matching rule count> matching CVE rules
- <рядок першої CVE>
- <рядок другої CVE>
- <до поточного ліміту>
...
Приклад рядка CVE з кількома частинами:
- CVE-2026-43284 (dirtyfrag) on almalinux 10: kernel package 0:6.12.0-211.7.3.el10_2 for kernel 6.12.0-211.7.3.el10_2.x86_64; package kernel-tools, kernel-tools-libs 0:6.12.0-211.7.3.el10_2 [priority: critical]
- Типово показується максимум 5 CVE;
--cve-limitзмінює ліміт,--show-all-cvesзнімає його і прибирає.... Ліміт рахує рядки CVE, а не правила. - Якщо CVE більше за поточний ліміт, у кінці списку додається
.... - Дублікати прибираються:
unique CVEsрахує унікальні CVE ID,matching CVE rules— rule hits після дедуплікації однакових частин у межах CVE. - Без enrichment kernel-збіги пріоритизуються над package-збігами.
- З enrichment збіги спочатку сортуються за
priority, а вже потім kernel вище package. - CVE з
is_manual = trueсортуються вище за звичайнийcritical. - CVE, у яких усі частини мають
[leftover], завжди йдуть після решти, незалежно від priority. Якщо в CVE є й інші частини, рядок сортується за ними.
Останній успішно завантажений рулсет зберігається у --cache-path. Якщо свіжий fetch не вдався:
- поки кеш молодший за
ttlрулсету — агент використовує кеш; - якщо кеш протух і
--allow-expired-cacheне задано — агент повертаєERROR(exit code1): «не зміг перевірити» свідомо не маскується підOK.
Перевірка fallback-у вручну: один раз успішно запустіть агента, зробіть static URL недоступним і запустіть повторно з тим самим --cache-path — поки кеш свіжий, агент використає його.
Override-и platform/release/kernel дозволяють перевірити зв'язку builder → hosting → agent з будь-якої машини:
local-agent --rules-base-url https://host/rules \
--platform ubuntu --release focal --kernel-version 5.4.0-92Очікування: VULNERABLE: CVE-2026-31431 on ubuntu focal: kernel 5.4.0-92, exit code 2 (або вищий, якщо для цього CVE в cve-priority.json заданий high/critical).
Негативний кейс:
local-agent --rules-base-url https://host/rules \
--platform ubuntu --release focal --kernel-version 5.4.0-101Очікування: OK: no matching CVE rules found, exit code 0.
python3 -m unittest discover -s tests -p 'test_*.py'
# або: uv run python3 -m unittest discover -s tests -p 'test_*.py'- Агент очікує per-release static JSON-файли;
--rules-base-urlвказує на каталог, а не на окремий файл. RPM-платформи додають platform prefix до числового release (almalinux10.json). - У контейнері
kernel_version-перевірка фактично стосується ядра хоста. - Debian kernel-правила порівнюють версію пакета, з якого зібране запущене ядро (
uname -v), а за її відсутності — версію встановленогоlinux-image-*;uname -rіз tracker version напряму не порівнюється. - AlmaLinux kernel-правила порівнюють RPM EVR пакета, якому належить каталог модулів запущеного ядра.
- Зворотної телеметрії/звітування на сервер немає.
- Сторонні репозиторії не покриваються. Правила описують лише пакети дистрибутива. Деталі — в Data Sources.