Skip to content

Bound the in-memory report registry to avoid unbounded growth - #82

Open
arpitjain099 wants to merge 1 commit into
cisagov:developfrom
arpitjain099:chore/bound-report-registry
Open

Bound the in-memory report registry to avoid unbounded growth#82
arpitjain099 wants to merge 1 commit into
cisagov:developfrom
arpitjain099:chore/bound-report-registry

Conversation

@arpitjain099

Copy link
Copy Markdown

Hi, I do supply-chain-security work and was reading through the eleVADR backend. I noticed the completed-report registry can grow without bound, so here is a small hardening fix.

In backend/src/app/main.py, _report_registry stores the full Analyzer for each analysis, and each Analyzer holds the parsed-pcap pandas frames (traffic_df, endpoints_df, services_df). The only writes are the insert in run_analysis and the read in _require_analyzer; nothing ever evicts or caps it. Its sibling dict _progress_queues does get cleaned up (the WebSocket finally block pops it), but the heavier report registry keeps every entry for the lifetime of the worker, so memory climbs steadily as more PCAPs are analyzed.

The change backs the registry with an OrderedDict capped at MAX_STORED_REPORTS (32) and evicts the oldest entry once the cap is reached. Reads through _require_analyzer move the entry to the end, so a report that is actively being drilled into is not the first one evicted. The existing drilldown read path keeps working for recent reports, which is the common case.

Tests: I added two cases in backend/tests/test_main.py covering the size cap and the least-recently-used eviction order. Both pass under Python 3.14, and I confirmed they fail against the previous unbounded behavior. The full test_main.py suite (14 tests) stays green and ruff is clean on the edited source.

If you would rather I raise the 32 default differently, or handle eviction some other way (a TTL or an explicit delete on drilldown completion were alternatives I considered), happy to adjust. Thanks for the tool.

The completed-report registry (_report_registry) stored a full Analyzer,
including its parsed-pcap pandas frames, on every analysis and was never
evicted or capped. Its companion dict _progress_queues is popped in the
WebSocket cleanup path, but the heavier report registry kept growing for
the lifetime of the worker, so repeated analyses steadily increased memory.

Back the registry with an OrderedDict capped at MAX_STORED_REPORTS and evict
the oldest entry once the cap is reached. Reads through _require_analyzer move
the entry to the end so an actively used report is not the first evicted, which
keeps the drilldown routes working for recent reports. Add tests covering the
size bound and the least-recently-used eviction order.

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
@arpitjain099
arpitjain099 requested a review from a team as a code owner July 18, 2026 15:59
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