Skip to content

Add individual securityReportFinding GraphQL Query

What does this MR do and why?

This MR adds an individual GraphQL query to pull a single security report finding data. This is necessary to avoid having to pull all data from the report for one finding.

This re-uses a lot of code from the existing Security::PipelineVulnerabilitiesFinder. The code reused is expected to be removed as unnecessary once we begin storing the report data as described in Extend the use of `security_findings` (&8341 - closed).

Screenshots or screen recordings

Example of new query:

query {
  project(fullPath:"<project path>") {
    pipeline(iid:"<pipeline iid>") {
      securityReportFinding(uuid:"<uuid>") {
        state
        uuid
        reportType
      }
    }
  }
}

Database

postgres.ai details: https://postgres.ai/console/gitlab/gitlab-production-tunnel-pg12/sessions/13163/commands/46158

Query:

SELECT "vulnerabilities"."id" AS t0_r0, "vulnerabilities"."milestone_id" AS t0_r1, "vulnerabilities"."epic_id" AS t0_r2, "vulnerabilities"."project_id" AS t0_r3, "vulnerabilities"."author_id" AS t0_r4, "vulnerabilities"."updated_by_id" AS t0_r5, "vulnerabilities"."last_edited_by_id" AS t0_r6, "vulnerabilities"."start_date" AS t0_r7, "vulnerabilities"."due_date" AS t0_r8, "vulnerabilities"."last_edited_at" AS t0_r9, "vulnerabilities"."created_at" AS t0_r10, "vulnerabilities"."updated_at" AS t0_r11, "vulnerabilities"."title" AS t0_r12, "vulnerabilities"."title_html" AS t0_r13, "vulnerabilities"."description" AS t0_r14, "vulnerabilities"."description_html" AS t0_r15, "vulnerabilities"."start_date_sourcing_milestone_id" AS t0_r16, "vulnerabilities"."due_date_sourcing_milestone_id" AS t0_r17, "vulnerabilities"."state" AS t0_r18, "vulnerabilities"."severity" AS t0_r19, "vulnerabilities"."severity_overridden" AS t0_r20, "vulnerabilities"."confidence" AS t0_r21, "vulnerabilities"."confidence_overridden" AS t0_r22, "vulnerabilities"."resolved_by_id" AS t0_r23, "vulnerabilities"."resolved_at" AS t0_r24, "vulnerabilities"."report_type" AS t0_r25, "vulnerabilities"."cached_markdown_version" AS t0_r26, "vulnerabilities"."confirmed_by_id" AS t0_r27, "vulnerabilities"."confirmed_at" AS t0_r28, "vulnerabilities"."dismissed_at" AS t0_r29, "vulnerabilities"."dismissed_by_id" AS t0_r30, "vulnerabilities"."resolved_on_default_branch" AS t0_r31, "vulnerabilities"."present_on_default_branch" AS t0_r32, "vulnerabilities"."detected_at" AS t0_r33, "findings"."id" AS t1_r0, "findings"."created_at" AS t1_r1, "findings"."updated_at" AS t1_r2, "findings"."severity" AS t1_r3, "findings"."confidence" AS t1_r4, "findings"."report_type" AS t1_r5, "findings"."project_id" AS t1_r6, "findings"."scanner_id" AS t1_r7, "findings"."primary_identifier_id" AS t1_r8, "findings"."project_fingerprint" AS t1_r9, "findings"."location_fingerprint" AS t1_r10, "findings"."uuid" AS t1_r11, "findings"."name" AS t1_r12, "findings"."metadata_version" AS t1_r13, "findings"."raw_metadata" AS t1_r14, "findings"."vulnerability_id" AS t1_r15, "findings"."details" AS t1_r16, "findings"."description" AS t1_r17, "findings"."message" AS t1_r18, "findings"."solution" AS t1_r19, "findings"."cve" AS t1_r20, "findings"."location" AS t1_r21, "findings"."detection_method" AS t1_r22, "findings"."uuid_convert_string_to_uuid" AS t1_r23 FROM "vulnerabilities" LEFT OUTER JOIN "vulnerability_occurrences" "findings" ON "findings"."vulnerability_id" = "vulnerabilities"."id" WHERE "vulnerabilities"."project_id" = 37661569 AND "findings"."uuid" = 'e97672f2-7f81-58b2-b7b8-2c654f3f5f25' 

Execution Plan:

Nested Loop  (cost=1.13..7.17 rows=1 width=1938) (actual time=46.011..46.022 rows=1 loops=1)
   Buffers: shared hit=2 read=8
   I/O Timings: read=45.823 write=0.000
   ->  Index Scan using index_vulnerability_occurrences_on_uuid on public.vulnerability_occurrences findings  (cost=0.56..3.58 rows=1 width=1574) (actual time=27.261..27.268 rows=1 loops=1)
         Index Cond: ((findings.uuid)::text = 'e97672f2-7f81-58b2-b7b8-2c654f3f5f25'::text)
         Buffers: shared read=5
         I/O Timings: read=27.157 write=0.000
   ->  Index Scan using vulnerabilities_pkey on public.vulnerabilities  (cost=0.56..3.58 rows=1 width=364) (actual time=18.731..18.731 rows=1 loops=1)
         Index Cond: (vulnerabilities.id = findings.vulnerability_id)
         Filter: (vulnerabilities.project_id = 37661569)
         Rows Removed by Filter: 0
         Buffers: shared hit=2 read=3
         I/O Timings: read=18.665 write=0.000

Timings:

Time: 52.290 ms  
  - planning: 6.206 ms  
  - execution: 46.084 ms  
    - I/O read: 45.823 ms  
    - I/O write: 0.000 ms  
  
Shared buffers:  
  - hits: 2 (~16.00 KiB) from the buffer pool  
  - reads: 8 (~64.00 KiB) from the OS file cache, including disk I/O  
  - dirtied: 0  
  - writes: 0  

How to set up and validate locally

  1. Get the uuid of a security report finding
query {
  project(fullPath:"<project path>") {
    pipeline(iid:"<pipeline iid>") {
      securityReportFindings(first:1){
        nodes {
          uuid
        }
      }
    }
  }
}
  1. Submit the new query
query {
  project(fullPath:"<project path>") {
    pipeline(iid:"<pipeline iid>") {
      securityReportFinding(uuid:"<uuid>") {
        state
        uuid
        reportType
      }
    }
  }
}

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #376713 (closed)

Edited by Jonathan Schafer

Merge request reports

Loading