Commit 3dcc4663 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'gsd-confidence-filter' into 'master'

Adds a confidence filter to the GSD

See merge request gitlab-org/gitlab-ee!12805
parents 327306e1 b2624086
...@@ -54,6 +54,7 @@ First, navigate to the Security Dashboard found under your group's ...@@ -54,6 +54,7 @@ First, navigate to the Security Dashboard found under your group's
Once you're on the dashboard, at the top you should see a series of filters for: Once you're on the dashboard, at the top you should see a series of filters for:
- Severity - Severity
- Confidence
- Report type - Report type
- Project - Project
......
...@@ -33,6 +33,10 @@ export const BASE_FILTERS = { ...@@ -33,6 +33,10 @@ export const BASE_FILTERS = {
name: s__('ciReport|All severities'), name: s__('ciReport|All severities'),
id: 'all', id: 'all',
}, },
confidence: {
name: s__('ciReport|All confidence levels'),
id: 'all',
},
report_type: { report_type: {
name: s__('ciReport|All report types'), name: s__('ciReport|All report types'),
id: 'all', id: 'all',
......
import { SEVERITY_LEVELS, REPORT_TYPES, BASE_FILTERS } from './constants'; import { SEVERITY_LEVELS, CONFIDENCE_LEVELS, REPORT_TYPES, BASE_FILTERS } from './constants';
const optionsObjectToArray = obj => Object.entries(obj).map(([id, name]) => ({ id, name })); const optionsObjectToArray = obj => Object.entries(obj).map(([id, name]) => ({ id, name }));
...@@ -10,6 +10,12 @@ export default () => ({ ...@@ -10,6 +10,12 @@ export default () => ({
options: [BASE_FILTERS.severity, ...optionsObjectToArray(SEVERITY_LEVELS)], options: [BASE_FILTERS.severity, ...optionsObjectToArray(SEVERITY_LEVELS)],
selection: new Set(['all']), selection: new Set(['all']),
}, },
{
name: 'Confidence',
id: 'confidence',
options: [BASE_FILTERS.confidence, ...optionsObjectToArray(CONFIDENCE_LEVELS)],
selection: new Set(['all']),
},
{ {
name: 'Report type', name: 'Report type',
id: 'report_type', id: 'report_type',
......
...@@ -39,7 +39,7 @@ class Groups::Security::VulnerabilitiesController < Groups::Security::Applicatio ...@@ -39,7 +39,7 @@ class Groups::Security::VulnerabilitiesController < Groups::Security::Applicatio
private private
def filter_params def filter_params
params.permit(report_type: [], project_id: [], severity: []) params.permit(report_type: [], confidence: [], project_id: [], severity: [])
.merge(hide_dismissed: Gitlab::Utils.to_boolean(params[:hide_dismissed])) .merge(hide_dismissed: Gitlab::Utils.to_boolean(params[:hide_dismissed]))
end end
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
# group - object to filter vulnerabilities # group - object to filter vulnerabilities
# params: # params:
# severity: Array<String> # severity: Array<String>
# confidence: Array<String>
# project: Array<String> # project: Array<String>
# report_type: Array<String> # report_type: Array<String>
...@@ -26,6 +27,7 @@ module Security ...@@ -26,6 +27,7 @@ module Security
collection = by_report_type(collection) collection = by_report_type(collection)
collection = by_project(collection) collection = by_project(collection)
collection = by_severity(collection) collection = by_severity(collection)
collection = by_confidence(collection)
collection collection
end end
...@@ -53,6 +55,14 @@ module Security ...@@ -53,6 +55,14 @@ module Security
*params[:severity]).compact) *params[:severity]).compact)
end end
def by_confidence(items)
return items unless params[:confidence].present?
items.by_confidences(
Vulnerabilities::Occurrence::CONFIDENCE_LEVELS.values_at(
*params[:confidence]).compact)
end
def init_collection(scope) def init_collection(scope)
if scope == :all if scope == :all
group.all_vulnerabilities group.all_vulnerabilities
......
...@@ -79,6 +79,7 @@ module Vulnerabilities ...@@ -79,6 +79,7 @@ module Vulnerabilities
scope :by_report_types, -> (values) { where(report_type: values) } scope :by_report_types, -> (values) { where(report_type: values) }
scope :by_projects, -> (values) { where(project_id: values) } scope :by_projects, -> (values) { where(project_id: values) }
scope :by_severities, -> (values) { where(severity: values) } scope :by_severities, -> (values) { where(severity: values) }
scope :by_confidences, -> (values) { where(confidence: values) }
scope :all_preloaded, -> do scope :all_preloaded, -> do
preload(:scanner, :identifiers, project: [:namespace, :project_feature]) preload(:scanner, :identifiers, project: [:namespace, :project_feature])
......
---
title: Adds a confidence filter to the Group Security Dashboard
merge_request: 12805
author:
type: added
...@@ -10,8 +10,8 @@ describe Security::VulnerabilitiesFinder do ...@@ -10,8 +10,8 @@ describe Security::VulnerabilitiesFinder do
set(:pipeline1) { create(:ci_pipeline, :success, project: project1) } set(:pipeline1) { create(:ci_pipeline, :success, project: project1) }
set(:pipeline2) { create(:ci_pipeline, :success, project: project2) } set(:pipeline2) { create(:ci_pipeline, :success, project: project2) }
set(:vulnerability1) { create(:vulnerabilities_occurrence, report_type: :sast, severity: :high, pipelines: [pipeline1], project: project1) } set(:vulnerability1) { create(:vulnerabilities_occurrence, report_type: :sast, severity: :high, confidence: :high, pipelines: [pipeline1], project: project1) }
set(:vulnerability2) { create(:vulnerabilities_occurrence, report_type: :dependency_scanning, severity: :medium, pipelines: [pipeline2], project: project2) } set(:vulnerability2) { create(:vulnerabilities_occurrence, report_type: :dependency_scanning, severity: :medium, confidence: :low, pipelines: [pipeline2], project: project2) }
set(:vulnerability3) { create(:vulnerabilities_occurrence, report_type: :sast, severity: :low, pipelines: [pipeline2], project: project2) } set(:vulnerability3) { create(:vulnerabilities_occurrence, report_type: :sast, severity: :low, pipelines: [pipeline2], project: project2) }
set(:vulnerability4) { create(:vulnerabilities_occurrence, report_type: :dast, severity: :medium, pipelines: [pipeline1], project: project1) } set(:vulnerability4) { create(:vulnerabilities_occurrence, report_type: :dast, severity: :medium, pipelines: [pipeline1], project: project1) }
...@@ -53,6 +53,24 @@ describe Security::VulnerabilitiesFinder do ...@@ -53,6 +53,24 @@ describe Security::VulnerabilitiesFinder do
end end
end end
context 'by confidence' do
context 'when high' do
let(:params) { { confidence: %w[high] } }
it 'includes only high confidence vulnerabilities' do
is_expected.to contain_exactly(vulnerability1)
end
end
context 'when low' do
let(:params) { { confidence: %w[low] } }
it 'includes only low confidence vulnerabilities' do
is_expected.to contain_exactly(vulnerability2)
end
end
end
context 'by project' do context 'by project' do
let(:params) { { project_id: [project2.id] } } let(:params) { { project_id: [project2.id] } }
......
...@@ -18,7 +18,7 @@ describe('Filter component', () => { ...@@ -18,7 +18,7 @@ describe('Filter component', () => {
}); });
it('should display all filters', () => { it('should display all filters', () => {
expect(vm.$el.querySelectorAll('.js-filter').length).toEqual(3); expect(vm.$el.querySelectorAll('.js-filter').length).toEqual(4);
}); });
}); });
}); });
...@@ -218,7 +218,7 @@ describe Vulnerabilities::Occurrence do ...@@ -218,7 +218,7 @@ describe Vulnerabilities::Occurrence do
subject { described_class.by_severities(param) } subject { described_class.by_severities(param) }
context 'with one param' do context 'with one param' do
let(:param) { 4 } let(:param) { described_class.severities[:low] }
it 'returns found record' do it 'returns found record' do
is_expected.to contain_exactly(vulnerability_low) is_expected.to contain_exactly(vulnerability_low)
...@@ -226,7 +226,30 @@ describe Vulnerabilities::Occurrence do ...@@ -226,7 +226,30 @@ describe Vulnerabilities::Occurrence do
end end
context 'without found record' do context 'without found record' do
let(:param) { 7 } let(:param) { described_class.severities[:unknown] }
it 'returns empty collection' do
is_expected.to be_empty
end
end
end
describe '.by_confidences' do
let!(:vulnerability_high) { create(:vulnerabilities_occurrence, confidence: :high) }
let!(:vulnerability_low) { create(:vulnerabilities_occurrence, confidence: :low) }
subject { described_class.by_confidences(param) }
context 'with matching param' do
let(:param) { described_class.confidences[:low] }
it 'returns found record' do
is_expected.to contain_exactly(vulnerability_low)
end
end
context 'with non-matching param' do
let(:param) { described_class.confidences[:unknown] }
it 'returns empty collection' do it 'returns empty collection' do
is_expected.to be_empty is_expected.to be_empty
......
...@@ -14946,6 +14946,9 @@ msgstr "" ...@@ -14946,6 +14946,9 @@ msgstr ""
msgid "ciReport|(is loading, errors when loading results)" msgid "ciReport|(is loading, errors when loading results)"
msgstr "" msgstr ""
msgid "ciReport|All confidence levels"
msgstr ""
msgid "ciReport|All projects" msgid "ciReport|All projects"
msgstr "" msgstr ""
......
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