| name | cve-source-check |
| promoted_to | service-health-check |
| description | 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. Generic: works for any service or stack. |
| user-invocable | false |
| argument-hint | [--inventory <file>] [--inline <tech-list>] [--current-sources <file>] [--service <name>] [--check-urls] |
| allowed-tools | ["Bash","Read","Write","Edit","Glob","Grep"] |
| routing | {"triggers":["check cve sources","cve source coverage","audit cve feeds","vulnerability source audit","verify cve sources","security feed audit"],"category":"infrastructure","complexity":"Simple","pairs_with":["service-health-check"]} |
CVE Source Check
Audits CVE/vulnerability source coverage for a technology stack. Given an inventory
of components and (optionally) the feeds you currently monitor, it maps each
component to authoritative CVE sources, flags gaps, and emits audit-ready reports.
Scope
| In scope | Out of scope |
|---|
| Mapping components → authoritative feeds via a versioned registry | Running vulnerability scanners (Trivy/Snyk/etc.) |
| Reporting coverage and gaps in JSON + Markdown | Fetching CVE content or ranking by severity |
| Optional HEAD-check for source URL reachability | Integrating with private/commercial vuln databases |
| Audit-ready output (deterministic, reproducible) | Live LLM research per run |
Inputs
| Flag | Purpose |
|---|
--inventory <file> | JSON inventory: [{name, version?, type?}, ...] or {components: [...]}. |
--inline "name@ver,name,..." | Quick comma-separated list. Mutually exclusive with --inventory. |
--current-sources <file> | Optional. One URL per line. Blank lines and # comments skipped. |
--service <name> | Free-form name used in 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 inventory format only. YAML is not supported — stdlib does not ship a YAML parser.
Outputs
| File | Format |
|---|
cve-source-report-{service}-{YYYYMMDD}.md | Human-readable audit report. |
cve-source-report-{service}-{YYYYMMDD}.json | Machine-readable per references/output-formats.md. |
| Exit code | Meaning |
|---|
| 0 | Full coverage. |
| 1 | Gaps exist (unmapped components or unmonitored sources). |
| 2 | At least one source URL is unreachable (only with --check-urls). |
| 3 | Input error (missing/malformed registry or inventory). |
Workflow
Phase 1: LOAD
- Locate the registry:
tech-source-registry.json next to this SKILL.md by default.
- Build an inventory:
- From
--inventory: parse JSON; accept either a list or {components: [...]}.
- From
--inline: split on commas, parse name@version pairs.
- If
--current-sources is provided, read URLs (one per line); normalize for
case-insensitive comparison.
Gate: at least one inventory component is present. Empty inventory → exit 3.
Phase 2: MAP & VERIFY
- For each component, look up
name (and aliases) in the registry.
- Found → status
mapped, attach the registry's source list.
- Missing → status
unmapped, sources [].
- If current sources were loaded, mark each source
monitored: true when its
normalized URL appears in the set.
- If
--check-urls is set, HEAD-check every unique source URL. Treat
200/301/302/403/405 as reachable; record definite failures and network errors
distinctly. See references/source-verification.md.
Gate: every component has a status; every source has monitored and
reachable fields populated (reachable: null when checks are skipped).
Phase 3: REPORT
- Compute the summary: components, mapped/unmapped, monitored, coverage %,
gaps, unreachable.
- Write the JSON report.
- Write the Markdown report:
- Summary table.
- Components table with ✅ / ⚠️ / ❌ markers.
- Gaps section listing primary then secondary sources to add (only when
gaps exist).
- Unmapped section listing registry-extension TODOs (only when unmapped
components exist).
- Print a one-screen summary to stdout including report paths.
- Set the exit code per the table above.
Gate: both files exist on disk and the summary printed; exit code reflects
the audit result.
Quick start
python3 scripts/check-cve-sources.py \
--inline "go@1.22,alpine@3.19,postgres@16,redis@7,nginx@1.25" \
--service my-service
python3 scripts/check-cve-sources.py \
--inventory examples/inventory.example.json \
--current-sources examples/current-sources.example.txt \
--service my-service
python3 scripts/check-cve-sources.py \
--inventory examples/inventory.example.json \
--current-sources examples/current-sources.example.txt \
--service my-service \
--check-urls
Extending the registry
To add a technology, edit tech-source-registry.json. Each entry needs name,
aliases, type, and 1–3 sources. Schema lives at
references/registry-schema.md.
Reference Loading Table
| Signal | Load These Files | Why |
|---|
| adding a technology to the registry | registry-schema.md | Defines registry shape and allowed values. |
| checking source URLs | source-verification.md | Defines HEAD-check semantics and graceful degradation. |
| generating audit reports | output-formats.md | Defines JSON and Markdown report contracts. |
Error handling
"ERROR: failed to load registry"
Cause: registry file missing or malformed JSON.
Solution: confirm tech-source-registry.json is at --registry (or default
location) and parses with python3 -m json.tool.
"ERROR: failed to load inventory"
Cause: inventory file missing, malformed JSON, or unexpected shape.
Solution: validate with python3 -m json.tool. Inventory must be a list or an
object with a components key.
"ERROR: inventory is empty"
Cause: no usable components after parsing.
Solution: confirm each entry has a name. Inline form requires non-empty tokens.
Coverage stuck at 0%
Cause: --current-sources URLs do not match registry URLs exactly (e.g., extra
path segments, trailing slashes).
Solution: copy URLs directly from the registry. The script normalizes scheme/host
case and trailing slash; everything else must match.
--check-urls flags many [—] entries
Cause: network issues (proxy, DNS, offline) — recorded as reachable: null.
Solution: re-run without --check-urls for the audit; investigate network
separately. Network errors do not affect the gap exit code.