Commit a6981733 authored by Dmytro Zaporozhets (DZ)'s avatar Dmytro Zaporozhets (DZ)

Merge branch '280951-add-method-to-create-issue-in-jira-from-finding' into 'master'

Add method to create issue in Jira from vulnerability finding

See merge request gitlab-org/gitlab!49000
parents 0f3cd731 a4379bae
# frozen_string_literal: true # frozen_string_literal: true
module VulnerabilitiesHelper module VulnerabilitiesHelper
FINDING_FIELDS = %i[metadata identifiers name issue_feedback merge_request_feedback project project_fingerprint scanner].freeze
def vulnerability_details_json(vulnerability, pipeline) def vulnerability_details_json(vulnerability, pipeline)
vulnerability_details(vulnerability, pipeline).to_json vulnerability_details(vulnerability, pipeline).to_json
end end
...@@ -36,9 +38,10 @@ module VulnerabilitiesHelper ...@@ -36,9 +38,10 @@ module VulnerabilitiesHelper
def create_jira_issue_url_for(vulnerability) def create_jira_issue_url_for(vulnerability)
return unless vulnerability.project.jira_vulnerabilities_integration_enabled? return unless vulnerability.project.jira_vulnerabilities_integration_enabled?
summary = _('Investigate vulnerability: %{title}') % { title: vulnerability.title } decorated_vulnerability = vulnerability.present
summary = _('Investigate vulnerability: %{title}') % { title: decorated_vulnerability.title }
description = ApplicationController.render(template: 'vulnerabilities/jira_issue_description.md.erb', description = ApplicationController.render(template: 'vulnerabilities/jira_issue_description.md.erb',
locals: { vulnerability: vulnerability.present }) locals: { vulnerability: decorated_vulnerability })
vulnerability.project.jira_service.new_issue_url_with_predefined_fields(summary, description) vulnerability.project.jira_service.new_issue_url_with_predefined_fields(summary, description)
end end
...@@ -59,28 +62,7 @@ module VulnerabilitiesHelper ...@@ -59,28 +62,7 @@ module VulnerabilitiesHelper
end end
def vulnerability_finding_data(vulnerability) def vulnerability_finding_data(vulnerability)
finding = Vulnerabilities::FindingSerializer.new(current_user: current_user).represent(vulnerability.finding) data = Vulnerabilities::FindingSerializer.new(current_user: current_user).represent(vulnerability.finding, only: FINDING_FIELDS)
data = finding.slice(
:description,
:identifiers,
:links,
:location,
:name,
:issue_feedback,
:merge_request_feedback,
:project,
:project_fingerprint,
:remediations,
:evidence,
:scanner,
:solution,
:request,
:response,
:evidence_source,
:supporting_messages,
:assets
)
if data[:location]['file'] if data[:location]['file']
branch = vulnerability.finding.pipelines&.last&.sha || vulnerability.project.default_branch branch = vulnerability.finding.pipelines&.last&.sha || vulnerability.project.default_branch
......
...@@ -4,6 +4,10 @@ module Vulnerabilities ...@@ -4,6 +4,10 @@ module Vulnerabilities
class FindingPresenter < Gitlab::View::Presenter::Delegated class FindingPresenter < Gitlab::View::Presenter::Delegated
presents :finding presents :finding
def title
name
end
def blob_path def blob_path
return '' unless sha.present? return '' unless sha.present?
return '' unless location.present? && location['file'].present? return '' unless location.present? && location['file'].present?
......
...@@ -2,11 +2,15 @@ ...@@ -2,11 +2,15 @@
class Vulnerabilities::FindingEntity < Grape::Entity class Vulnerabilities::FindingEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
include VulnerabilitiesHelper
expose :id, :report_type, :name, :severity, :confidence expose :id, :report_type, :name, :severity, :confidence
expose :scanner, using: Vulnerabilities::ScannerEntity expose :scanner, using: Vulnerabilities::ScannerEntity
expose :identifiers, using: Vulnerabilities::IdentifierEntity expose :identifiers, using: Vulnerabilities::IdentifierEntity
expose :project_fingerprint expose :project_fingerprint
expose :create_jira_issue_url do |occurrence|
create_jira_issue_url_for(occurrence)
end
expose :create_vulnerability_feedback_issue_path do |occurrence| expose :create_vulnerability_feedback_issue_path do |occurrence|
create_vulnerability_feedback_issue_path(occurrence.project) create_vulnerability_feedback_issue_path(occurrence.project)
end end
......
...@@ -12,11 +12,11 @@ h3. <%= _("Description") %>: ...@@ -12,11 +12,11 @@ h3. <%= _("Description") %>:
<% if vulnerability.confidence.present? %> <% if vulnerability.confidence.present? %>
* <%= _("Confidence") %>: <%= vulnerability.confidence %> * <%= _("Confidence") %>: <%= vulnerability.confidence %>
<% end %> <% end %>
<% if vulnerability.try(:file) %> <% if vulnerability.try(:location_text) && vulnerability.try(:location_link) %>
* <%= _("Location") %>: [<%= vulnerability.location_text %>|<%= vulnerability.location_link %>] * <%= _("Location") %>: [<%= vulnerability.try(:location_text) %>|<%= vulnerability.try(:location_link) %>]
<% end %> <% end %>
<% if vulnerability.solution.present? %> <% if vulnerability.solution.present? && vulnerability.is_a?(Vulnerability) %>
### <%= _("Solution") %>: ### <%= _("Solution") %>:
<%= _("See vulnerability %{vulnerability_link} for any Solution details.".html_safe) % { vulnerability_link: "[#{vulnerability.id}|#{vulnerability_url(vulnerability)}]" } %> <%= _("See vulnerability %{vulnerability_link} for any Solution details.".html_safe) % { vulnerability_link: "[#{vulnerability.id}|#{vulnerability_url(vulnerability)}]" } %>
...@@ -59,17 +59,17 @@ h3. <%= _("Scanner") %>: ...@@ -59,17 +59,17 @@ h3. <%= _("Scanner") %>:
* <%= _("Name") %>: <%= vulnerability.scanner[:name] %> * <%= _("Name") %>: <%= vulnerability.scanner[:name] %>
<% end %> <% end %>
<% if vulnerability.scan.present? %> <% if vulnerability.scan.present? %>
<% if vulnerability.scan[:type].present? %> <% if vulnerability.scan.type.present? %>
* <%= _("Type") %>: <%= vulnerability.scan[:type] %> * <%= _("Type") %>: <%= vulnerability.scan.type %>
<% end %> <% end %>
<% if vulnerability.scan[:status].present? %> <% if vulnerability.scan.status.present? %>
* <%= _("Status") %>: <%= vulnerability.scan[:status] %> * <%= _("Status") %>: <%= vulnerability.scan.status %>
<% end %> <% end %>
<% if vulnerability.scan[:start_time].present? %> <% if vulnerability.scan.start_time.present? %>
* <%= _("Start Time") %>: <%= vulnerability.scan[:start_time] %> * <%= _("Start Time") %>: <%= vulnerability.scan.start_time %>
<% end %> <% end %>
<% if vulnerability.scan[:end_time].present? %> <% if vulnerability.scan.end_time.present? %>
* <%= _("End Time") %>: <%= vulnerability.scan[:end_time] %> * <%= _("End Time") %>: <%= vulnerability.scan.end_time %>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
...@@ -41,6 +41,8 @@ RSpec.describe VulnerabilitiesHelper do ...@@ -41,6 +41,8 @@ RSpec.describe VulnerabilitiesHelper do
:solution) :solution)
end end
let(:desired_serializer_fields) { %i[metadata identifiers name issue_feedback merge_request_feedback project project_fingerprint scanner] }
before do before do
vulnerability_serializer_stub = instance_double("VulnerabilitySerializer") vulnerability_serializer_stub = instance_double("VulnerabilitySerializer")
expect(VulnerabilitySerializer).to receive(:new).and_return(vulnerability_serializer_stub) expect(VulnerabilitySerializer).to receive(:new).and_return(vulnerability_serializer_stub)
...@@ -48,7 +50,7 @@ RSpec.describe VulnerabilitiesHelper do ...@@ -48,7 +50,7 @@ RSpec.describe VulnerabilitiesHelper do
finding_serializer_stub = instance_double("Vulnerabilities::FindingSerializer") finding_serializer_stub = instance_double("Vulnerabilities::FindingSerializer")
expect(Vulnerabilities::FindingSerializer).to receive(:new).and_return(finding_serializer_stub) expect(Vulnerabilities::FindingSerializer).to receive(:new).and_return(finding_serializer_stub)
expect(finding_serializer_stub).to receive(:represent).with(finding).and_return(finding_serializer_hash) expect(finding_serializer_stub).to receive(:represent).with(finding, only: desired_serializer_fields).and_return(finding_serializer_hash)
end end
around do |example| around do |example|
...@@ -227,7 +229,7 @@ RSpec.describe VulnerabilitiesHelper do ...@@ -227,7 +229,7 @@ RSpec.describe VulnerabilitiesHelper do
subject { helper.vulnerability_finding_data(vulnerability) } subject { helper.vulnerability_finding_data(vulnerability) }
it 'returns finding information' do it 'returns finding information' do
expect(subject).to match( expect(subject.to_h).to match(
description: finding.description, description: finding.description,
identifiers: kind_of(Array), identifiers: kind_of(Array),
issue_feedback: anything, issue_feedback: anything,
......
...@@ -6,6 +6,12 @@ RSpec.describe Vulnerabilities::FindingPresenter do ...@@ -6,6 +6,12 @@ RSpec.describe Vulnerabilities::FindingPresenter do
let(:presenter) { described_class.new(occurrence) } let(:presenter) { described_class.new(occurrence) }
let(:occurrence) { build_stubbed(:vulnerabilities_finding) } let(:occurrence) { build_stubbed(:vulnerabilities_finding) }
describe '#title' do
subject { presenter.title }
it { is_expected.to eq occurrence.name }
end
describe '#blob_path' do describe '#blob_path' do
subject { presenter.blob_path } subject { presenter.blob_path }
......
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::FindingEntity do RSpec.describe Vulnerabilities::FindingEntity do
let_it_be(:user) { build(:user) } let_it_be(:user) { build(:user) }
let_it_be(:project) { build(:project) } let_it_be_with_refind(:project) { create(:project) }
let(:scanner) { build(:vulnerabilities_scanner, project: project) } let(:scanner) { build(:vulnerabilities_scanner, project: project) }
...@@ -67,6 +67,7 @@ RSpec.describe Vulnerabilities::FindingEntity do ...@@ -67,6 +67,7 @@ RSpec.describe Vulnerabilities::FindingEntity do
end end
it 'does not contain vulnerability feedback paths' do it 'does not contain vulnerability feedback paths' do
expect(subject[:create_jira_issue_url]).to be_falsey
expect(subject[:create_vulnerability_feedback_issue_path]).to be_falsey expect(subject[:create_vulnerability_feedback_issue_path]).to be_falsey
expect(subject[:create_vulnerability_feedback_merge_request_path]).to be_falsey expect(subject[:create_vulnerability_feedback_merge_request_path]).to be_falsey
expect(subject[:create_vulnerability_feedback_dismissal_path]).to be_falsey expect(subject[:create_vulnerability_feedback_dismissal_path]).to be_falsey
...@@ -78,6 +79,10 @@ RSpec.describe Vulnerabilities::FindingEntity do ...@@ -78,6 +79,10 @@ RSpec.describe Vulnerabilities::FindingEntity do
project.add_developer(user) project.add_developer(user)
end end
it 'does not contain create jira issue path' do
expect(subject[:create_jira_issue_url]).to be_falsey
end
it 'contains vulnerability feedback dismissal path' do it 'contains vulnerability feedback dismissal path' do
expect(subject).to include(:create_vulnerability_feedback_dismissal_path) expect(subject).to include(:create_vulnerability_feedback_dismissal_path)
end end
...@@ -90,9 +95,28 @@ RSpec.describe Vulnerabilities::FindingEntity do ...@@ -90,9 +95,28 @@ RSpec.describe Vulnerabilities::FindingEntity do
expect(subject).to include(:create_vulnerability_feedback_merge_request_path) expect(subject).to include(:create_vulnerability_feedback_merge_request_path)
end end
context 'when jira service is configured' do
let_it_be(:jira_service) { create(:jira_service, project: project, issues_enabled: true, project_key: 'FE', vulnerabilities_enabled: true, vulnerabilities_issuetype: '10001') }
before do
stub_licensed_features(jira_vulnerabilities_integration: true)
allow_next_found_instance_of(JiraService) do |jira|
allow(jira).to receive(:jira_project_id).and_return('11223')
end
end
it 'does contains create jira issue path' do
expect(subject[:create_jira_issue_url]).to be_present
end
end
context 'when disallowed to create issue' do context 'when disallowed to create issue' do
let(:project) { create(:project, issues_access_level: ProjectFeature::DISABLED) } let(:project) { create(:project, issues_access_level: ProjectFeature::DISABLED) }
it 'does not contain create jira issue path' do
expect(subject[:create_jira_issue_url]).to be_falsey
end
it 'does not contain vulnerability feedback issue path' do it 'does not contain vulnerability feedback issue path' do
expect(subject[:create_vulnerability_feedback_issue_path]).to be_falsey expect(subject[:create_vulnerability_feedback_issue_path]).to be_falsey
end end
...@@ -109,6 +133,10 @@ RSpec.describe Vulnerabilities::FindingEntity do ...@@ -109,6 +133,10 @@ RSpec.describe Vulnerabilities::FindingEntity do
context 'when disallowed to create merge_request' do context 'when disallowed to create merge_request' do
let(:project) { create(:project, merge_requests_access_level: ProjectFeature::DISABLED) } let(:project) { create(:project, merge_requests_access_level: ProjectFeature::DISABLED) }
it 'does not contain create jira issue path' do
expect(subject[:create_jira_issue_url]).to be_falsey
end
it 'does not contain vulnerability feedback merge_request path' do it 'does not contain vulnerability feedback merge_request path' do
expect(subject[:create_vulnerability_feedback_merge_request_path]).to be_falsey expect(subject[:create_vulnerability_feedback_merge_request_path]).to be_falsey
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