--- name: cve-source-check promoted_to: deploy 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 ] [--inline ] [--current-sources ] [--service ] [--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: - assessment --- # 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 ```bash # 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 ` | JSON: `[{name, version?, type?}, ...]` or `{components: [...]}`. | | `--inline "name@ver,..."` | Comma-separated list. Mutually exclusive with `--inventory`. | | `--current-sources ` | One URL per line. `#` comments and blank lines skipped. | | `--service ` | Name for report header and filenames. | | `--check-urls` | HEAD-check every source URL (5s timeout, graceful degradation). | | `--registry ` | Override default `tech-source-registry.json`. | | `--out-dir ` | 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: ```json { "$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. |