Skip to content

feat(scan): run a full threat-intel refresh before a manual scan#211

Merged
yasirhamza merged 1 commit into
mainfrom
feat/scan-triggers-full-update
May 29, 2026
Merged

feat(scan): run a full threat-intel refresh before a manual scan#211
yasirhamza merged 1 commit into
mainfrom
feat/scan-triggers-full-update

Conversation

@yasirhamza
Copy link
Copy Markdown
Owner

Summary

A manual scan now freshens all threat intel before scanning, fixing two latent bugs in the existing pre-scan update:

  1. It only called indicatorUpdater.update() — missing the curated public-repo IOCs, SIGMA rules, and CVEs.
  2. Its 24h staleness gate effectively never fired (the background worker refreshes every 12h), so manual scans ran on stale intel.

Changes

  • Shared IntelRefresher (@Singleton): the periodic IocUpdateWorker and the pre-scan path now run identical refresh logic — no drift. Pruning stays worker-only.
  • Throttle fix: runScan() now refreshes if intel is older than PRE_SCAN_REFRESH_THROTTLE_MS (1h), anchored on IndicatorDao.lastFetchTimeGlobal() (a single feed failing no longer wedges the throttle).
  • Single-flight refresh: a caller arriving during an in-flight refresh waits for it (scan gets fresh data) then reuses it (skipIfRefreshedWithinMs) instead of re-downloading ~6–8 MB. Fixes a worker/pre-scan double-download race.
  • UX: Dashboard shows "Updating threat intel…" during the pre-scan refresh so the scan doesn't look hung behind a non-advancing bar.

Per discussion: full refresh on any network, 1h throttle (no metered-network special-casing).

Review & verification

  • Two independent reviewers + a focused concurrency re-review of the mutex semantics — all clean.
  • On-device (SM-F916B, Android 13/API 33): confirmed via logcat that the pre-scan full refresh runs first (450 public-repo IOCs + 24 SIGMA rules + 87 CVEs), the scan completes after fresh intel lands, the worker/pre-scan race no longer double-downloads (reusing, skipping refresh), and "Updating threat intel…" renders.
  • :app:testDebugUnitTest passes; compileDebugKotlin clean.

🤖 Generated with Claude Code

A manual scan now freshens ALL threat intel before scanning, not just the
bulk feeds. Previously runScan() only called indicatorUpdater.update()
(missing the curated public-repo IOCs, SIGMA rules, and CVEs) and gated it
on a 24h staleness check that effectively never fired given the 12h periodic
worker — so manual scans ran on stale intel.

Changes:
- Extract the worker's refresh sequence into a shared @singleton IntelRefresher
  so the periodic IocUpdateWorker and the pre-scan path run identical logic
  (no drift). Pruning stays worker-only.
- runScan() throttle: 24h -> PRE_SCAN_REFRESH_THROTTLE_MS (1h), anchored on
  indicatorDao.lastFetchTimeGlobal() instead of a single feed's timestamp
  (a single-feed failure no longer wedges the throttle on/off).
- IntelRefresher.refreshAll() is single-flighted: a caller arriving while a
  refresh is in flight WAITS for it (so the scan gets fresh data) and then
  reuses it (skipIfRefreshedWithinMs) instead of re-downloading ~6-8 MB.
- Dashboard shows "Updating threat intel…" during the pre-scan refresh so the
  scan doesn't look hung behind a non-advancing bar.

Reviewed by two independent reviewers + a focused concurrency re-review.
Verified on-device (SM-F916B, API 33): pre-scan full refresh runs first
(450 public-repo IOCs + 24 SIGMA rules + 87 CVEs), scan completes after fresh
intel lands, worker/pre-scan race no longer double-downloads, "Updating
threat intel…" shows. Unit tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yasirhamza yasirhamza merged commit 6fdd064 into main May 29, 2026
4 of 7 checks passed
@yasirhamza yasirhamza deleted the feat/scan-triggers-full-update branch May 29, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant