Commit 81628d41 authored by James Fargher's avatar James Fargher

Merge branch '267521-add-blobPath-to-vulnerabilitylocation' into 'master'

Add `blobPath` field to `VulnerabilityLocation` types where `file` field is present in GraphQL

See merge request gitlab-org/gitlab!52599
parents 158e768a 461622a2
...@@ -28014,6 +28014,11 @@ type VulnerabilityLocationContainerScanning { ...@@ -28014,6 +28014,11 @@ type VulnerabilityLocationContainerScanning {
Represents the location of a vulnerability found by a Coverage Fuzzing scan Represents the location of a vulnerability found by a Coverage Fuzzing scan
""" """
type VulnerabilityLocationCoverageFuzzing { type VulnerabilityLocationCoverageFuzzing {
"""
Blob path to the vulnerable file
"""
blobPath: String
""" """
Number of the last relevant line in the vulnerable file Number of the last relevant line in the vulnerable file
""" """
...@@ -28069,6 +28074,11 @@ type VulnerabilityLocationDast { ...@@ -28069,6 +28074,11 @@ type VulnerabilityLocationDast {
Represents the location of a vulnerability found by a dependency security scan Represents the location of a vulnerability found by a dependency security scan
""" """
type VulnerabilityLocationDependencyScanning { type VulnerabilityLocationDependencyScanning {
"""
Blob path to the vulnerable file
"""
blobPath: String
""" """
Dependency containing the vulnerability Dependency containing the vulnerability
""" """
...@@ -28084,6 +28094,11 @@ type VulnerabilityLocationDependencyScanning { ...@@ -28084,6 +28094,11 @@ type VulnerabilityLocationDependencyScanning {
Represents the location of a vulnerability found by a SAST scan Represents the location of a vulnerability found by a SAST scan
""" """
type VulnerabilityLocationSast { type VulnerabilityLocationSast {
"""
Blob path to the vulnerable file
"""
blobPath: String
""" """
Number of the last relevant line in the vulnerable file Number of the last relevant line in the vulnerable file
""" """
...@@ -28114,6 +28129,11 @@ type VulnerabilityLocationSast { ...@@ -28114,6 +28129,11 @@ type VulnerabilityLocationSast {
Represents the location of a vulnerability found by a secret detection scan Represents the location of a vulnerability found by a secret detection scan
""" """
type VulnerabilityLocationSecretDetection { type VulnerabilityLocationSecretDetection {
"""
Blob path to the vulnerable file
"""
blobPath: String
""" """
Number of the last relevant line in the vulnerable file Number of the last relevant line in the vulnerable file
""" """
......
...@@ -81316,6 +81316,20 @@ ...@@ -81316,6 +81316,20 @@
"name": "VulnerabilityLocationCoverageFuzzing", "name": "VulnerabilityLocationCoverageFuzzing",
"description": "Represents the location of a vulnerability found by a Coverage Fuzzing scan", "description": "Represents the location of a vulnerability found by a Coverage Fuzzing scan",
"fields": [ "fields": [
{
"name": "blobPath",
"description": "Blob path to the vulnerable file",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "endLine", "name": "endLine",
"description": "Number of the last relevant line in the vulnerable file", "description": "Number of the last relevant line in the vulnerable file",
...@@ -81468,6 +81482,20 @@ ...@@ -81468,6 +81482,20 @@
"name": "VulnerabilityLocationDependencyScanning", "name": "VulnerabilityLocationDependencyScanning",
"description": "Represents the location of a vulnerability found by a dependency security scan", "description": "Represents the location of a vulnerability found by a dependency security scan",
"fields": [ "fields": [
{
"name": "blobPath",
"description": "Blob path to the vulnerable file",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "dependency", "name": "dependency",
"description": "Dependency containing the vulnerability", "description": "Dependency containing the vulnerability",
...@@ -81509,6 +81537,20 @@ ...@@ -81509,6 +81537,20 @@
"name": "VulnerabilityLocationSast", "name": "VulnerabilityLocationSast",
"description": "Represents the location of a vulnerability found by a SAST scan", "description": "Represents the location of a vulnerability found by a SAST scan",
"fields": [ "fields": [
{
"name": "blobPath",
"description": "Blob path to the vulnerable file",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "endLine", "name": "endLine",
"description": "Number of the last relevant line in the vulnerable file", "description": "Number of the last relevant line in the vulnerable file",
...@@ -81592,6 +81634,20 @@ ...@@ -81592,6 +81634,20 @@
"name": "VulnerabilityLocationSecretDetection", "name": "VulnerabilityLocationSecretDetection",
"description": "Represents the location of a vulnerability found by a secret detection scan", "description": "Represents the location of a vulnerability found by a secret detection scan",
"fields": [ "fields": [
{
"name": "blobPath",
"description": "Blob path to the vulnerable file",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "endLine", "name": "endLine",
"description": "Number of the last relevant line in the vulnerable file", "description": "Number of the last relevant line in the vulnerable file",
...@@ -4266,6 +4266,7 @@ Represents the location of a vulnerability found by a Coverage Fuzzing scan. ...@@ -4266,6 +4266,7 @@ Represents the location of a vulnerability found by a Coverage Fuzzing scan.
| Field | Type | Description | | Field | Type | Description |
| ----- | ---- | ----------- | | ----- | ---- | ----------- |
| `blobPath` | String | Blob path to the vulnerable file |
| `endLine` | String | Number of the last relevant line in the vulnerable file | | `endLine` | String | Number of the last relevant line in the vulnerable file |
| `file` | String | Path to the vulnerable file | | `file` | String | Path to the vulnerable file |
| `startLine` | String | Number of the first relevant line in the vulnerable file | | `startLine` | String | Number of the first relevant line in the vulnerable file |
...@@ -4289,6 +4290,7 @@ Represents the location of a vulnerability found by a dependency security scan. ...@@ -4289,6 +4290,7 @@ Represents the location of a vulnerability found by a dependency security scan.
| Field | Type | Description | | Field | Type | Description |
| ----- | ---- | ----------- | | ----- | ---- | ----------- |
| `blobPath` | String | Blob path to the vulnerable file |
| `dependency` | VulnerableDependency | Dependency containing the vulnerability | | `dependency` | VulnerableDependency | Dependency containing the vulnerability |
| `file` | String | Path to the vulnerable file | | `file` | String | Path to the vulnerable file |
...@@ -4298,6 +4300,7 @@ Represents the location of a vulnerability found by a SAST scan. ...@@ -4298,6 +4300,7 @@ Represents the location of a vulnerability found by a SAST scan.
| Field | Type | Description | | Field | Type | Description |
| ----- | ---- | ----------- | | ----- | ---- | ----------- |
| `blobPath` | String | Blob path to the vulnerable file |
| `endLine` | String | Number of the last relevant line in the vulnerable file | | `endLine` | String | Number of the last relevant line in the vulnerable file |
| `file` | String | Path to the vulnerable file | | `file` | String | Path to the vulnerable file |
| `startLine` | String | Number of the first relevant line in the vulnerable file | | `startLine` | String | Number of the first relevant line in the vulnerable file |
...@@ -4310,6 +4313,7 @@ Represents the location of a vulnerability found by a secret detection scan. ...@@ -4310,6 +4313,7 @@ Represents the location of a vulnerability found by a secret detection scan.
| Field | Type | Description | | Field | Type | Description |
| ----- | ---- | ----------- | | ----- | ---- | ----------- |
| `blobPath` | String | Blob path to the vulnerable file |
| `endLine` | String | Number of the last relevant line in the vulnerable file | | `endLine` | String | Number of the last relevant line in the vulnerable file |
| `file` | String | Path to the vulnerable file | | `file` | String | Path to the vulnerable file |
| `startLine` | String | Number of the first relevant line in the vulnerable file | | `startLine` | String | Number of the first relevant line in the vulnerable file |
......
...@@ -23,6 +23,9 @@ module Types ...@@ -23,6 +23,9 @@ module Types
field :start_line, GraphQL::STRING_TYPE, null: true, field :start_line, GraphQL::STRING_TYPE, null: true,
description: 'Number of the first relevant line in the vulnerable file' description: 'Number of the first relevant line in the vulnerable file'
field :blob_path, GraphQL::STRING_TYPE, null: true,
description: 'Blob path to the vulnerable file'
end end
end end
end end
...@@ -12,6 +12,9 @@ module Types ...@@ -12,6 +12,9 @@ module Types
field :file, GraphQL::STRING_TYPE, null: true, field :file, GraphQL::STRING_TYPE, null: true,
description: 'Path to the vulnerable file' description: 'Path to the vulnerable file'
field :blob_path, GraphQL::STRING_TYPE, null: true,
description: 'Blob path to the vulnerable file'
end end
end end
end end
...@@ -23,6 +23,9 @@ module Types ...@@ -23,6 +23,9 @@ module Types
field :start_line, GraphQL::STRING_TYPE, null: true, field :start_line, GraphQL::STRING_TYPE, null: true,
description: 'Number of the first relevant line in the vulnerable file' description: 'Number of the first relevant line in the vulnerable file'
field :blob_path, GraphQL::STRING_TYPE, null: true,
description: 'Blob path to the vulnerable file'
end end
end end
end end
...@@ -23,6 +23,9 @@ module Types ...@@ -23,6 +23,9 @@ module Types
field :start_line, GraphQL::STRING_TYPE, null: true, field :start_line, GraphQL::STRING_TYPE, null: true,
description: 'Number of the first relevant line in the vulnerable file' description: 'Number of the first relevant line in the vulnerable file'
field :blob_path, GraphQL::STRING_TYPE, null: true,
description: 'Blob path to the vulnerable file'
end end
end end
end end
...@@ -115,7 +115,8 @@ module Types ...@@ -115,7 +115,8 @@ module Types
end end
def location def location
object.finding&.location&.merge(report_type: object.report_type) object_location = object.finding&.location
object_location&.merge(blob_path: object.blob_path, report_type: object.report_type)&.compact
end end
def scanner def scanner
......
...@@ -64,14 +64,7 @@ module VulnerabilitiesHelper ...@@ -64,14 +64,7 @@ module VulnerabilitiesHelper
def vulnerability_finding_data(vulnerability) def vulnerability_finding_data(vulnerability)
data = Vulnerabilities::FindingSerializer.new(current_user: current_user).represent(vulnerability.finding, only: FINDING_FIELDS) data = Vulnerabilities::FindingSerializer.new(current_user: current_user).represent(vulnerability.finding, only: FINDING_FIELDS)
data[:location].merge!('blob_path' => vulnerability.blob_path).compact!
if data[:location]['file']
branch = vulnerability.finding.pipelines&.last&.sha || vulnerability.project.default_branch
path = project_blob_path(vulnerability.project, tree_join(branch, data[:location]['file']))
data[:location]['blob_path'] = path
end
data data
end end
end end
...@@ -127,6 +127,8 @@ module EE ...@@ -127,6 +127,8 @@ module EE
:cve_value, :cwe_value, :other_identifier_values, :cve_value, :cwe_value, :other_identifier_values,
to: :finding, allow_nil: true to: :finding, allow_nil: true
delegate :file, to: :finding, prefix: true, private: true
def to_reference(from = nil, full: false) def to_reference(from = nil, full: false)
project project
.to_reference_base(from, full: full) .to_reference_base(from, full: full)
...@@ -161,6 +163,12 @@ module EE ...@@ -161,6 +163,12 @@ module EE
::Vulnerabilities::StatDiff.new(self) ::Vulnerabilities::StatDiff.new(self)
end end
def blob_path
return unless finding_file
::Gitlab::Routing.url_helpers.project_blob_path(project, File.join(finding.pipeline_branch, finding_file))
end
private private
def user_notes_count_service def user_notes_count_service
......
...@@ -372,6 +372,10 @@ module Vulnerabilities ...@@ -372,6 +372,10 @@ module Vulnerabilities
Gitlab::UUID.v5?(uuid) ? uuid : Gitlab::UUID.v5(uuid_v5_name) Gitlab::UUID.v5?(uuid) ? uuid : Gitlab::UUID.v5(uuid_v5_name)
end end
def pipeline_branch
pipelines&.last&.sha || project.default_branch
end
protected protected
def first_fingerprint def first_fingerprint
......
...@@ -34,7 +34,7 @@ class VulnerabilityPresenter < Gitlab::View::Presenter::Delegated ...@@ -34,7 +34,7 @@ class VulnerabilityPresenter < Gitlab::View::Presenter::Delegated
def blob_path def blob_path
return unless file return unless file
path_with_line_number(project_blob_path(vulnerability.project, File.join(pipeline_branch, file))) path_with_line_number(vulnerability.blob_path)
end end
def scanner def scanner
......
---
title: Add blobPath field to VulnerabilityLocation types in GraphQL
merge_request: 52599
author:
type: added
...@@ -42,7 +42,7 @@ RSpec.describe Projects::Security::VulnerabilitiesController do ...@@ -42,7 +42,7 @@ RSpec.describe Projects::Security::VulnerabilitiesController do
end end
context "when there's no attached pipeline" do context "when there's no attached pipeline" do
let_it_be(:finding) { create(:vulnerabilities_finding, vulnerability: vulnerability) } let_it_be(:finding) { create(:vulnerabilities_finding, vulnerability: vulnerability, project: vulnerability.project ) }
it 'renders the vulnerability page' do it 'renders the vulnerability page' do
show_vulnerability show_vulnerability
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityLocationCoverageFuzzing'] do
it do
expect(described_class).to have_graphql_fields(
:vulnerable_class,
:end_line,
:file,
:vulnerable_method,
:start_line,
:blob_path
)
end
end
...@@ -3,5 +3,5 @@ ...@@ -3,5 +3,5 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityLocationDependencyScanning'] do RSpec.describe GitlabSchema.types['VulnerabilityLocationDependencyScanning'] do
it { expect(described_class).to have_graphql_fields(:dependency, :file) } it { expect(described_class).to have_graphql_fields(:dependency, :file, :blob_path) }
end end
...@@ -9,7 +9,8 @@ RSpec.describe GitlabSchema.types['VulnerabilityLocationSast'] do ...@@ -9,7 +9,8 @@ RSpec.describe GitlabSchema.types['VulnerabilityLocationSast'] do
:file, :file,
:start_line, :start_line,
:vulnerable_class, :vulnerable_class,
:vulnerable_method :vulnerable_method,
:blob_path
) )
end end
end end
...@@ -9,7 +9,8 @@ RSpec.describe GitlabSchema.types['VulnerabilityLocationSecretDetection'] do ...@@ -9,7 +9,8 @@ RSpec.describe GitlabSchema.types['VulnerabilityLocationSecretDetection'] do
:file, :file,
:start_line, :start_line,
:vulnerable_class, :vulnerable_class,
:vulnerable_method :vulnerable_method,
:blob_path
) )
end end
end end
...@@ -763,4 +763,18 @@ RSpec.describe Vulnerability do ...@@ -763,4 +763,18 @@ RSpec.describe Vulnerability do
it { is_expected.to be_an_instance_of(Vulnerabilities::StatDiff) } it { is_expected.to be_an_instance_of(Vulnerabilities::StatDiff) }
end end
describe '#blob_path' do
let_it_be(:vulnerability) { create(:vulnerability) }
let_it_be(:pipeline) { create(:ci_pipeline) }
let_it_be(:finding) { create(:vulnerabilities_finding, pipelines: [pipeline], vulnerability: vulnerability) }
subject { vulnerability.blob_path }
it 'returns project blob path' do
expect(subject).to eq(
"/#{vulnerability.project.namespace.path}/#{vulnerability.project.name}/-/blob/#{pipeline.sha}/#{vulnerability.finding.file}"
)
end
end
end end
...@@ -32,6 +32,7 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -32,6 +32,7 @@ RSpec.describe 'Query.vulnerabilities.location' do
name name
} }
} }
blobPath
} }
... on VulnerabilityLocationDast { ... on VulnerabilityLocationDast {
hostname hostname
...@@ -45,6 +46,7 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -45,6 +46,7 @@ RSpec.describe 'Query.vulnerabilities.location' do
startLine startLine
vulnerableClass vulnerableClass
vulnerableMethod vulnerableMethod
blobPath
} }
... on VulnerabilityLocationSecretDetection { ... on VulnerabilityLocationSecretDetection {
endLine endLine
...@@ -52,6 +54,7 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -52,6 +54,7 @@ RSpec.describe 'Query.vulnerabilities.location' do
startLine startLine
vulnerableClass vulnerableClass
vulnerableMethod vulnerableMethod
blobPath
} }
} }
QUERY QUERY
...@@ -112,6 +115,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -112,6 +115,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
create(:vulnerability, project: project, report_type: :dependency_scanning) create(:vulnerability, project: project, report_type: :dependency_scanning)
end end
let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) }
let_it_be(:metadata) do let_it_be(:metadata) do
{ {
location: { location: {
...@@ -130,7 +135,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -130,7 +135,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
create( create(
:vulnerabilities_finding, :vulnerabilities_finding,
vulnerability: vulnerability, vulnerability: vulnerability,
raw_metadata: metadata.to_json raw_metadata: metadata.to_json,
pipelines: [pipeline]
) )
end end
...@@ -149,6 +155,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -149,6 +155,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
create(:vulnerability, project: project, report_type: :sast) create(:vulnerability, project: project, report_type: :sast)
end end
let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) }
let_it_be(:metadata) do let_it_be(:metadata) do
{ {
location: { location: {
...@@ -156,7 +164,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -156,7 +164,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
method: 'vulnerable_method', method: 'vulnerable_method',
file: 'vulnerable_file', file: 'vulnerable_file',
start_line: '420', start_line: '420',
end_line: '666' end_line: '666',
blob_path: 'blob/vulnerable_file'
} }
} }
end end
...@@ -165,7 +174,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -165,7 +174,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
create( create(
:vulnerabilities_finding, :vulnerabilities_finding,
vulnerability: vulnerability, vulnerability: vulnerability,
raw_metadata: metadata.to_json raw_metadata: metadata.to_json,
pipelines: [pipeline]
) )
end end
...@@ -186,6 +196,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -186,6 +196,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
create(:vulnerability, project: project, report_type: :secret_detection) create(:vulnerability, project: project, report_type: :secret_detection)
end end
let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) }
let_it_be(:metadata) do let_it_be(:metadata) do
{ {
location: { location: {
...@@ -202,7 +214,8 @@ RSpec.describe 'Query.vulnerabilities.location' do ...@@ -202,7 +214,8 @@ RSpec.describe 'Query.vulnerabilities.location' do
create( create(
:vulnerabilities_finding, :vulnerabilities_finding,
vulnerability: vulnerability, vulnerability: vulnerability,
raw_metadata: metadata.to_json raw_metadata: metadata.to_json,
pipelines: [pipeline]
) )
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment