Commit cb47a241 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'sast_relative_broken_links_10435' into 'master'

Link to vulnerability location URL in the issue

See merge request gitlab-org/gitlab!27747
parents 63c0654e e50baae5
...@@ -105,6 +105,7 @@ class Projects::VulnerabilityFeedbackController < Projects::ApplicationControlle ...@@ -105,6 +105,7 @@ class Projects::VulnerabilityFeedbackController < Projects::ApplicationControlle
def vulnerability_data_params_attributes def vulnerability_data_params_attributes
%i[ %i[
blob_path
category category
confidence confidence
count count
......
...@@ -5,15 +5,12 @@ module Issues ...@@ -5,15 +5,12 @@ module Issues
def execute def execute
return error("Can't create issue") unless can?(@current_user, :create_issue, @project) return error("Can't create issue") unless can?(@current_user, :create_issue, @project)
vulnerability = case @params[:category] begin
when 'sast', 'dependency_scanning', 'dast' vulnerability = Gitlab::Vulnerabilities::Parser.fabricate(@params)
Gitlab::Vulnerabilities::StandardVulnerability.new(params) rescue Gitlab::Vulnerabilities::InvalidCategoryError
when 'container_scanning' return error('Invalid vulnerability category')
Gitlab::Vulnerabilities::ContainerScanningVulnerability.new(params)
end end
return error('Invalid vulnerability category') unless vulnerability
issue_params = { issue_params = {
title: "Investigate vulnerability: #{vulnerability.title}", title: "Investigate vulnerability: #{vulnerability.title}",
description: render_description(vulnerability), description: render_description(vulnerability),
...@@ -36,8 +33,10 @@ module Issues ...@@ -36,8 +33,10 @@ module Issues
end end
def render_description(vulnerability) def render_description(vulnerability)
view = ActionView::Base.new(ActionController::Base.view_paths, {}) ApplicationController.render(
view.render(file: 'vulnerabilities/issue_description.md.erb', locals: { vulnerability: vulnerability }) template: 'vulnerabilities/issue_description.md.erb',
locals: { vulnerability: vulnerability }
)
end end
end end
end end
...@@ -3,9 +3,11 @@ ...@@ -3,9 +3,11 @@
module MergeRequests module MergeRequests
class CreateFromVulnerabilityDataService < ::BaseService class CreateFromVulnerabilityDataService < ::BaseService
def execute def execute
vulnerability = create_vulnerability begin
vulnerability = Gitlab::Vulnerabilities::Parser.fabricate(@params)
return error('Invalid vulnerability category') unless vulnerability rescue Gitlab::Vulnerabilities::InvalidCategoryError
return error('Invalid vulnerability category')
end
title_slug = Gitlab::Utils.slugify(vulnerability.title) title_slug = Gitlab::Utils.slugify(vulnerability.title)
source_branch = "remediate/%s-%s" % [ source_branch = "remediate/%s-%s" % [
...@@ -40,15 +42,6 @@ module MergeRequests ...@@ -40,15 +42,6 @@ module MergeRequests
private private
def create_vulnerability
case @params[:category]
when 'sast', 'dependency_scanning', 'dast'
Gitlab::Vulnerabilities::StandardVulnerability.new(@params)
when 'container_scanning'
Gitlab::Vulnerabilities::ContainerScanningVulnerability.new(@params)
end
end
def create_patch(vulnerability, source_branch, target_branch) def create_patch(vulnerability, source_branch, target_branch)
diffs = vulnerability.data[:remediations].map { |remediation| Base64.decode64(remediation[:diff]) } diffs = vulnerability.data[:remediations].map { |remediation| Base64.decode64(remediation[:diff]) }
head_commit = project.repository.find_branch(target_branch).dereferenced_target head_commit = project.repository.find_branch(target_branch).dereferenced_target
......
---
title: Use absolute URLs to ensure links to the source of SAST vulnerabilities resolve
merge_request: 27747
author:
type: fixed
# frozen_string_literal: true
module Gitlab
module Vulnerabilities
InvalidCategoryError = Class.new(StandardError)
module Parser
class << self
def fabricate(params)
raise ::Gitlab::Vulnerabilities::InvalidCategoryError unless valid_categories.key?(params[:category])
category = params[:category]
if standard_vulnerability? category
Gitlab::Vulnerabilities::StandardVulnerability.new(params)
else
Gitlab::Vulnerabilities::ContainerScanningVulnerability.new(params)
end
end
private
def valid_categories
::Vulnerabilities::Feedback.categories
end
def standard_vulnerability?(category)
(valid_categories.keys - ['container_scanning']).include?(category)
end
end
end
end
end
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
module Gitlab module Gitlab
module Vulnerabilities module Vulnerabilities
class StandardVulnerability < BaseVulnerability class StandardVulnerability < BaseVulnerability
include RequestAwareEntity
# Passthrough properties # Passthrough properties
%i[ %i[
severity severity
...@@ -40,10 +41,16 @@ module Gitlab ...@@ -40,10 +41,16 @@ module Gitlab
"#{file}:#{line}" "#{file}:#{line}"
end end
def blob_path
return unless @data[:blob_path]
@data[:blob_path].gsub(/^\//, '')
end
def location_link def location_link
return file unless line return location_text unless blob_path
"#{file}#L#{line}" "#{root_url}#{blob_path}"
end end
end end
end end
......
...@@ -122,6 +122,7 @@ describe Projects::VulnerabilityFeedbackController do ...@@ -122,6 +122,7 @@ describe Projects::VulnerabilityFeedbackController do
title: 'Predictable pseudorandom number generator', title: 'Predictable pseudorandom number generator',
description: 'Description of Predictable pseudorandom number generator', description: 'Description of Predictable pseudorandom number generator',
tool: 'find_sec_bugs', tool: 'find_sec_bugs',
blob_path: '/group_path/project_path/-/blob/commitsha/subdir/src/main/App.java#L15',
location: { location: {
file: 'subdir/src/main/java/com/gitlab/security_products/tests/App.java', file: 'subdir/src/main/java/com/gitlab/security_products/tests/App.java',
start_line: '41' start_line: '41'
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Vulnerabilities::Parser do
describe '.fabricate' do
let(:params) do
{
target_branch: 'master'
}
end
subject { described_class.fabricate(params) }
context 'with standard categories' do
let(:categories) do
%w(
sast
dast
dependency_scanning
)
end
it 'returns a Standard Vulnerability' do
categories.each do |category|
params[:category] = category
expect(subject).to be_a(Gitlab::Vulnerabilities::StandardVulnerability)
expect(subject.target_branch).to eq('master')
end
end
end
context 'with container scanning as category' do
it 'returns a Scanning Vulnerability' do
params[:category] = 'container_scanning'
expect(subject).to be_a(Gitlab::Vulnerabilities::ContainerScanningVulnerability)
expect(subject.target_branch).to eq('master')
end
end
context 'with an invalid category' do
it 'raises an exception' do
params[:category] = 'foo'
expect { subject }.to raise_error(Gitlab::Vulnerabilities::InvalidCategoryError)
end
end
end
end
...@@ -259,19 +259,19 @@ describe Gitlab::Vulnerabilities::StandardVulnerability do ...@@ -259,19 +259,19 @@ describe Gitlab::Vulnerabilities::StandardVulnerability do
end end
describe '#location_link' do describe '#location_link' do
context 'when line is nil' do context 'when blob_path is nil' do
it 'returns a string with file' do it 'returns file path' do
vulnerability = described_class.new(file: file) vulnerability = described_class.new(file: "/foo/bar/-/blob/sha/#{file}")
expect(vulnerability.location_link).to eq file expect(vulnerability.location_link).to eq "/foo/bar/-/blob/sha/#{file}"
end end
end end
context 'when line is present' do context 'when line is present' do
it 'returns a string with file and line' do it 'returns a string with file and line' do
vulnerability = described_class.new(file: file, line: line) vulnerability = described_class.new(blob_path: "/foo/bar/-/blob/sha/#{file}#L#{line}")
expect(vulnerability.location_link).to eq "#{file}#L#{line}" expect(vulnerability.location_link).to eq "http://localhost/foo/bar/-/blob/sha/#{file}#L#{line}"
end end
end end
end end
......
...@@ -56,6 +56,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -56,6 +56,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
context 'when a description is present' do context 'when a description is present' do
let(:params) do let(:params) do
{ {
blob_path: '/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15',
category: 'sast', category: 'sast',
severity: 'Low', confidence: 'High', severity: 'Low', confidence: 'High',
solution: 'Please do something!', solution: 'Please do something!',
...@@ -98,7 +99,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -98,7 +99,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
* Severity: Low * Severity: Low
* Confidence: High * Confidence: High
* Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:15](subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15) * Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:15](http://localhost/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15)
### Solution: ### Solution:
...@@ -123,6 +124,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -123,6 +124,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
context 'when a description is NOT present' do context 'when a description is NOT present' do
let(:params) do let(:params) do
{ {
blob_path: '/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15',
category: 'sast', category: 'sast',
severity: 'Low', confidence: 'High', severity: 'Low', confidence: 'High',
solution: 'Please do something!', solution: 'Please do something!',
...@@ -142,7 +144,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -142,7 +144,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
* Severity: Low * Severity: Low
* Confidence: High * Confidence: High
* Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:15](subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15) * Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:15](http://localhost/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15)
### Solution: ### Solution:
...@@ -158,6 +160,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -158,6 +160,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
context 'when a description is present' do context 'when a description is present' do
let(:params) do let(:params) do
{ {
blob_path: '/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15',
category: 'dependency_scanning', category: 'dependency_scanning',
severity: 'Low', confidence: 'High', severity: 'Low', confidence: 'High',
solution: 'Please do something!', solution: 'Please do something!',
...@@ -199,7 +202,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -199,7 +202,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
* Severity: Low * Severity: Low
* Confidence: High * Confidence: High
* Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:15](subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15) * Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:15](http://localhost/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15)
### Solution: ### Solution:
...@@ -224,6 +227,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -224,6 +227,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
context 'when a description is NOT present' do context 'when a description is NOT present' do
let(:params) do let(:params) do
{ {
blob_path: '/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15',
category: 'dependency_scanning', category: 'dependency_scanning',
priority: 'Low', line: '41', priority: 'Low', line: '41',
severity: 'Low', confidence: 'High', severity: 'Low', confidence: 'High',
...@@ -243,7 +247,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -243,7 +247,7 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
* Severity: Low * Severity: Low
* Confidence: High * Confidence: High
* Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:41](subdir/src/main/java/com/gitlab/security_products/tests/App.java#L41) * Location: [subdir/src/main/java/com/gitlab/security_products/tests/App.java:41](http://localhost/group_path/sub_group_path/project_path/-/blob/commitsha/subdir/src/main/java/com/gitlab/security_products/tests/App.java#L15)
### Solution: ### Solution:
...@@ -402,5 +406,15 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do ...@@ -402,5 +406,15 @@ describe Issues::CreateFromVulnerabilityDataService, '#execute' do
expect(result[:message]).to eq('Invalid vulnerability category') expect(result[:message]).to eq('Invalid vulnerability category')
end end
end end
context 'when category is missing' do
let(:params) { {} }
let(:result) { described_class.new(project, user, params).execute }
it 'return expected error' do
expect(result[:status]).to eq(:error)
expect(result[:message]).to eq('Invalid vulnerability category')
end
end
end end
end end
...@@ -19,6 +19,7 @@ describe VulnerabilityFeedback::CreateService, '#execute' do ...@@ -19,6 +19,7 @@ describe VulnerabilityFeedback::CreateService, '#execute' do
project_fingerprint: '418291a26024a1445b23fe64de9380cdcdfd1fa8', project_fingerprint: '418291a26024a1445b23fe64de9380cdcdfd1fa8',
comment: 'a dismissal comment', comment: 'a dismissal comment',
vulnerability_data: { vulnerability_data: {
blob_path: '/path/to/blob',
category: 'sast', category: 'sast',
priority: 'Low', line: '41', priority: 'Low', line: '41',
file: 'subdir/src/main/java/com/gitlab/security_products/tests/App.java', file: 'subdir/src/main/java/com/gitlab/security_products/tests/App.java',
......
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