Commit a3788157 authored by Robert Speicher's avatar Robert Speicher

Merge branch '209994-add-link-when-issue-is-created-from-vulnerability' into 'master'

Create vulnerability issue link when creating issue from vulnerability

See merge request gitlab-org/gitlab!27899
parents 7df75cf1 5b5e2cc2
......@@ -87,7 +87,11 @@ export default {
feedback_type: 'issue',
category: this.vulnerability.report_type,
project_fingerprint: this.projectFingerprint,
vulnerability_data: { ...this.vulnerability, category: this.vulnerability.report_type },
vulnerability_data: {
...this.vulnerability,
category: this.vulnerability.report_type,
vulnerability_id: this.vulnerability.id,
},
},
})
.then(({ data: { issue_url } }) => {
......
......@@ -137,6 +137,7 @@ class Projects::VulnerabilityFeedbackController < Projects::ApplicationControlle
tool
tools
url
vulnerability_id
wascid
] + [
instances: %i[
......
......@@ -65,6 +65,14 @@ module VulnerabilityFeedback
end
issue = result[:issue]
issue_link_result = create_vulnerability_issue_link(vulnerability_feedback.vulnerability_data[:vulnerability_id], issue)
if issue_link_result&.error?
vulnerability_feedback.errors[:issue_link] << issue_link_result.message
raise ActiveRecord::Rollback
end
vulnerability_feedback.issue = issue
# Ensure created association is rolled back if feedback can't be saved
......@@ -95,5 +103,17 @@ module VulnerabilityFeedback
merge_request&.destroy &&
::Branches::DeleteService.new(project, current_user).execute(branch_name)
end
def create_vulnerability_issue_link(vulnerability_id, issue)
return unless vulnerability_id
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :read_vulnerability, project)
vulnerability = project.vulnerabilities.find_by_id(vulnerability_id)
VulnerabilityIssueLinks::CreateService
.new(current_user, vulnerability, issue, link_type: Vulnerabilities::IssueLink.link_types[:created])
.execute
end
end
end
---
title: Create issue link when creating issue from vulnerability
merge_request: 27899
author:
type: added
......@@ -150,6 +150,30 @@ describe Projects::VulnerabilityFeedbackController do
expect(response).to match_response_schema('vulnerability_feedback', dir: 'ee')
end
context 'when id of finding is not provided' do
subject { create_feedback user: user, project: project, params: create_params.deep_merge(feedback_type: 'issue', vulnerability_data: { vulnerability_id: nil }) }
it 'creates no vulnerability issue link for related vulnerability' do
expect { subject }.not_to change { Vulnerabilities::IssueLink.count }
end
end
context 'when security dashboard feature enabled' do
before do
stub_licensed_features(security_dashboard: true)
end
context 'when id of finding is provided' do
let!(:vulnerability) { create(:vulnerability, :with_findings, project: project) }
subject { create_feedback user: user, project: project, params: create_params.deep_merge(feedback_type: 'issue', vulnerability_data: { vulnerability_id: vulnerability.id }) }
it 'creates vulnerability issue link for related vulnerability' do
expect { subject }.to change { Vulnerabilities::IssueLink.count }.by(1)
end
end
end
end
context 'with invalid params' do
......
......@@ -113,6 +113,7 @@ describe('Vulnerability management app', () => {
vulnerability_data: {
...defaultVulnerability,
category: defaultVulnerability.report_type,
vulnerability_id: defaultVulnerability.id,
},
},
});
......
......@@ -130,6 +130,124 @@ describe VulnerabilityFeedback::CreateService, '#execute' do
expect(result[:status]).to eq(:success)
end
context 'id of vulnerability is provided in vulnerability_data params' do
before do
stub_licensed_features(security_dashboard: true)
end
let(:feedback_params_with_vulnerability_id) do
feedback_params.deep_merge(
feedback_type: 'issue',
vulnerability_data: { vulnerability_id: vulnerability_id }
)
end
subject(:result) { described_class.new(project, user, feedback_params_with_vulnerability_id).execute }
context 'when id is missing' do
let(:vulnerability_id) { nil }
it 'does not create new Vulnerabilities::IssueLink' do
expect { subject }.not_to change { Vulnerabilities::IssueLink.count }
end
it 'creates the feedback' do
expect(result[:status]).to eq(:success)
expect(result[:vulnerability_feedback]).to be_persisted
end
end
context 'when id is invalid' do
let(:vulnerability_id) { 9999 }
it 'raises Gitlab::Access::AccessDeniedError' do
expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'when id belongs to other project' do
let(:vulnerability) { create(:vulnerability, :with_findings) }
let(:vulnerability_id) { vulnerability.id }
it 'raises Gitlab::Access::AccessDeniedError' do
expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'when id is valid' do
let(:vulnerability) { create(:vulnerability, :with_findings, project: project) }
let(:vulnerability_id) { vulnerability.id }
let(:last_issue_link) { Vulnerabilities::IssueLink.last }
let(:last_vulnerability_feedback) { Vulnerabilities::Feedback.last }
it 'delegates issue link creation to VulnerabilityIssueLinks::CreateService' do
expect(VulnerabilityIssueLinks::CreateService).to(receive(:new)
.with(user, vulnerability, anything, link_type: Vulnerabilities::IssueLink.link_types[:created])
.once
.and_call_original)
expect(result[:status]).to eq(:success)
end
it 'delegates work to VulnerabilityIssueLinks::CreateService' do
expect_next_instance_of(VulnerabilityIssueLinks::CreateService) do |instance|
expect(instance).to receive(:execute).with(no_args).once.and_call_original
end
expect(result[:status]).to eq(:success)
end
it 'issue link has correctly set vulnerability and link type' do
subject
expect(last_issue_link).to be_created
expect(last_issue_link.vulnerability).to eq(vulnerability)
expect(last_issue_link.issue).to eq(last_vulnerability_feedback.issue)
end
it 'creates the feedback' do
expect(result[:status]).to eq(:success)
expect(result[:vulnerability_feedback]).to be_persisted
end
context 'when issue link is already created' do
context 'when feedback does not exist' do
let!(:issue_link) { create(:vulnerabilities_issue_link, :created, vulnerability: vulnerability) }
it 'does not create new issue link' do
expect { subject }.not_to change { Vulnerabilities::IssueLink.count }
end
it 'does not create new issue' do
expect { subject }.not_to change { Issue.count }
end
it 'does not create a feedback' do
expect(result[:status]).to eq(:error)
end
end
context 'when feedback already exists' do
let!(:vulnerability_feedback) { create(:vulnerability_feedback, :issue, :comment, project: project, author: user, **feedback_params_with_vulnerability_id) }
let!(:issue_link) { create(:vulnerabilities_issue_link, :created, vulnerability: vulnerability, issue: vulnerability_feedback.issue) }
it 'does not create new issue link' do
expect { subject }.not_to change { Vulnerabilities::IssueLink.count }
end
it 'does not create new issue' do
expect { subject }.not_to change { Issue.count }
end
it 'returns the feedback' do
expect(result[:status]).to eq(:success)
expect(result[:vulnerability_feedback]).to be_persisted
end
end
end
end
end
end
context 'when feedback_type is merge_request' do
......
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