Commit b39493fc authored by Savas Vedova's avatar Savas Vedova

Export instance level vulnerabilities

- Add a button to export vulnerabilities
- Generate changelog
- Update documentation
parent 22926703
...@@ -67,7 +67,7 @@ NOTE: **Note:** ...@@ -67,7 +67,7 @@ NOTE: **Note:**
It may take several minutes for the download to start if your project consists It may take several minutes for the download to start if your project consists
of thousands of vulnerabilities. Do not close the page until the download finishes. of thousands of vulnerabilities. Do not close the page until the download finishes.
![CSV Export Button](img/project_security_dashboard_export_csv_v12.10.png) ![CSV Export Button](img/project_security_dashboard_export_csv_v12_10.png)
## Group Security Dashboard ## Group Security Dashboard
...@@ -152,6 +152,22 @@ projects. ...@@ -152,6 +152,22 @@ projects.
![Instance Security Dashboard with projects](img/instance_security_dashboard_with_projects_v12_8.png) ![Instance Security Dashboard with projects](img/instance_security_dashboard_with_projects_v12_8.png)
### Export vulnerabilities
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213014) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.0.
You can export all your vulnerabilities as CSV by clicking the **{upload}** **Export**
button located at top right of the **Instance Security Dashboard**. After the report
is built, the CSV report downloads to your local machine. The report contains all
vulnerabilities for the projects defined in the **Instance Security Dashboard**,
as filters don't apply to the export function.
NOTE: **Note:**
It may take several minutes for the download to start if your project contains
thousands of vulnerabilities. Do not close the page until the download finishes.
![CSV Export Button](img/instance_security_dashboard_export_csv_v13_0.png)
## Keeping the dashboards up to date ## Keeping the dashboards up to date
The Security Dashboard displays information from the results of the most recent The Security Dashboard displays information from the results of the most recent
......
...@@ -7,10 +7,12 @@ import InstanceSecurityVulnerabilities from './first_class_instance_security_das ...@@ -7,10 +7,12 @@ import InstanceSecurityVulnerabilities from './first_class_instance_security_das
import VulnerabilitySeverity from 'ee/security_dashboard/components/vulnerability_severity.vue'; import VulnerabilitySeverity from 'ee/security_dashboard/components/vulnerability_severity.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue'; import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import ProjectManager from './project_manager.vue'; import ProjectManager from './project_manager.vue';
import CsvExportButton from './csv_export_button.vue';
export default { export default {
components: { components: {
ProjectManager, ProjectManager,
CsvExportButton,
SecurityDashboardLayout, SecurityDashboardLayout,
InstanceSecurityVulnerabilities, InstanceSecurityVulnerabilities,
VulnerabilitySeverity, VulnerabilitySeverity,
...@@ -41,6 +43,11 @@ export default { ...@@ -41,6 +43,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
vulnerabilitiesExportEndpoint: {
type: String,
required: true,
},
}, },
data() { data() {
return { return {
...@@ -95,9 +102,10 @@ export default { ...@@ -95,9 +102,10 @@ export default {
<security-dashboard-layout> <security-dashboard-layout>
<template #header> <template #header>
<header class="page-title-holder flex-fill d-flex align-items-center"> <header class="page-title-holder flex-fill d-flex align-items-center">
<h2 class="page-title">{{ s__('SecurityReports|Security Dashboard') }}</h2> <h2 class="page-title flex-grow">{{ s__('SecurityReports|Security Dashboard') }}</h2>
<csv-export-button :vulnerabilities-export-endpoint="vulnerabilitiesExportEndpoint" />
<gl-button <gl-button
class="page-title-controls js-project-selector-toggle" class="page-title-controls ml-2"
:variant="toggleButtonProps.variant" :variant="toggleButtonProps.variant"
@click="toggleProjectSelector" @click="toggleProjectSelector"
>{{ toggleButtonProps.text }}</gl-button >{{ toggleButtonProps.text }}</gl-button
......
...@@ -64,6 +64,7 @@ export default ( ...@@ -64,6 +64,7 @@ export default (
} else if (dashboardType === DASHBOARD_TYPES.INSTANCE) { } else if (dashboardType === DASHBOARD_TYPES.INSTANCE) {
component = FirstClassInstanceSecurityDashboard; component = FirstClassInstanceSecurityDashboard;
props.vulnerableProjectsEndpoint = el.dataset.vulnerableProjectsEndpoint; props.vulnerableProjectsEndpoint = el.dataset.vulnerableProjectsEndpoint;
props.vulnerabilitiesExportEndpoint = el.dataset.vulnerabilitiesExportEndpoint;
} }
const router = createRouter(); const router = createRouter();
......
---
title: Export an instance-level vulnerabilities report
merge_request: 30079
author:
type: added
...@@ -5,6 +5,7 @@ import SecurityDashboardLayout from 'ee/security_dashboard/components/security_d ...@@ -5,6 +5,7 @@ import SecurityDashboardLayout from 'ee/security_dashboard/components/security_d
import FirstClassInstanceDashboard from 'ee/security_dashboard/components/first_class_instance_security_dashboard.vue'; import FirstClassInstanceDashboard from 'ee/security_dashboard/components/first_class_instance_security_dashboard.vue';
import FirstClassInstanceVulnerabilities from 'ee/security_dashboard/components/first_class_instance_security_dashboard_vulnerabilities.vue'; import FirstClassInstanceVulnerabilities from 'ee/security_dashboard/components/first_class_instance_security_dashboard_vulnerabilities.vue';
import VulnerabilitySeverity from 'ee/security_dashboard/components/vulnerability_severity.vue'; import VulnerabilitySeverity from 'ee/security_dashboard/components/vulnerability_severity.vue';
import CsvExportButton from 'ee/security_dashboard/components/csv_export_button.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue'; import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import ProjectManager from 'ee/security_dashboard/components/project_manager.vue'; import ProjectManager from 'ee/security_dashboard/components/project_manager.vue';
...@@ -18,11 +19,13 @@ describe('First Class Instance Dashboard Component', () => { ...@@ -18,11 +19,13 @@ describe('First Class Instance Dashboard Component', () => {
const dashboardDocumentation = 'dashboard-documentation'; const dashboardDocumentation = 'dashboard-documentation';
const emptyStateSvgPath = 'empty-state-path'; const emptyStateSvgPath = 'empty-state-path';
const vulnerableProjectsEndpoint = '/vulnerable/projects'; const vulnerableProjectsEndpoint = '/vulnerable/projects';
const vulnerabilitiesExportEndpoint = '/vulnerabilities/exports';
const projectAddEndpoint = 'projectAddEndpoint'; const projectAddEndpoint = 'projectAddEndpoint';
const projectListEndpoint = 'projectListEndpoint'; const projectListEndpoint = 'projectListEndpoint';
const findInstanceVulnerabilities = () => wrapper.find(FirstClassInstanceVulnerabilities); const findInstanceVulnerabilities = () => wrapper.find(FirstClassInstanceVulnerabilities);
const findVulnerabilitySeverity = () => wrapper.find(VulnerabilitySeverity); const findVulnerabilitySeverity = () => wrapper.find(VulnerabilitySeverity);
const findCsvExportButton = () => wrapper.find(CsvExportButton);
const findProjectManager = () => wrapper.find(ProjectManager); const findProjectManager = () => wrapper.find(ProjectManager);
const findEmptyState = () => wrapper.find(GlEmptyState); const findEmptyState = () => wrapper.find(GlEmptyState);
const findFilters = () => wrapper.find(Filters); const findFilters = () => wrapper.find(Filters);
...@@ -55,6 +58,7 @@ describe('First Class Instance Dashboard Component', () => { ...@@ -55,6 +58,7 @@ describe('First Class Instance Dashboard Component', () => {
projectAddEndpoint, projectAddEndpoint,
projectListEndpoint, projectListEndpoint,
vulnerableProjectsEndpoint, vulnerableProjectsEndpoint,
vulnerabilitiesExportEndpoint,
}, },
stubs: { stubs: {
...stubs, ...stubs,
...@@ -100,6 +104,12 @@ describe('First Class Instance Dashboard Component', () => { ...@@ -100,6 +104,12 @@ describe('First Class Instance Dashboard Component', () => {
it('displays the vulnerability severity in an aside', () => { it('displays the vulnerability severity in an aside', () => {
expect(findVulnerabilitySeverity().exists()).toBe(true); expect(findVulnerabilitySeverity().exists()).toBe(true);
}); });
it('displays the csv export button', () => {
expect(findCsvExportButton().props('vulnerabilitiesExportEndpoint')).toBe(
vulnerabilitiesExportEndpoint,
);
});
}); });
describe('when uninitialized', () => { describe('when uninitialized', () => {
......
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