Performance issues on vulnerability_findings endpoint
Summary
This is a follow-up to an internal request for help issue.
The api/v4/projects/<project_id>/vulnerability_findings
endpoint results in a PG::QueryCanceled: ERROR: canceling statement due to statement timeout
on projects with a large number of vulnerability findings. In this issue(Internal), we noted that it was getting hung up on a query like so:
*/ SELECT \"security_findings\".* FROM \"security_findings\" INNER JOIN \"security_scans\" ON \"security_findings\".\"scan_id\" = \"security_scans\".\"id\" WHERE \"security_scans\".\"pipeline_id\" = $1 ORDER BY \"security_findings\".\"id\" ASC LIMIT $2"
We merged !117290 (merged) which skiped the ORDER BY
to improve the query performance, but it was not enough to resolve the full scope of the performance issues.
The next step is to look at https://gitlab.com/gitlab-org/gitlab/-/blob/af749b979a3ef624d4c73f4962c9306681780f24/ee/app/finders/security/findings_finder.rb#L104 and see if we can remove it or replace it.
Steps to reproduce
See linked project(Internal), this also includes an example report for team members only.
What is the current bug behavior?
The Merge Request security report widget & Security tab on the pipeline page take a very long time to load (Upwards of 30 minutes). Occasionally, they see Error fetching the vulnerability list. Please check your network connection and try again
. Curls to the vulnerability_findings
timeout. Request ran for longer than 60000ms
errors are displayed when trying to load vulnerability findings.
What is the expected correct behavior?
We should be able to retrieve vulnerabilities and be performant on projects with a large number of vulnerabilities reported.
Relevant logs and/or screenshots
v15.8.2
Output of checks
Results of GitLab environment info
Expand for output related to GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of: `sudo gitlab-rake gitlab:env:info`) (For installations from source run and paste the output of: `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
Results of GitLab application Check
Expand for output related to the GitLab application check
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:check SANITIZE=true
)(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true
)(we will only investigate if the tests are passing)
Possible fixes
- Restructure the query in
Security::FindingsFinder
to useLATERAL JOIN
.
SELECT
"security_findings".*
FROM
"security_scans",
unnest('{1, 2, 3, 4, 5, 6, 7}'::smallint[]) AS "severities" ("severity"),
LATERAL (
SELECT
"security_findings".*
FROM
"security_findings"
WHERE
"security_findings"."scan_id" = "security_scans"."id"
AND "security_findings"."deduplicated" = TRUE
AND "security_findings"."severity" = "severities"."severity"
AND (NOT EXISTS (
SELECT
1
FROM
"vulnerabilities"
INNER JOIN "vulnerability_occurrences" ON "vulnerability_occurrences"."vulnerability_id" = "vulnerabilities"."id"
WHERE
"vulnerabilities"."state" = 2
AND (vulnerability_occurrences.uuid = security_findings.uuid::text)))
ORDER BY
"security_findings"."id" ASC
LIMIT 20
) AS "security_findings"
WHERE
"security_scans"."pipeline_id" = $PIPELINE_ID
AND "security_scans"."latest" = TRUE
AND "security_scans"."status" = 1
AND "security_scans"."scan_type" IN (1, 2, 3, 4, 5, 6, 7)
ORDER BY
"security_findings"."severity" DESC,
"security_findings"."id" ASC
LIMIT 20
- Add a new index to
security_findings
CREATE INDEX ON security_findings (scan_id, deduplicated, severity DESC, id ASC)
- Add keyset pagination to the
/api/:version/projects/:id/vulnerability_findings
and modify any frontend code to keyset paginate bysecurity_findings.id
.
Verification steps
The verification project set up for this issue can be used. Prior to the changes this project was taking around 15 seconds to run the database queries.
- Visit https://gitlab.com/gitlab-org/govern/threat-insights-demos/verification-projects/verify-411666/-/pipelines
- Click on the most recent pipeline, then Security
- Ensure there is a paginated list of findings
- Check the logs in kibana for your request to the
vulnerability_findings
endpoint. - Verify the
json.db_duration_s
of the request is adequate, e.g. around 0.5 seconds.