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
- Get the uuid of a security report finding
query {
project(fullPath:"<project path>") {
pipeline(iid:"<pipeline iid>") {
securityReportFindings(first:1){
nodes {
uuid
}
}
}
}
}
- 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.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #376713 (closed)