Repository navigation
feat(verdict): keep the verdict per product, and judge over HTTP too - #59
maksimtech wants to merge 2 commits into
Conversation
PR-01a judged each CVE against the installed version in memory; the next
`status`, /api/cves and the web UI went back to CVEs by name, and a scan
over HTTP did not judge at all, so the two scans disagreed.
- cve_software gains verdict, verdict_reason, verdict_fixed_version and
judged_version, migrated into existing databases: per product, since
one CVE can affect one watched product and not another. The latest
scan decides it.
- get_cves shows a verdict only while the installed version is still the
one it was given for: a stale "affected" sends someone to patch what
is patched, a stale "not affected" is worse.
- affected.mark is the one place both scans judge.
- The API takes version and cpe on POST /api/watchlist/{name} with the
CLI's checks, lists entries on GET /api/watchlist, and returns the
split per product from POST /api/scan. `status` gets a Verdict column.
Tests first, seen failing; 15 of 15 mutants killed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merging this PR will degrade performance by 14.06%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ |
test_api_cves_filtered |
49.7 ms | 59.2 ms | -16.09% |
| ❌ |
test_api_cves |
33.6 ms | 39.2 ms | -14.13% |
| ❌ |
test_get_cves_by_software |
10.7 ms | 12.3 ms | -13.07% |
| ❌ |
test_get_cves |
11.4 ms | 13.1 ms | -12.9% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing feat/the-verdict-is-kept-per-product (284d5de) with main (2e2fdc8)
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…e watchlist CodSpeed on #59: /api/watchlist 24% slower, get_cves and the /api/cves listings 14-17%. - /api/watchlist read the names and the entries in two queries; the names now come from the entries. - get_cves picked the current verdict with a CASE per column; the version check is now part of the join, so a stale link simply does not match. Measured locally on the benchmark's 500 seeded CVEs: 1.68 ms -> 1.61 ms (main 1.45 ms). The rest is the join and four more fields per row, which is what reading the verdict costs: the same query with NULL columns was already 1.57 ms. The full listing's stale-verdict case had no test of its own: added, and it kills the mutant that drops the version check from that join. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| async with db.execute(f""" | ||
| SELECT cves.*, {_CURRENT_VERDICT} FROM cves |
| async with db.execute(f""" | ||
| SELECT cves.*, {_CURRENT_VERDICT} FROM cves |
|
|
Folded into #64, which now targets main with every commit of the stack: one review, one merge, no conflicts from squash merges. |



Audit finding PR-01, step 01b-1 (docs/DESIGN.md §5.5, §5.6). It follows #58.
What was wrong after #58
patchradar status,/api/cvesand the web UI went back to CVEs by name.POST /api/scandid not judge, so the CLI and the API gave two different answers for the same machine. That is the failuretest_collector_wiring.pyexists to prevent.What changes
cve_softwaregainsverdict,verdict_reason,verdict_fixed_versionandjudged_version, migrated in place.get_cvesshows the verdict only whilejudged_versionis still the installed version. Afteradd --version 8.9.6.4, a verdict about 8.5.0 is not shown until a scan judges the new version.affected.mark: the one place both scans judge.POST /api/watchlist/{name}?version=&cpe=runs the CLI's checks and answers 422 with NVD's form of the CPE;GET /api/watchlistaddsentries;POST /api/scanreturnsverdictsper judged product;/api/cvesrows carry the four fields, sanitised.statusgets a Verdict column when any row has a current verdict.test_priority_wiringboundary), and KEV or MSRC entries judged through NVD's record of the same CVE.Tests (strict TDD)
test_verdict_stored.py: migration from a hand-written 2026.44cve_software, round trip, stale version hidden, one verdict per product, the latest scan wins,status.test_api_versioned.py: add, 422s, update, entries, scan split{affected: 10, not evaluable: 0, not affected: 11}, rows read back, entry without a version. NVD replayed from the recording; Debian 503 is listed inerrors.Note:
feat/the-verdict-is-kepton the remote is the same commit before the rebase. The force-push was refused, so it went to this new branch; the old one can be deleted.🤖 Generated with Claude Code