Skip to content

perf(api): eliminate notes N+1 in finding/engagement/test/risk_acceptance list endpoints#15274

Open
vvpoglazov wants to merge 1 commit into
DefectDojo:devfrom
vvpoglazov:perf/notes-nested-prefetch
Open

perf(api): eliminate notes N+1 in finding/engagement/test/risk_acceptance list endpoints#15274
vvpoglazov wants to merge 1 commit into
DefectDojo:devfrom
vvpoglazov:perf/notes-nested-prefetch

Conversation

@vvpoglazov

Copy link
Copy Markdown
Contributor

Description

List endpoints that embed NoteSerializer (findings, engagements, tests, risk acceptances) prefetch the notes relation flat. NoteSerializer then renders author, editor, note_type on each note and current_editor/note_type on each history entry, so each of those is lazy-loaded with a separate query per note - a classic N+1 that grows with the number of notes on the page.

This PR adds notes_prefetch() to dojo/notes/helper.py - a nested Prefetch that pulls every relation NoteSerializer renders in bulk - and uses it in the four affected viewsets.

Measured on /api/v2/findings/ (25 findings × 5 notes each, each note edited with one history entry): ~375 per-note queries collapse into 3 constant ones, median response time 299ms to 144ms (~2.1×). The response payload is byte-identical before and after (verified by diffing the full JSON responses).

No behavior change, no model changes, no migrations.

Test results

Added unittests/test_api_notes_nplusone.py: for each of the four list endpoints it asserts the SQL query count is identical with 1 note and with 5 notes. Without the fix the tests fail with "+16 extra queries for 4 extra notes"; with the fix all four pass.

Documentation

Not needed - no user-facing or API contract changes.

…ance list endpoints

The list endpoints that embed NoteSerializer prefetched the notes relation
flat, so the serializer lazy-loaded author, editor, note_type and
history__current_editor with one query per note (4+ extra queries per note
per request). Introduce notes_prefetch() in dojo/notes/helper.py — a nested
Prefetch that pulls every relation NoteSerializer renders in bulk — and use
it in the four affected viewsets.

Measured on the finding list endpoint (25 findings x 5 notes each): 375
queries dropped to 3 constant ones, median response time 299ms -> 144ms
(~2.1x); response payload is byte-identical.

The regression test asserts the query count is independent of the number of
notes on each of the four endpoints.
@dryrunsecurity

Copy link
Copy Markdown

DryRun Security

This pull request contains a critical finding where a sensitive code file, dojo/notes/helper.py, was modified by an unauthorized author, 'vvpoglazov', violating the configured sensitive codepath policy, though the issue is non-blocking.

🔴 Configured Sensitive Codepath Modified by Non-Allowed Author in dojo/notes/helper.py (drs_76ebc5b0)
Vulnerability Configured Sensitive Codepath Modified by Non-Allowed Author
Description File 'dojo/notes/helper.py' matches configured sensitive codepath pattern 'dojo/notes/*.py' and was modified by 'vvpoglazov' (commit 01ba8a4) who is not in the allowed authors list.

We've notified @mtesauro.


Comment to provide feedback on these findings.

Report false positive: @dryrunsecurity fp [FINDING ID] [FEEDBACK]
Report low-impact: @dryrunsecurity nit [FINDING ID] [FEEDBACK]

Example: @dryrunsecurity fp drs_90eda195 This code is not user-facing

All finding details can be found in the DryRun Security Dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant