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.mdskills/infrastructure/cve-source-check/SKILL.md
GitHubCVE 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
- Locate
tech-source-registry.json(next to SKILL.md by default, or--registry). - Build inventory from
--inventory(JSON list or{components: [...]}) or--inline(comma-splitname@version). - If
--current-sourcesprovided, read URLs and normalize for case-insensitive comparison.
Gate: at least one component present. Empty inventory -> exit 3.
Phase 2: MAP & VERIFY
- Look up each component
name(and aliases) in the registry.- Found ->
mapped, attach source list. Missing ->unmapped, sources[].
- Found ->
- If current sources loaded, mark each source
monitored: truewhen its normalized URL appears. - 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
- Compute summary: components, mapped/unmapped, monitored, coverage %, gaps, unreachable.
- Write JSON report with per-component status and per-source
monitored/reachablefields. - Write Markdown report: summary table, components table (markers), gaps section (when gaps exist), unmapped section (when unmapped exist).
- 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. |