Skip to main content

Advisory database system

PatchBase maintains a curated collection of security advisories organized into per-distribution "scopes." This page explains the data model and sync pipeline.

Scope structure

A scope represents a set of advisories for a specific distribution channel. Examples:

Scope keyDistribution
ubuntu:jammyUbuntu 22.04
ubuntu:nobleUbuntu 24.04
ubuntu:resoluteUbuntu 26.04
debian:bookworm-dsaDebian 12
debian:trixie-dsaDebian 13
rocky:9Rocky Linux 9
rocky:10Rocky Linux 10
alma:9AlmaLinux 9
alma:10AlmaLinux 10

Each scope has its own SQLite database file hosted at dl.patchbase.net.

SQLite schema

Each scope database contains these tables:

advisories

ColumnDescription
idAdvisory identifier (e.g., RHSA-2024:1234, USN-6021-1)
source_systemSource (e.g., rocky, ubuntu)
raw_source_idOriginal ID from the upstream source
source_urlLink to the original advisory
vendorVendor name
advisory_typeType (e.g., security, bugfix)
severitySeverity rating (critical, important, moderate, low)
summaryShort description
descriptionFull description
published_atPublication timestamp
updated_atLast update timestamp
evidence_tierEvidence quality level
is_securityWhether this is a security advisory

product_streams

Represents a distribution channel (e.g., "Rocky Linux 10.2 BaseOS x86_64"). Each stream has a vendor, distribution family, major/minor version, architecture, repo family, and optional CPE.

advisory_product_streams

Many-to-many link between advisories and product streams.

advisory_references

External references (CVE IDs, vendor advisories, CVSS scores).

affected_package_rules

Conditions that determine if a package is vulnerable. Each rule specifies:

  • Package name
  • Source RPM (for RPM systems)
  • Architecture constraint
  • Version constraints (epoch, version, release)
  • RPM EVR comparison rules
  • Context (e.g., base, appstream)

fixed_packages

Specific package versions (NEVRA) that resolve the advisory.

Sync pipeline

1. Fetch manifest.json from base_url
2. Find scope detail in manifest
3. Compare SHA-256 checksum with local copy
├── Same hash + already imported → skip download, re-match hosts
└── Different hash or missing → continue
4. Download SQLite file to staging directory
5. Verify SHA-256 checksum
6. Atomically rename to final path
7. Open SQLite, verify advisories table exists
8. Begin Postgres transaction
9. Import records:
a. Product streams (upsert)
b. Clean up old streams for this scope
c. Advisories (upsert)
d. Advisory references (insert)
e. Advisory ↔ product stream links (insert)
f. Affected package rules (insert)
g. Fixed packages (insert)
10. Commit transaction
11. Re-match all hosts in this scope
12. Update scope status to "synced"
13. Clean up old SQLite file if hash changed

The import is transactional — if any step fails, the entire import is rolled back and the scope is marked as failed with the error message preserved.

Manifest format

The manifest is a JSON document listing all available scopes:

{
"schema_version": 1,
"generated_at": "2025-01-15T00:00:00Z",
"scopes": [
{
"key": "rocky:9",
"path": "rocky/9/advisories.db",
"url": "https://dl.patchbase.net/v1/advisory-db/rocky/9/advisories.db",
"sha256": "abc123...",
"size_bytes": 4567890,
"updated_at": "2025-01-14T18:00:00Z",
"advisory_count": 1247,
"license_feature": ""
}
]
}

The server fetches this manifest on every sync cycle to detect changes.