Commit 436fa8d2 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch '227878-add-new-security-charts-page' into 'master'

Add new security charts page

See merge request gitlab-org/gitlab!38088
parents 4b662d49 3b51f3dd
......@@ -93,25 +93,14 @@ NOTE: **Note:**
The Security Dashboard only shows projects with [security reports](#supported-reports) enabled in a
group.
![Dashboard with action buttons and metrics](img/group_security_dashboard_v13_2_noNav.png)
![Dashboard with action buttons and metrics](img/group_security_dashboard_v13_3.png)
You can filter which vulnerabilities the Security Dashboard displays by:
- Status
- Severity
- Scanner
- Project
A table lists the vulnerabilities, sorted by severity. The table shows each vulnerability's status,
severity, and description. Clicking a vulnerability takes you to its [Vulnerability Details](../vulnerabilities)
page to view more information about that vulnerability.
Next to the list is a timeline chart that shows how many open
There is a timeline chart that shows how many open
vulnerabilities your projects had at various points in time. You can filter among 30, 60, and
90 days, with the default being 90. Hover over the chart to get more details about
the open vulnerabilities at a specific time.
Below the timeline chart is a list of projects, grouped and sorted by the severity of the vulnerability found:
Next to the timeline chart is a list of projects, grouped and sorted by the severity of the vulnerability found:
- F: 1 or more "critical"
- D: 1 or more "high" or "unknown"
......@@ -122,7 +111,7 @@ Below the timeline chart is a list of projects, grouped and sorted by the severi
Projects with no vulnerability tests configured will not appear in the list. Additionally, dismissed
vulnerabilities are not included either.
Read more on how to [interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
Navigate to the group's [Vulnerability Report](#vulnerability-list) to view the vulnerabilities found.
## Instance Security Dashboard
......@@ -200,8 +189,19 @@ to configure daily security scans.
Each dashboard's vulnerability list contains vulnerabilities from the latest scans that were merged
into the default branch.
Click any vulnerability in the table to see more information on that vulnerability. To create an
issue associated with the vulnerability, click the **Create Issue** button.
![Vulnerability Report](img/group_vulnerability_report_v13_3.png)
You can filter which vulnerabilities the Security Dashboard displays by:
- Status
- Severity
- Scanner
- Project
Clicking any vulnerability in the table takes you to its
[Vulnerability Details](../vulnerabilities) page to see more information on that vulnerability.
To create an issue associated with the vulnerability, click the **Create Issue** button.
![Create an issue for the vulnerability](img/standalone_vulnerability_page_v13_1.png)
......@@ -221,3 +221,5 @@ questions that you know someone might ask.
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->
Read more on how to [interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
import initFirstClassSecurityDashboard from 'ee/security_dashboard/first_class_init';
import initSecurityCharts from 'ee/security_dashboard/security_charts_init';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
document.addEventListener('DOMContentLoaded', () => {
initFirstClassSecurityDashboard(
document.getElementById('js-group-security-dashboard'),
DASHBOARD_TYPES.GROUP,
);
initSecurityCharts(document.getElementById('js-group-security-dashboard'), DASHBOARD_TYPES.GROUP);
});
import initFirstClassSecurityDashboard from 'ee/security_dashboard/first_class_init';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
document.addEventListener('DOMContentLoaded', () => {
initFirstClassSecurityDashboard(
document.getElementById('js-group-vulnerabilities'),
DASHBOARD_TYPES.GROUP,
);
});
......@@ -3,18 +3,13 @@ import { GlLoadingIcon } from '@gitlab/ui';
import SecurityDashboardLayout from 'ee/security_dashboard/components/security_dashboard_layout.vue';
import GroupSecurityVulnerabilities from 'ee/security_dashboard/components/first_class_group_security_dashboard_vulnerabilities.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import VulnerabilityChart from 'ee/security_dashboard/components/first_class_vulnerability_chart.vue';
import CsvExportButton from './csv_export_button.vue';
import VulnerabilitySeverity from './vulnerability_severity.vue';
import vulnerabilityHistoryQuery from '../graphql/group_vulnerability_history.query.graphql';
import DashboardNotConfigured from './empty_states/group_dashboard_not_configured.vue';
export default {
components: {
SecurityDashboardLayout,
GroupSecurityVulnerabilities,
VulnerabilitySeverity,
VulnerabilityChart,
Filters,
CsvExportButton,
DashboardNotConfigured,
......@@ -25,10 +20,6 @@ export default {
type: String,
required: true,
},
vulnerableProjectsEndpoint: {
type: String,
required: true,
},
vulnerabilitiesExportEndpoint: {
type: String,
required: true,
......@@ -39,7 +30,6 @@ export default {
filters: {},
projects: [],
projectsWereFetched: false,
vulnerabilityHistoryQuery,
};
},
computed: {
......@@ -67,7 +57,7 @@ export default {
<template #header>
<header class="page-title-holder flex-fill d-flex align-items-center">
<h2 class="page-title flex-grow">
{{ s__('SecurityReports|Group Security Dashboard') }}
{{ s__('SecurityReports|Vulnerability Report') }}
</h2>
<csv-export-button :vulnerabilities-export-endpoint="vulnerabilitiesExportEndpoint" />
</header>
......@@ -80,14 +70,6 @@ export default {
:filters="filters"
@projectFetch="handleProjectsFetch"
/>
<template #aside>
<vulnerability-chart
:query="vulnerabilityHistoryQuery"
:group-full-path="groupFullPath"
class="mb-4"
/>
<vulnerability-severity :endpoint="vulnerableProjectsEndpoint" />
</template>
</security-dashboard-layout>
</div>
</template>
......@@ -10,7 +10,7 @@ export default {
<template functional>
<div>
<h1>{{ $options.i18n.title }}</h1>
<h2>{{ $options.i18n.title }}</h2>
<div class="security-charts gl-display-flex gl-flex-wrap">
<slot></slot>
</div>
......
......@@ -9,7 +9,6 @@ class Groups::Security::DashboardController < Groups::ApplicationController
private
def dashboard_available?
group.feature_available?(:security_dashboard) &&
can?(current_user, :read_group_security_dashboard, group)
end
end
# frozen_string_literal: true
module Groups
module Security
class VulnerabilitiesController < Groups::ApplicationController
layout 'group'
def index
render :unavailable unless dashboard_available?
end
private
def dashboard_available?
can?(current_user, :read_group_security_dashboard, group)
end
end
end
end
......@@ -14,4 +14,12 @@ module SecurityHelper
vulnerabilities_export_endpoint: expose_path(api_v4_security_vulnerability_exports_path)
}
end
def security_dashboard_unavailable_view_data
{
empty_state_svg_path: image_path('illustrations/security-dashboard-empty-state.svg'),
dashboard_documentation: help_page_path('user/application_security/security_dashboard/index'),
is_unavailable: "true"
}
end
end
- breadcrumb_title _("Security Dashboard")
- page_title _("Security Dashboard")
#js-group-security-dashboard{ data: { is_unavailable: "true",
empty_state_svg_path: image_path('illustrations/security-dashboard-empty-state.svg'),
dashboard_documentation: help_page_path('user/application_security/security_dashboard/index') } }
#js-group-security-dashboard{ data: security_dashboard_unavailable_view_data }
- breadcrumb_title _("Vulnerability Report")
- page_title _("Vulnerability Report")
#js-group-vulnerabilities{ data: group_level_security_dashboard_data(@group) }
- breadcrumb_title _("Vulnerability Report")
- page_title _("Vulnerability Report")
#js-group-vulnerabilities{ data: security_dashboard_unavailable_view_data }
- main_path = primary_group_level_security_feature_path(@group)
- if main_path.present?
= nav_link(path: %w[dashboard#show compliance_dashboards#show credentials#index]) do
= nav_link(path: %w[dashboard#show vulnerabilities#index compliance_dashboards#show credentials#index]) do
= link_to main_path, data: { qa_selector: 'security_compliance_link' } do
.nav-icon-container
= sprite_icon('shield')
......@@ -9,8 +9,13 @@
%ul.sidebar-sub-level-items{ data: { qa_selector: 'group_secure_submenu' } }
- if group_level_security_dashboard_available?(@group)
= nav_link(path: 'dashboard#show') do
= link_to group_security_dashboard_path(@group), title: _('Security'), data: { qa_selector: 'security_dashboard_link' } do
%span= _('Security')
= link_to group_security_dashboard_path(@group), title: _('Security Dashboard'), data: { qa_selector: 'security_dashboard_link' } do
%span= _('Security Dashboard')
- if group_level_security_dashboard_available?(@group)
= nav_link(path: 'vulnerabilities#index') do
= link_to group_security_vulnerabilities_path(@group), title: _('Vulnerability Report') do
%span= _('Vulnerability Report')
- if group_level_compliance_dashboard_available?(@group)
= nav_link(path: 'compliance_dashboards#show') do
......
---
title: Add new security charts page and unavailable view
merge_request: 38088
author:
type: changed
......@@ -147,6 +147,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
namespace :security do
resource :dashboard, only: [:show], controller: :dashboard
resources :vulnerabilities, only: [:index]
resource :compliance_dashboard, only: [:show]
resources :vulnerable_projects, only: [:index]
resource :discover, only: [:show], controller: :discover
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::Security::VulnerabilitiesController do
let(:user) { create(:user) }
let(:group) { create(:group) }
before do
sign_in(user)
end
describe 'GET index' do
subject { get :index, params: { group_id: group.to_param } }
context 'when security dashboard feature is enabled' do
before do
stub_licensed_features(security_dashboard: true)
end
context 'and user is allowed to access group security vulnerabilities' do
before do
group.add_developer(user)
end
it { is_expected.to have_gitlab_http_status(:ok) }
end
context 'when user is not allowed to access group security vulnerabilities' do
it { is_expected.to have_gitlab_http_status(:ok) }
it { is_expected.to render_template(:unavailable) }
end
end
context 'when security dashboard feature is disabled' do
it { is_expected.to have_gitlab_http_status(:ok) }
it { is_expected.to render_template(:unavailable) }
end
end
end
......@@ -158,7 +158,8 @@ RSpec.describe 'Group navbar' do
new_nav_item: {
nav_item: _('Security & Compliance'),
nav_sub_items: [
_('Security'),
_('Security Dashboard'),
_('Vulnerability Report'),
_('Compliance')
]
}
......
......@@ -3,8 +3,6 @@ import { GlLoadingIcon } from '@gitlab/ui';
import SecurityDashboardLayout from 'ee/security_dashboard/components/security_dashboard_layout.vue';
import FirstClassGroupDashboard from 'ee/security_dashboard/components/first_class_group_security_dashboard.vue';
import FirstClassGroupVulnerabilities from 'ee/security_dashboard/components/first_class_group_security_dashboard_vulnerabilities.vue';
import VulnerabilitySeverity from 'ee/security_dashboard/components/vulnerability_severity.vue';
import VulnerabilityChart from 'ee/security_dashboard/components/first_class_vulnerability_chart.vue';
import DashboardNotConfigured from 'ee/security_dashboard/components/empty_states/group_dashboard_not_configured.vue';
import CsvExportButton from 'ee/security_dashboard/components/csv_export_button.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
......@@ -20,8 +18,6 @@ describe('First Class Group Dashboard Component', () => {
const findDashboardLayout = () => wrapper.find(SecurityDashboardLayout);
const findGroupVulnerabilities = () => wrapper.find(FirstClassGroupVulnerabilities);
const findVulnerabilitySeverity = () => wrapper.find(VulnerabilitySeverity);
const findVulnerabilityChart = () => wrapper.find(VulnerabilityChart);
const findCsvExportButton = () => wrapper.find(CsvExportButton);
const findFilters = () => wrapper.find(Filters);
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
......@@ -83,10 +79,6 @@ describe('First Class Group Dashboard Component', () => {
expect(findFilters().exists()).toBe(true);
});
it('has the vulnerability history chart', () => {
expect(findVulnerabilityChart().props('groupFullPath')).toBe(groupFullPath);
});
it('responds to the projectFetch event', () => {
const projects = [{ id: 1, name: 'GitLab Org' }];
findGroupVulnerabilities().vm.$listeners.projectFetch(projects);
......@@ -104,10 +96,6 @@ describe('First Class Group Dashboard Component', () => {
});
});
it('displays the vulnerability severity in an aside', () => {
expect(findVulnerabilitySeverity().exists()).toBe(true);
});
it('displays the csv export button', () => {
expect(findCsvExportButton().props('vulnerabilitiesExportEndpoint')).toBe(
vulnerabilitiesExportEndpoint,
......
......@@ -25,6 +25,10 @@ RSpec.describe 'Group routing', "routing" do
it 'shows group dashboard' do
expect(get('/groups/gitlabhq/-/security/dashboard')).to route_to('groups/security/dashboard#show', group_id: 'gitlabhq')
end
it 'shows vulnerability list' do
expect(get('/groups/gitlabhq/-/security/vulnerabilities')).to route_to('groups/security/vulnerabilities#index', group_id: 'gitlabhq')
end
end
describe 'dependency proxy for containers' do
......
......@@ -21507,9 +21507,6 @@ msgstr ""
msgid "SecurityReports|Fuzzing artifacts"
msgstr ""
msgid "SecurityReports|Group Security Dashboard"
msgstr ""
msgid "SecurityReports|Hide dismissed"
msgstr ""
......@@ -21636,6 +21633,9 @@ msgstr ""
msgid "SecurityReports|Undo dismiss"
msgstr ""
msgid "SecurityReports|Vulnerability Report"
msgstr ""
msgid "SecurityReports|While it's rare to have no vulnerabilities for your pipeline, it can happen. In any event, we ask that you double check your settings to make sure all security scanning jobs have passed successfully."
msgstr ""
......@@ -27025,6 +27025,9 @@ msgstr ""
msgid "Vulnerabilities over time"
msgstr ""
msgid "Vulnerability Report"
msgstr ""
msgid "Vulnerability remediated. Review before resolving."
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