CI / Check (pull_request) Successful in 5m20s
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped
OSV-by-purl can't match `pkg:codesys/*` (OSV has no codesys ecosystem), so the CODESYS control-app SBOM produced zero CVE alerts even when the runtime was affected — "No CVE alerts" read as safe when it just meant "not checked" (found live during the demo). Add CveScanner::scan_codesys: find the CODESYS **runtime** component (the version advisories key off), pull `cpe:2.3:a:codesys:*` CVEs from NVD, and keep the ones whose affected-version range (versionStart/End Including/Excluding, or an exact CPE version) covers the runtime version. Wired into persist_control_app_sbom alongside the OSV scan (best-effort, timeout-bounded). Pure logic unit-tested (runtime detection, dotted-version compare, CPE range matching, NVD-config parsing against a fixture): a 4.17.0.0 runtime matches a `<=4.20` CVE but not an old `<4.9` one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>