Skip to content

Fix scoping vulns on group dashboard

Olivier Gonzalez requested to merge fix_vulns_scoping_on_dasbhoard into master

What does this MR do?

Fix the Group Security Dashboard by ensuring we only filter pipeline that effectively have vulnerabilities.

Here are the new queries:

Vulnerabilities list:

EXPLAIN ANALYZE
SELECT "vulnerability_occurrences".*
FROM "vulnerability_occurrences"
INNER JOIN "vulnerability_occurrence_pipelines" ON "vulnerability_occurrence_pipelines"."occurrence_id" = "vulnerability_occurrences"."id"
WHERE "vulnerability_occurrence_pipelines"."pipeline_id" IN
    (SELECT max(ci_pipelines.id) AS id
     FROM "ci_pipelines"
     WHERE "ci_pipelines"."project_id" IN
         (SELECT "projects"."id"
          FROM "projects"
          INNER JOIN routes rs ON rs.source_id = projects.id
          AND rs.source_type = 'Project'
          WHERE (rs.path LIKE 'olivier/%'))
       AND (EXISTS
              (SELECT 1
               FROM "vulnerability_occurrence_pipelines"
               WHERE (ci_pipelines.id=vulnerability_occurrence_pipelines.pipeline_id)))
       AND "ci_pipelines"."status" = 'success'
     GROUP BY "ci_pipelines"."project_id")
                                                                                                                                        QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=15.74..10336.93 rows=12991 width=662) (actual time=0.331..0.560 rows=72 loops=1)
   ->  Nested Loop  (cost=15.32..3275.64 rows=12991 width=8) (actual time=0.323..0.364 rows=72 loops=1)
         ->  HashAggregate  (cost=14.90..14.91 rows=1 width=4) (actual time=0.319..0.319 rows=3 loops=1)
               Group Key: max(ci_pipelines.id)
               ->  GroupAggregate  (cost=14.86..14.88 rows=1 width=8) (actual time=0.311..0.314 rows=3 loops=1)
                     Group Key: ci_pipelines.project_id
                     ->  Sort  (cost=14.86..14.87 rows=1 width=8) (actual time=0.307..0.309 rows=11 loops=1)
                           Sort Key: ci_pipelines.project_id
                           Sort Method: quicksort  Memory: 25kB
                           ->  Nested Loop Semi Join  (cost=7.13..14.85 rows=1 width=8) (actual time=0.193..0.278 rows=11 loops=1)
                                 ->  Nested Loop  (cost=6.71..8.20 rows=15 width=8) (actual time=0.119..0.163 rows=31 loops=1)
                                       Join Filter: (ci_pipelines.project_id = rs.source_id)
                                       ->  Unique  (cost=6.44..6.45 rows=2 width=8) (actual time=0.109..0.111 rows=5 loops=1)
                                             ->  Sort  (cost=6.44..6.44 rows=2 width=8) (actual time=0.108..0.108 rows=5 loops=1)
                                                   Sort Key: projects.id
                                                   Sort Method: quicksort  Memory: 25kB
                                                   ->  Nested Loop  (cost=0.29..6.43 rows=2 width=8) (actual time=0.040..0.059 rows=5 loops=1)
                                                         ->  Index Scan using index_routes_on_path on routes rs  (cost=0.14..3.09 rows=2 width=4) (actual time=0.019..0.026 rows=5 loops=1)
                                                               Index Cond: (((path)::text >= 'olivier/'::text) AND ((path)::text < 'olivier0'::text))
                                                               Filter: (((path)::text ~~ 'olivier/%'::text) AND ((source_type)::text = 'Project'::text))
                                                               Rows Removed by Filter: 2
                                                         ->  Index Only Scan using idx_projects_on_repository_storage_last_repository_updated_at on projects  (cost=0.14..1.66 rows=1 width=4) (actual time=0.002..0.003 rows=1 loops=5)
                                                               Index Cond: (id = rs.source_id)
                                                               Heap Fetches: 4
                                       ->  Index Scan using index_ci_pipelines_on_project_id_and_status_and_config_source on ci_pipelines  (cost=0.27..0.76 rows=9 width=8) (actual time=0.004..0.007 rows=6 loops=5)
                                             Index Cond: ((project_id = projects.id) AND ((status)::text = 'success'::text))
                                 ->  Index Only Scan using index_vulnerability_occurrence_pipelines_on_pipeline_id on vulnerability_occurrence_pipelines vulnerability_occurrence_pipelines_1  (cost=0.42..242.32 rows=12991 width=4) (actual time=0.002..0.002 rows=0 loops=31)
                                       Index Cond: (pipeline_id = ci_pipelines.id)
                                       Heap Fetches: 11
         ->  Index Scan using index_vulnerability_occurrence_pipelines_on_pipeline_id on vulnerability_occurrence_pipelines  (cost=0.42..3130.83 rows=12991 width=12) (actual time=0.003..0.010 rows=24 loops=3)
               Index Cond: (pipeline_id = (max(ci_pipelines.id)))
   ->  Index Scan using vulnerability_occurrences_pkey on vulnerability_occurrences  (cost=0.42..0.53 rows=1 width=662) (actual time=0.002..0.002 rows=1 loops=72)
         Index Cond: (id = vulnerability_occurrence_pipelines.occurrence_id)
 Planning time: 8.017 ms
 Execution time: 0.995 ms
(35 rows)

summary counters:

EXPLAIN ANALYZE
SELECT COUNT(*) AS count_all,
       "vulnerability_occurrences"."report_type" AS vulnerability_occurrences_report_type,
       "vulnerability_occurrences"."severity" AS vulnerability_occurrences_severity
FROM "vulnerability_occurrences"
INNER JOIN "vulnerability_occurrence_pipelines" ON "vulnerability_occurrence_pipelines"."occurrence_id" = "vulnerability_occurrences"."id"
WHERE "vulnerability_occurrence_pipelines"."pipeline_id" IN
    (SELECT max(id) AS id
     FROM "ci_pipelines"
     WHERE "ci_pipelines"."project_id" IN
         (SELECT "projects"."id"
          FROM "projects"
          INNER JOIN routes rs ON rs.source_id = projects.id
          AND rs.source_type = 'Project'
          WHERE (rs.path LIKE 'olivier/%'))
       AND (EXISTS
              (SELECT 1
               FROM "vulnerability_occurrence_pipelines"
               WHERE (ci_pipelines.id=vulnerability_occurrence_pipelines.pipeline_id)))
       AND "ci_pipelines"."status" = 'success'
     GROUP BY "ci_pipelines"."project_id")
GROUP BY "vulnerability_occurrences"."report_type",
         "vulnerability_occurrences"."severity";
                                                                                                                                      QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=10434.36..10434.44 rows=8 width=12) (actual time=0.311..0.312 rows=6 loops=1)
   Group Key: vulnerability_occurrences.report_type, vulnerability_occurrences.severity
   ->  Nested Loop  (cost=15.74..10336.93 rows=12991 width=4) (actual time=0.152..0.297 rows=72 loops=1)
         ->  Nested Loop  (cost=15.32..3275.64 rows=12991 width=8) (actual time=0.149..0.170 rows=72 loops=1)
               ->  HashAggregate  (cost=14.90..14.91 rows=1 width=4) (actual time=0.147..0.147 rows=3 loops=1)
                     Group Key: max(ci_pipelines.id)
                     ->  GroupAggregate  (cost=14.86..14.88 rows=1 width=8) (actual time=0.142..0.145 rows=3 loops=1)
                           Group Key: ci_pipelines.project_id
                           ->  Sort  (cost=14.86..14.87 rows=1 width=8) (actual time=0.139..0.140 rows=11 loops=1)
                                 Sort Key: ci_pipelines.project_id
                                 Sort Method: quicksort  Memory: 25kB
                                 ->  Nested Loop Semi Join  (cost=7.13..14.85 rows=1 width=8) (actual time=0.079..0.132 rows=11 loops=1)
                                       ->  Nested Loop  (cost=6.71..8.20 rows=15 width=8) (actual time=0.044..0.075 rows=31 loops=1)
                                             Join Filter: (ci_pipelines.project_id = rs.source_id)
                                             ->  Unique  (cost=6.44..6.45 rows=2 width=8) (actual time=0.038..0.041 rows=5 loops=1)
                                                   ->  Sort  (cost=6.44..6.44 rows=2 width=8) (actual time=0.038..0.040 rows=5 loops=1)
                                                         Sort Key: projects.id
                                                         Sort Method: quicksort  Memory: 25kB
                                                         ->  Nested Loop  (cost=0.29..6.43 rows=2 width=8) (actual time=0.015..0.027 rows=5 loops=1)
                                                               ->  Index Scan using index_routes_on_path on routes rs  (cost=0.14..3.09 rows=2 width=4) (actual time=0.008..0.013 rows=5 loops=1)
                                                                     Index Cond: (((path)::text >= 'olivier/'::text) AND ((path)::text < 'olivier0'::text))
                                                                     Filter: (((path)::text ~~ 'olivier/%'::text) AND ((source_type)::text = 'Project'::text))
                                                                     Rows Removed by Filter: 2
                                                               ->  Index Only Scan using idx_projects_on_repository_storage_last_repository_updated_at on projects  (cost=0.14..1.66 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=5)
                                                                     Index Cond: (id = rs.source_id)
                                                                     Heap Fetches: 4
                                             ->  Index Scan using index_ci_pipelines_on_project_id_and_status_and_config_source on ci_pipelines  (cost=0.27..0.76 rows=9 width=8) (actual time=0.003..0.005 rows=6 loops=5)
                                                   Index Cond: ((project_id = projects.id) AND ((status)::text = 'success'::text))
                                       ->  Index Only Scan using index_vulnerability_occurrence_pipelines_on_pipeline_id on vulnerability_occurrence_pipelines vulnerability_occurrence_pipelines_1  (cost=0.42..242.32 rows=12991 width=4) (actual time=0.002..0.002 rows=0 loops=31)
                                             Index Cond: (pipeline_id = ci_pipelines.id)
                                             Heap Fetches: 11
               ->  Index Scan using index_vulnerability_occurrence_pipelines_on_pipeline_id on vulnerability_occurrence_pipelines  (cost=0.42..3130.83 rows=12991 width=12) (actual time=0.002..0.004 rows=24 loops=3)
                     Index Cond: (pipeline_id = (max(ci_pipelines.id)))
         ->  Index Scan using vulnerability_occurrences_pkey on vulnerability_occurrences  (cost=0.42..0.53 rows=1 width=12) (actual time=0.001..0.001 rows=1 loops=72)
               Index Cond: (id = vulnerability_occurrence_pipelines.occurrence_id)
 Planning time: 1.272 ms
 Execution time: 0.528 ms
(37 rows)

What are the relevant issue numbers?

#6709 (closed)

Does this MR meet the acceptance criteria?

Edited by Kamil Trzciński

Merge request reports