Commit b3d9ec37 authored by Can Eldem's avatar Can Eldem Committed by Lin Jen-Shin

Expose fields matching with FE

Change payload to match with vulnerability api
Update tests
parent c3aa5a68
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
module Security module Security
class PipelineVulnerabilitiesFinder class PipelineVulnerabilitiesFinder
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
ParseError = Class.new(Gitlab::Ci::Parsers::ParserError)
attr_accessor :params attr_accessor :params
attr_reader :pipeline attr_reader :pipeline
...@@ -31,6 +32,10 @@ module Security ...@@ -31,6 +32,10 @@ module Security
occurrences.concat(filtered_occurrences) occurrences.concat(filtered_occurrences)
end end
# Created follow-up issue to better handle exception case - https://gitlab.com/gitlab-org/gitlab-ee/issues/14007
rescue NoMethodError => _ # propagate error for CompareReportsBaseService
raise ParseError, 'JSON parsing failed'
end end
private private
......
...@@ -182,5 +182,24 @@ module Vulnerabilities ...@@ -182,5 +182,24 @@ module Vulnerabilities
def remediations def remediations
metadata.dig('remediations') metadata.dig('remediations')
end end
alias_method :==, :eql? # eql? is necessary in some cases like array intersection
def eql?(other)
other.report_type == report_type &&
other.location == location &&
other.first_fingerprint == first_fingerprint
end
# Array.difference (-) method uses hash and eql? methods to do comparison
def hash
report_type.hash ^ location.hash ^ first_fingerprint.hash
end
protected
def first_fingerprint
identifiers.first&.fingerprint
end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
class Vulnerabilities::OccurrenceReportsComparerEntity < Grape::Entity class Vulnerabilities::OccurrenceReportsComparerEntity < Grape::Entity
expose :added, using: Vulnerabilities::OccurrenceReportEntity expose :added, using: Vulnerabilities::OccurrenceEntity
expose :fixed, using: Vulnerabilities::OccurrenceReportEntity expose :fixed, using: Vulnerabilities::OccurrenceEntity
expose :existing, using: Vulnerabilities::OccurrenceReportEntity expose :existing, using: Vulnerabilities::OccurrenceEntity
end end
...@@ -36,5 +36,8 @@ class Vulnerabilities::OccurrenceEntity < Grape::Entity ...@@ -36,5 +36,8 @@ class Vulnerabilities::OccurrenceEntity < Grape::Entity
end end
alias_method :occurrence, :object alias_method :occurrence, :object
delegate :current_user, to: :request
def current_user
return request.current_user if request.respond_to?(:current_user)
end
end end
...@@ -11,11 +11,7 @@ module Ci ...@@ -11,11 +11,7 @@ module Ci
end end
def get_report(pipeline) def get_report(pipeline)
report = pipeline&.security_reports&.get_report('container_scanning') Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[container_scanning] }).execute
raise report.error if report&.errored? # propagate error to base class's execute method
report
end end
end end
end end
...@@ -11,11 +11,7 @@ module Ci ...@@ -11,11 +11,7 @@ module Ci
end end
def get_report(pipeline) def get_report(pipeline)
report = pipeline&.security_reports&.get_report('dependency_scanning') Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[dependency_scanning] }).execute
raise report.error if report&.errored? # propagate error to base class's execute method
report
end end
end end
end end
...@@ -11,11 +11,7 @@ module Ci ...@@ -11,11 +11,7 @@ module Ci
end end
def get_report(pipeline) def get_report(pipeline)
report = pipeline&.security_reports&.get_report('sast') Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[sast] }).execute
raise report.error if report&.errored? # propagate error to base class's execute method
report
end end
end end
end end
---
title: Change payload for comparing security reports in MR widget
merge_request: 15531
author:
type: fixed
...@@ -10,25 +10,25 @@ module Gitlab ...@@ -10,25 +10,25 @@ module Gitlab
attr_reader :base_report, :head_report attr_reader :base_report, :head_report
def initialize(base_report, head_report) def initialize(base_report, head_report)
@base_report = base_report || ::Gitlab::Ci::Reports::Security::Report.new(head_report&.type, '') @base_report = base_report || []
@head_report = head_report @head_report = head_report
end end
def added def added
strong_memoize(:added) do strong_memoize(:added) do
head_report.occurrences - base_report.occurrences head_report - base_report
end end
end end
def fixed def fixed
strong_memoize(:fixed) do strong_memoize(:fixed) do
base_report.occurrences - head_report.occurrences base_report - head_report
end end
end end
def existing def existing
strong_memoize(:existing) do strong_memoize(:existing) do
base_report.occurrences & head_report.occurrences base_report & head_report
end end
end end
end end
......
...@@ -4,12 +4,16 @@ require 'spec_helper' ...@@ -4,12 +4,16 @@ require 'spec_helper'
describe Vulnerabilities::OccurrenceReportsComparerEntity do describe Vulnerabilities::OccurrenceReportsComparerEntity do
describe 'container scanning report comparison' do describe 'container scanning report comparison' do
let!(:base_pipeline) { create(:ee_ci_pipeline, :with_container_scanning_report) } set(:user) { create(:user) }
let!(:head_pipeline) { create(:ee_ci_pipeline, :with_container_scanning_feature_branch) }
let(:base_report) { base_pipeline.security_reports.get_report('container_scanning')} let(:base_report) { create_list(:vulnerabilities_occurrence, 2) }
let(:head_report) { head_pipeline.security_reports.get_report('container_scanning')} let(:head_report) { create_list(:vulnerabilities_occurrence, 1) }
let(:comparer) { Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report) } let(:comparer) { Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report) }
let(:entity) { described_class.new(comparer) }
let(:request) { double('request') }
let(:entity) { described_class.new(comparer, request: request) }
before do before do
stub_licensed_features(container_scanning: true) stub_licensed_features(container_scanning: true)
...@@ -18,24 +22,11 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do ...@@ -18,24 +22,11 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
describe '#as_json' do describe '#as_json' do
subject { entity.as_json } subject { entity.as_json }
it 'contains the added existing and fixed vulnerabilities for container scanning' do before do
expect(subject.keys).to match_array([:added, :existing, :fixed]) allow(request).to receive(:current_user).and_return(user)
end end
end
end
describe 'sast report comparison' do
let!(:base_pipeline) { create(:ee_ci_pipeline, :with_sast_report) }
let!(:head_pipeline) { create(:ee_ci_pipeline, :with_sast_feature_branch) }
let(:base_report) { base_pipeline.security_reports.get_report('sast')}
let(:head_report) { head_pipeline.security_reports.get_report('sast')}
let(:comparer) { Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report) }
let(:entity) { described_class.new(comparer) }
describe '#as_json' do it 'contains the added existing and fixed vulnerabilities for container scanning' do
subject { entity.as_json }
it 'contains the added existing and fixed vulnerabilities for sast' do
expect(subject.keys).to match_array([:added, :existing, :fixed]) expect(subject.keys).to match_array([:added, :existing, :fixed])
end end
end end
......
...@@ -33,7 +33,7 @@ describe Ci::CompareContainerScanningReportsService do ...@@ -33,7 +33,7 @@ describe Ci::CompareContainerScanningReportsService do
it 'reports new vulnerability' do it 'reports new vulnerability' do
expect(subject[:data]['added'].count).to eq(1) expect(subject[:data]['added'].count).to eq(1)
expect(subject[:data]['added']).to include(a_hash_including('compare_key' => 'CVE-2017-15650')) expect(subject[:data]['added'].first['identifiers']).to include(a_hash_including('external_id' => 'CVE-2017-15650'))
end end
it 'reports existing container vulnerabilities' do it 'reports existing container vulnerabilities' do
...@@ -42,7 +42,7 @@ describe Ci::CompareContainerScanningReportsService do ...@@ -42,7 +42,7 @@ describe Ci::CompareContainerScanningReportsService do
it 'reports fixed container scanning vulnerabilities' do it 'reports fixed container scanning vulnerabilities' do
expect(subject[:data]['fixed'].count).to eq(8) expect(subject[:data]['fixed'].count).to eq(8)
compare_keys = subject[:data]['fixed'].map { |t| t['compare_key'] } compare_keys = subject[:data]['fixed'].map { |t| t['identifiers'].first['external_id'] }
expected_keys = %w(CVE-2017-16997 CVE-2017-18269 CVE-2018-1000001 CVE-2016-10228 CVE-2010-4052 CVE-2018-18520 CVE-2018-16869 CVE-2018-18311) expected_keys = %w(CVE-2017-16997 CVE-2017-18269 CVE-2018-1000001 CVE-2016-10228 CVE-2010-4052 CVE-2018-18520 CVE-2018-16869 CVE-2018-18311)
expect(compare_keys - expected_keys).to eq([]) expect(compare_keys - expected_keys).to eq([])
end end
......
...@@ -35,7 +35,7 @@ describe Ci::CompareDependencyScanningReportsService do ...@@ -35,7 +35,7 @@ describe Ci::CompareDependencyScanningReportsService do
it 'reports fixed vulnerability' do it 'reports fixed vulnerability' do
expect(subject[:data]['added'].count).to eq(1) expect(subject[:data]['added'].count).to eq(1)
expect(subject[:data]['added']).to include(a_hash_including('compare_key' => 'Gemfile.lock:rubyzip:cve:CVE-2017-5946')) expect(subject[:data]['added'].first['identifiers']).to include(a_hash_including('external_id' => 'CVE-2017-5946'))
end end
it 'reports existing dependency vulenerabilities' do it 'reports existing dependency vulenerabilities' do
...@@ -44,8 +44,8 @@ describe Ci::CompareDependencyScanningReportsService do ...@@ -44,8 +44,8 @@ describe Ci::CompareDependencyScanningReportsService do
it 'reports fixed dependency scanning vulnerabilities' do it 'reports fixed dependency scanning vulnerabilities' do
expect(subject[:data]['fixed'].count).to eq(1) expect(subject[:data]['fixed'].count).to eq(1)
compare_keys = subject[:data]['fixed'].map { |t| t['compare_key'] } compare_keys = subject[:data]['fixed'].map { |t| t['identifiers'].first['external_id'] }
expected_keys = %w(rails/Gemfile.lock:nokogiri@1.8.0:USN-3424-1) expected_keys = %w(06565b64-486d-4326-b906-890d9915804d)
expect(compare_keys - expected_keys).to eq([]) expect(compare_keys - expected_keys).to eq([])
end end
end end
......
...@@ -36,7 +36,7 @@ describe Ci::CompareSastReportsService do ...@@ -36,7 +36,7 @@ describe Ci::CompareSastReportsService do
it 'reports new vulnerability' do it 'reports new vulnerability' do
expect(subject[:data]['added'].count).to eq(1) expect(subject[:data]['added'].count).to eq(1)
expect(subject[:data]['added']).to include(a_hash_including('compare_key' => 'c/subdir/utils.c:b466873101951fe96e1332f6728eb7010acbbd5dfc3b65d7d53571d091a06d9e:CWE-119!/CWE-120')) expect(subject[:data]['added'].first['identifiers']).to include(a_hash_including('name' => 'CWE-120'))
end end
it 'reports existing sast vulnerabilities' do it 'reports existing sast vulnerabilities' do
...@@ -45,8 +45,8 @@ describe Ci::CompareSastReportsService do ...@@ -45,8 +45,8 @@ describe Ci::CompareSastReportsService do
it 'reports fixed sast vulnerabilities' do it 'reports fixed sast vulnerabilities' do
expect(subject[:data]['fixed'].count).to eq(4) expect(subject[:data]['fixed'].count).to eq(4)
compare_keys = subject[:data]['fixed'].map { |t| t['compare_key'] } compare_keys = subject[:data]['fixed'].map { |t| t['identifiers'].first['external_id'] }
expected_keys = ['c/subdir/utils.c:b466873101951fe96e1332f6728eb7010acbbd5dfc3b65d7d53571d091a06d9e:CWE-119!/CWE-120', 'c/subdir/utils.c:bab681140fcc8fc3085b6bba74081b44ea145c1c98b5e70cf19ace2417d30770:CWE-362', 'cplusplus/src/hello.cpp:c8c6dd0afdae6814194cf0930b719f757ab7b379cf8f261e7f4f9f2f323a818a:CWE-119!/CWE-120', 'cplusplus/src/hello.cpp:331c04062c4fe0c7c486f66f59e82ad146ab33cdd76ae757ca41f392d568cbd0:CWE-120'] expected_keys = %w(char fopen strcpy char)
expect(compare_keys - expected_keys).to eq([]) expect(compare_keys - expected_keys).to eq([])
end end
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