feat(vuln): OSV cache staleness + refresh flags — closes #30#44
Closed
Wolfvin wants to merge 5 commits into
Closed
feat(vuln): OSV cache staleness + refresh flags — closes #30#44Wolfvin wants to merge 5 commits into
Wolfvin wants to merge 5 commits into
Conversation
added 5 commits
June 28, 2026 07:59
Issue #30 — expose OSV cache freshness in vuln-scan JSON output. - OSVCache.peek(key): pure inspection returning (timestamp, ttl) without mutating the cache (unlike get(), which deletes expired entries). - OSVClient.get_cache_info(packages, max_age=None): returns {last_refresh, age_hours, ttl_hours, is_stale, stale_packages}. is_stale when any cached entry is past the effective TTL, the newest entry's age >= TTL, or there are OSV-queriable packages but none cached. - vulnscan_engine.scan_vulnerabilities: attach cache_info to the result dict (additive — no existing output fields changed). Static cache_info blocks are surfaced on the no-packages and OSV-failure paths so consumers can rely on the shape. Network calls unchanged: cache_info only inspects the local SQLite cache.
Issue #30 — 'codelens vuln-scan --refresh' bypasses the OSV cache and forces fresh OSV.dev API calls for every package, then updates the cache with the new results. - OSVClient.query_packages(packages, force_refresh=False): when True (and not offline), skip cache reads and route all packages to _batch_query_api, which already caches each response via cache.set. No-op in offline mode. - vulnscan_engine.scan_vulnerabilities(..., refresh=False): passes through as force_refresh to the OSV client. - vuln-scan CLI: new --refresh flag (store_true). Default behaviour unchanged: without --refresh the cache is consulted first and only uncached packages hit the API.
Issue #30 — 'codelens vuln-scan --max-age Nh' treats OSV cache entries older than N hours as stale for the current run only (overrides the default 24h TTL without changing the stored TTL). Useful for agents that want fresher data without a full --refresh. - OSVClient.query_packages(packages, force_refresh=False, max_age=None): cached entries whose age exceeds max_age are re-fetched from the API for this run. Uses OSVCache.peek() to read timestamps without mutating the cache. Ignored when force_refresh is set (cache bypassed entirely) or in offline mode. - OSVClient.get_cache_info(packages, max_age=None): ttl_hours and the staleness threshold now honour max_age so cache_info stays consistent with the run's effective TTL. - vulnscan_engine.scan_vulnerabilities(..., max_age=None): passes through to both query_packages and get_cache_info. - vuln-scan CLI: new --max-age flag + _parse_max_age() helper accepting '6h'/'30m'/'2d'/'90s'/bare-integer (hours). Invalid values return an error result instead of crashing.
Issue #30 — 36 new network-free tests in tests/test_vuln_staleness.py: - OSVClient.get_cache_info(): shape, empty-cache staleness, fresh entry, expired entry listing, --max-age override, peek non-mutation, last_refresh = most-recent among multiple packages. - OSVClient.query_packages(force_refresh=...): bypasses cache + calls API, default still hits cache, no-op in offline mode. - OSVClient.query_packages(max_age=...): treats fresh entries as stale, below-threshold uses cache, ignored when force_refresh is set. - _parse_max_age(): valid forms (6h/30m/90s/2d/bare/1.5h/whitespace/upper), None passthrough, invalid + zero/negative rejection. - vuln-scan execute(): forwards refresh + parsed max_age to scan_vulnerabilities, returns error result on invalid --max-age. - scan_vulnerabilities(): cache_info present with no deps, reflects seeded fresh cache, reports stale under --max-age, and existing output fields remain unchanged (additive). The OSV API layer is mocked throughout; the SQLite cache is seeded directly with backdated timestamps.
Issue #30 — document the new vuln-scan staleness flags and the cache_info output block. - README.md: expand the vuln-scan command row with --refresh / --max-age and the cache_info block. - SKILL-QUICK.md: add the flags + cache_info note to the Security command list. - CHANGELOG.md: new 'OSV Cache Staleness Flag + Refresh Flags (issue #30)' section under [8.2.0] with Added / Changed / Non-Breaking subsections.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Summary
Closes #30. Completes the last Phase 1 (#21) checklist item: "Fix vuln DB staleness (OSV.dev API, update scheduler)".
vuln-scannow reports OSV cache freshness and lets agents force fresh data. Previously the 24h OSV cache had no staleness indicator and no way to force a re-fetch short of deleting the cache — agents relying onvuln-scanfor security posture had no way to know whether the CVE results were minutes or 23 hours old.The background refresh scheduler (stretch goal #4 in the issue) is intentionally out of scope for Phase 1.
Deliverables (3 of 3)
1.
cache_infoinvuln-scanJSON output (additive)is_staleis true when any cached entry is past the effective TTL, the newest entry's age ≥ the effective TTL, or there are OSV-queriable packages but none are cached (no fresh coverage).stale_packageslists the"name@version"of cached entries past the effective TTL. A staticcache_infoblock is also surfaced on the no-packages and OSV-failure paths so consumers can rely on the shape.2.
vuln-scan --refreshBypasses the OSV cache and forces fresh OSV.dev API calls for every package, then updates the cache with the new results (the existing
_batch_query_apialreadycache.sets each response). No-op in--offlinemode.3.
vuln-scan --max-age NhTreats cache entries older than
Nhours as stale for this run only (overrides the default 24h TTL without changing the stored TTL). Accepts6h/30m/2d/90s/ bare-integer (hours).cache_info.ttl_hoursand the staleness threshold honour this override so they stay consistent. Ignored with--refreshand in--offlinemode. Invalid values return anerrorresult instead of crashing.Files
scripts/osv_client.pyOSVCache.peek(key)(pure inspection, no mutation). NewOSVClient.get_cache_info(packages, max_age=None).OSVClient.query_packages()gainsforce_refresh+max_age(default behaviour unchanged).scripts/vulnscan_engine.pyscan_vulnerabilities()gainsrefresh+max_ageparams; attachescache_infoto result.scripts/commands/vuln_scan.py--refresh+--max-ageflags +_parse_max_age()helper.tests/test_vuln_staleness.pyREADME.md,SKILL-QUICK.md,CHANGELOG.mdConstraints honoured
cache_infois additive — no existingvuln-scanoutput field changed.--refreshis set, cache expired, or--max-agemarks entries stale. Default behaviour unchanged.scan.pyorgraph_model.py(worker 4-b's domain onfeat/issue-25-incremental-graph).CodeLens-4a) so the shared checkout used by worker 4-b was undisturbed.Commits (incremental)
f942088feat(vuln): cache_info in output82b94edfeat(vuln): --refresh flagd18e830feat(vuln): --max-age flag81e93c4test(vuln): staleness testsdb3cac3docs(vuln): README + SKILL-QUICK + CHANGELOGTests
Baseline on
mainwas 649 passed / 12 skipped; the +36 are the new tests. No new failures, no regressions. (test_integration.pyis excluded per repo convention — it is OOM-heavy.)End-to-end CLI confirmation:
codelens vuln-scan <ws> --format jsonnow includes a top-levelcache_infoblock;--refreshand--max-age 6hparse and run; an invalid--max-age 6xreturns{status: error, error: invalid_argument, message: ...}instead of crashing.Acceptance criteria (from issue #30)
vuln-scanoutput includescache_infowithlast_refresh,age_hours,is_stale,stale_packages(alsottl_hours).--refreshforces fresh API calls and updates the cache.--max-ageoverrides TTL for the current run.--refreshbypasses cache,--max-agetreats fresh entries as stale.[8.2.0].