cve-source-check

Audit CVE/vulnerability source coverage for a technology stack. Maps each component (container, library, base image, runtime) to authoritative CVE feeds, flags gaps, and produces audit-ready reports.

SKILL.md

GitHub

CVE Source Check

Audit CVE/vulnerability source coverage for a technology stack. Maps components to authoritative CVE feeds via a versioned registry, flags gaps, and produces audit-ready reports (JSON + Markdown).

In scope: component-to-feed mapping, coverage/gap reporting, optional URL reachability checks. Out of scope: running scanners (Trivy/Snyk), fetching CVE content, private vuln databases.

Quick Start

# Inline, offline
python3 scripts/check-cve-sources.py \
  --inline "go@1.22,alpine@3.19,postgres@16,redis@7,nginx@1.25" \
  --service my-service

# Inventory + monitored feeds + link verification
python3 scripts/check-cve-sources.py \
  --inventory examples/inventory.example.json \
  --current-sources examples/current-sources.example.txt \
  --service my-service --check-urls

Inputs

Flag Purpose
--inventory <file> JSON: [{name, version?, type?}, ...] or {components: [...]}.
--inline "name@ver,..." Comma-separated list. Mutually exclusive with --inventory.
--current-sources <file> One URL per line. # comments and blank lines skipped.
--service <name> Name for report header and filenames.
--check-urls HEAD-check every source URL (5s timeout, graceful degradation).
--registry <path> Override default tech-source-registry.json.
--out-dir <path> Output directory (default: cwd).

JSON only. YAML not supported (no stdlib parser).

Outputs

Files: cve-source-report-{service}-{YYYYMMDD}.{md,json} in --out-dir.

Exit Meaning
0 Full coverage.
1 Gaps (unmapped components or unmonitored sources).
2 Unreachable source URL (only with --check-urls).
3 Input error (missing/malformed registry or inventory).

Workflow

Phase 1: LOAD

  1. Locate tech-source-registry.json (next to SKILL.md by default, or --registry).
  2. Build inventory from --inventory (JSON list or {components: [...]}) or --inline (comma-split name@version).
  3. If --current-sources provided, read URLs and normalize for case-insensitive comparison.

Gate: at least one component present. Empty inventory -> exit 3.

Phase 2: MAP & VERIFY

  1. Look up each component name (and aliases) in the registry.
    • Found -> mapped, attach source list. Missing -> unmapped, sources [].
  2. If current sources loaded, mark each source monitored: true when its normalized URL appears.
  3. If --check-urls: HEAD-check each unique URL. Treat 200/301/302/403/405 as reachable. 4xx (except 403/405) and 5xx -> reachable: false. Timeout/DNS/TLS failure -> reachable: null (WARN, does not affect exit code). 5s timeout per URL, cached per run.

Gate: every component has status; every source has monitored and reachable fields.

Phase 3: REPORT

  1. Compute summary: components, mapped/unmapped, monitored, coverage %, gaps, unreachable.
  2. Write JSON report with per-component status and per-source monitored/reachable fields.
  3. Write Markdown report: summary table, components table (markers), gaps section (when gaps exist), unmapped section (when unmapped exist).
  4. Print one-screen summary to stdout. Set exit code per table above.

Gate: both files written, summary printed.

Registry Schema

tech-source-registry.json shape:

{
  "$schema_version": "1.0",
  "kinds": ["advisory-list", "github-security", "mailing-list", "distro-tracker", "vendor-page", "mitre"],
  "priorities": ["primary", "secondary"],
  "technologies": [
    {"name": "postgres", "aliases": ["postgresql","pg"], "type": "container",
     "sources": [{"url": "https://...", "kind": "advisory-list", "priority": "primary"}]}
  ]
}

Each technology: name (lowercase, unique), aliases (list), type (runtime/base-image/container/library), sources (1-3, at least one primary).

To add a technology: pick canonical name, list aliases, add 1-3 sources (lead with vendor advisory page), re-run against a sample inventory.

Error Handling

Error Cause Fix
Failed to load registry Missing or malformed JSON Validate with python3 -m json.tool
Failed to load inventory Missing, malformed, or wrong shape Validate JSON; must be list or {components: [...]}
Inventory empty No usable components Each entry needs name. Inline needs non-empty tokens.
Coverage stuck at 0% --current-sources URLs don't match registry Copy URLs from registry. Scheme/host case and trailing slash are normalized; rest must match.
Many [--] entries with --check-urls Network issues Re-run without --check-urls. Network errors don't affect gap exit code.