Skip to content

ARCHITECTURE

Andrii Sheiko edited this page Jun 23, 2026 · 8 revisions

Architecture

Призначення

PyCVE у цьому репозиторії побудований як static delivery pipeline:

  1. rule-service будує JSON rulesets для конкретних release
  2. static HTTP server віддає ці файли
  3. local-agent визначає локальний дистрибутив і release
  4. local-agent завантажує потрібний ruleset і виконує локальний match

Артефакти

У каталозі rules лежать тільки ті release-файли, які були реально згенеровані вибраним source і списком --releases. Наприклад, каталог може містити:

  • focal.json
  • jammy.json
  • noble.json
  • bookworm.json
  • bullseye.json
  • trixie.json
  • cve-priority.json

Релізні файли відповідають за applicability. cve-priority.json відповідає за enrichment, сортування і display metadata.

Artifact Lifecycle

Під час звичайного build-а в каталозі rules з’являються:

  • один JSON ruleset на кожен release із --releases
  • optional cve-priority.json, якщо builder запускався з --write-priority або --priority-only

Під час довгого --canonical-cves fetch можуть тимчасово з’являтися:

  • canonical-feed.checkpoint.json
  • canonical-feed.checkpoint.json.records.jsonl

Семантика цих файлів:

  • canonical-feed.checkpoint.json Маленький status/meta checkpoint для resume.
  • canonical-feed.checkpoint.json.records.jsonl Append-only spool уже витягнутих Canonical CVE records.

Поведінка:

  • після кожної успішно прочитаної сторінки checkpoint оновлюється
  • records.jsonl дозаписується, а не переписується цілком
  • при повторному запуску builder продовжує з останнього next_offset
  • після успішного завершення checkpoint і spool видаляються

Якщо builder був зупинений або мережа впала:

  • наявність цих двох файлів означає, що resume ще можливий
  • їх не треба видаляти вручну, якщо ти хочеш продовжити незавершений прохід

Rule Model

Builder генерує один уніфікований ruleset format.

Top-level shape:

{
  "version": "2026-05-13T19:24:59Z",
  "generated_at": "2026-05-13T19:24:59Z",
  "ttl": 3600,
  "rules": []
}

Shape одного rule:

{
  "id": "CVE-2026-41205",
  "platform": "ubuntu",
  "release": "jammy",
  "check_type": "package_version",
  "operator": "lt",
  "value": "1.1.3+ds1-2ubuntu0.2",
  "code": 12345,
  "message": "Host package mako is vulnerable to CVE-2026-41205",
  "package_name": "mako",
  "severity": "medium",
  "references": [
    "https://www.cve.org/CVERecord?id=CVE-2026-41205"
  ],
  "source": "canonical-ubuntu-cves",
  "match_mode": "version",
  "rule_status": "fixed",
  "fixed_version": "1.1.3+ds1-2ubuntu0.2",
  "updated_at": "2026-05-13T19:24:59Z"
}

Основні типи:

  • package_version
  • kernel_version
  • kernel_package_version

Основні режими match:

  • match_mode = "version" Це precise rules з comparator-based перевіркою.
  • match_mode = "advisory" Це unresolved/unfixed CVE без published fixed version.

Для advisory rules:

  • operator і value можуть бути відсутні
  • fixed_version зазвичай null

Match Semantics

match_mode rule_status Meaning
version fixed Є published fixed version; агент робить точну version-based перевірку.
advisory vulnerable Vendor still marks release/package/kernel track vulnerable; точного fixed cutoff ще немає.
advisory pending Fix line already tracked, але published fixed version ще не вважається доступною для normal precise matching.

Практично:

  • match_mode = "version" дає precise applicability verdict
  • match_mode = "advisory" дає advisory/unfixed signal
  • advisory matches показуються за замовчуванням
  • --fixed-only відсікає advisory matches

Priority Model

Пріоритезація не визначає applicability. Вона працює поверх уже applicable findings.

Shape cve-priority.json:

{
  "version": "2026-05-09T12:00:00Z",
  "generated_at": "2026-05-09T12:00:00Z",
  "ttl": 86400,
  "cves": {
    "CVE-2026-31431": {
      "priority": "critical",
      "is_kev": true,
      "kev_date_added": "2026-05-02",
      "epss_score": 0.9731,
      "epss_percentile": 0.9992,
      "published_at": "2026-04-29T00:00:00Z",
      "updated_at": "2026-05-02T10:00:00Z",
      "severity": "high",
      "tags": [
        "known_exploited",
        "high_epss"
      ]
    }
  }
}

Pipeline:

  1. з release rulesets витягуються CVE IDs
  2. формується cve-priority.json
  3. optional enrichment додає:
    • KEV
    • EPSS
    • severity-derived priority
  4. optional manual overrides додають:
    • title
    • is_manual
    • найвищий display priority

Manual overrides можуть задаватися окремим JSON-файлом у простому вигляді:

{
  "CVE-2026-31431": "copy.fail",
  "CVE-2026-43284": {
    "title": "dirtyfrag"
  }
}

Такі записи:

  • отримують найвищий display priority
  • позначаються як is_manual = true
  • додають title, який агент показує як CVE-... (title)

Priority policy:

  • manual override має найвищий display priority
  • is_kev = true -> priority = critical
  • дуже високий EPSS -> priority = high
  • severity = high|critical без сильніших сигналів -> зазвичай priority = medium
  • severity = medium або recent-only signal -> priority = medium
  • severity = low|negligible|unimportant -> priority = low
  • якщо сильного сигналу немає, можливий priority = unknown

Агент:

  1. матчить ruleset
  2. знаходить applicable CVE
  3. optional підтягує cve-priority.json
  4. сортує findings
  5. показує priority annotation і manual title

Failure Modes

Очікувана поведінка при типових проблемах:

  • якщо cve-priority.json відсутній: агент продовжує працювати без priority enrichment
  • якщо KEV або EPSS тимчасово недоступні: builder продовжує формування cve-priority.json без відповідного enrichment
  • якщо Canonical feed відповідає повільно або timeout-иться: builder для --canonical-cves не завершується одразу, а retry-ить і може продовжити через checkpoint
  • якщо Canonical fetch був перерваний: наступний запуск може продовжити з checkpoint
  • якщо ruleset не вдається завантажити агентом: агент пробує використати локальний cache
  • якщо cache протух і не дозволено allow_expired_cache: агент повертає ERROR
  • якщо dpkg-query недоступний: package/kernel-package checks не працюватимуть коректно, агент завершиться з ERROR

Best-effort поведінка:

  • enrichment layer може бути неповним
  • applicability layer повинен залишатися джерелом істини
  • мережеві проблеми не повинні змінювати саму семантику rules

Rules Directory Contract

У каталозі rules дозволено тримати поруч:

  • release rulesets
  • cve-priority.json
  • manual priority JSON

Для --priority-only це безпечно, тому що builder сканує тільки JSON-файли з полем rules. Через це:

  • cve-priority.json не буде помилково використаний як release ruleset
  • типовий manual-priority-file теж не буде прийнятий за ruleset
  • у збір CVE для priority payload потрапляють тільки реальні applicability rules

What Not To Expect

  • cve-priority.json не додає CVE у findings без applicability match
  • manual title не означає, що CVE автоматично з’явиться у виводі
  • priority = critical не означає, що CVE застосовна до поточного хоста
  • --priority-only не перебудовує release rules і не оновлює source feeds
  • --ubuntu-oval завжди завантажує повний файл на кожен release
  • advisory rules не дають такої ж version precision, як match_mode = "version"

Scope Limits

PyCVE не є:

  • exploit detector
  • runtime EDR
  • process scanner
  • container/image scanner
  • config auditor

PyCVE працює як applicability engine поверх:

  • kernel version
  • kernel package version
  • installed package versions
  • vendor security metadata

Тобто він відповідає на питання:

  • чи стосується CVE цього хоста за наявними package/kernel даними
  • чи є precise fixed cutoff або тільки advisory signal
  • наскільки finding пріоритетний для відображення

Але він не відповідає на питання:

  • чи CVE уже експлуатується саме на цьому хості
  • чи конкретний сервіс реально reachable/exposed
  • чи workaround/mitigation already applied поза package metadata

Supported Sources

Для rule-service:

  • --canonical-cves Основний Ubuntu source. Paginated JSON API, ~70k CVE records для всіх releases в одному feed. Підтримує resume через checkpoint при перерваному fetch.
  • --ubuntu-oval Альтернативний Ubuntu source на основі Canonical OVAL XML feed. Завантажує окремий файл на кожен release (plain XML або .bz2). Дані еквівалентні --canonical-cves за якістю і актуальністю. Кожен запуск завантажує повний файл.
  • --debian-cves Debian source.

Hosting Model

PyCVE не прив’язаний до конкретного web stack. Потрібен лише static hosting каталогу з JSON-файлами.

Приклад мінімального nginx-конфіга:

server {
    listen 8080;
    server_name _;

    root /usr/share/nginx/html;

    location = /health {
        default_type application/json;
        return 200 '{"status":"ok"}';
    }

    location /rules/ {
        try_files $uri =404;
    }

    location = / {
        default_type text/plain;
        return 200 'pycve static rules';
    }
}

Clone this wiki locally