Commit 5d7ba503 authored by Jannik Lehmann's avatar Jannik Lehmann Committed by Peter Hegman

Refactor securityReportsMixin into grouped_security_reports constants

This commit solves: https://gitlab.com/gitlab-org/gitlab/-/issues/342895
It refactors the securityReportsMixin into
the grouped_security_reports constants.
parent 8cac7158
/* eslint-disable import/export */ /* eslint-disable import/export */
import { invert } from 'lodash'; import { invert } from 'lodash';
import { s__ } from '~/locale';
import { import {
reportTypeToSecurityReportTypeEnum as reportTypeToSecurityReportTypeEnumCE, reportTypeToSecurityReportTypeEnum as reportTypeToSecurityReportTypeEnumCE,
REPORT_TYPE_API_FUZZING, REPORT_TYPE_API_FUZZING,
...@@ -43,3 +45,49 @@ export const reportTypeToSecurityReportTypeEnum = { ...@@ -43,3 +45,49 @@ export const reportTypeToSecurityReportTypeEnum = {
* A mapping from SecurityReportTypeEnum values to security scan report types. * A mapping from SecurityReportTypeEnum values to security scan report types.
*/ */
export const securityReportTypeEnumToReportType = invert(reportTypeToSecurityReportTypeEnum); export const securityReportTypeEnumToReportType = invert(reportTypeToSecurityReportTypeEnum);
/**
* Values for Security Scanner Info PopOvers including help Page Path Links
*/
export const sastPopover = {
title: s__(
'ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code.',
),
copy: s__('ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}'),
};
export const containerScanningPopover = {
title: s__('ciReport|Container scanning detects known vulnerabilities in your docker images.'),
copy: s__('ciReport|%{linkStartTag}Learn more about Container Scanning %{linkEndTag}'),
};
export const dastPopover = {
title: s__(
'ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application.',
),
copy: s__('ciReport|%{linkStartTag}Learn more about DAST %{linkEndTag}'),
};
export const dependencyScanningPopover = {
title: s__(
"ciReport|Dependency Scanning detects known vulnerabilities in your source code's dependencies.",
),
copy: s__('ciReport|%{linkStartTag}Learn more about Dependency Scanning %{linkEndTag}'),
};
export const secretDetectionPopover = {
title: s__(
'ciReport|Secret Detection detects secrets and credentials vulnerabilities in your source code.',
),
copy: s__('ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}'),
};
export const coverageFuzzingPopover = {
title: s__('ciReport|Coverage Fuzzing'),
copy: s__('ciReport|%{linkStartTag}Learn more about Coverage Fuzzing %{linkEndTag}'),
};
export const apiFuzzingPopover = {
title: s__('ciReport|API Fuzzing'),
copy: s__('ciReport|%{linkStartTag}Learn more about API Fuzzing%{linkEndTag}'),
};
...@@ -8,7 +8,8 @@ import { ...@@ -8,7 +8,8 @@ import {
GlModalDirective, GlModalDirective,
GlTooltipDirective as GlTooltip, GlTooltipDirective as GlTooltip,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { s__, n__, __ } from '~/locale'; import { spriteIcon } from '~/lib/utils/common_utils';
import { s__, n__, __, sprintf } from '~/locale';
import { componentNames } from 'ee/reports/components/issue_body'; import { componentNames } from 'ee/reports/components/issue_body';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { mrStates } from '~/mr_popover/constants'; import { mrStates } from '~/mr_popover/constants';
...@@ -22,12 +23,18 @@ import SecuritySummary from '~/vue_shared/security_reports/components/security_s ...@@ -22,12 +23,18 @@ import SecuritySummary from '~/vue_shared/security_reports/components/security_s
import { import {
REPORT_TYPE_DAST, REPORT_TYPE_DAST,
securityReportTypeEnumToReportType, securityReportTypeEnumToReportType,
sastPopover,
containerScanningPopover,
dastPopover,
dependencyScanningPopover,
secretDetectionPopover,
coverageFuzzingPopover,
apiFuzzingPopover,
} from 'ee/vue_shared/security_reports/constants'; } from 'ee/vue_shared/security_reports/constants';
import DastModal from './components/dast_modal.vue'; import DastModal from './components/dast_modal.vue';
import IssueModal from './components/modal.vue'; import IssueModal from './components/modal.vue';
import securityReportSummaryQuery from './graphql/mr_security_report_summary.graphql'; import securityReportSummaryQuery from './graphql/mr_security_report_summary.graphql';
import securityReportsMixin from './mixins/security_report_mixin';
import { vulnerabilityModalMixin } from './mixins/vulnerability_modal_mixin'; import { vulnerabilityModalMixin } from './mixins/vulnerability_modal_mixin';
import createStore from './store'; import createStore from './store';
import { import {
...@@ -60,23 +67,7 @@ export default { ...@@ -60,23 +67,7 @@ export default {
'gl-modal': GlModalDirective, 'gl-modal': GlModalDirective,
GlTooltip, GlTooltip,
}, },
mixins: [securityReportsMixin, vulnerabilityModalMixin()], mixins: [vulnerabilityModalMixin()],
apollo: {
dastSummary: {
query: securityReportSummaryQuery,
fetchPolicy: fetchPolicies.NETWORK_ONLY,
variables() {
return {
fullPath: this.projectFullPath,
pipelineIid: this.pipelineIid,
};
},
update(data) {
const dast = data?.project?.pipeline?.securityReportSummary?.dast;
return dast && Object.keys(dast).length ? dast : null;
},
},
},
props: { props: {
enabledReports: { enabledReports: {
type: Object, type: Object,
...@@ -250,7 +241,30 @@ export default { ...@@ -250,7 +241,30 @@ export default {
required: true, required: true,
}, },
}, },
apollo: {
dastSummary: {
query: securityReportSummaryQuery,
fetchPolicy: fetchPolicies.NETWORK_ONLY,
variables() {
return {
fullPath: this.projectFullPath,
pipelineIid: this.pipelineIid,
};
},
update(data) {
const dast = data?.project?.pipeline?.securityReportSummary?.dast;
return dast && Object.keys(dast).length ? dast : null;
},
},
},
i18n: { i18n: {
sastPopover,
containerScanningPopover,
dastPopover,
dependencyScanningPopover,
secretDetectionPopover,
coverageFuzzingPopover,
apiFuzzingPopover,
scannedResources: s__('SecurityReports|scanned resources'), scannedResources: s__('SecurityReports|scanned resources'),
viewReport: s__('ciReport|View full report'), viewReport: s__('ciReport|View full report'),
divergedFromTargetBranch: __( divergedFromTargetBranch: __(
...@@ -494,6 +508,19 @@ export default { ...@@ -494,6 +508,19 @@ export default {
// Do nothing, we dispatch an error message in the action // Do nothing, we dispatch an error message in the action
} }
}, },
getPopover(popoverContent, url) {
return {
title: popoverContent.title,
content: sprintf(
popoverContent.copy,
{
linkStartTag: `<a href="${url}" target="_blank" rel="noopener noreferrer">`,
linkEndTag: `${spriteIcon('external-link', 's16')}</a>`,
},
false,
),
};
},
}, },
summarySlots: ['success', 'error', 'loading'], summarySlots: ['success', 'error', 'loading'],
reportTypes: { reportTypes: {
...@@ -561,7 +588,7 @@ export default { ...@@ -561,7 +588,7 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="sastStatusIcon" :status-icon="sastStatusIcon"
:popover-options="sastPopover" :popover-options="getPopover($options.i18n.sastPopover, sastHelpPath)"
class="js-sast-widget" class="js-sast-widget"
data-qa-selector="sast_scan_report" data-qa-selector="sast_scan_report"
> >
...@@ -584,7 +611,9 @@ export default { ...@@ -584,7 +611,9 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="dependencyScanningStatusIcon" :status-icon="dependencyScanningStatusIcon"
:popover-options="dependencyScanningPopover" :popover-options="
getPopover($options.i18n.dependencyScanningPopover, dependencyScanningHelpPath)
"
class="js-dependency-scanning-widget" class="js-dependency-scanning-widget"
data-qa-selector="dependency_scan_report" data-qa-selector="dependency_scan_report"
> >
...@@ -607,7 +636,9 @@ export default { ...@@ -607,7 +636,9 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="containerScanningStatusIcon" :status-icon="containerScanningStatusIcon"
:popover-options="containerScanningPopover" :popover-options="
getPopover($options.i18n.containerScanningPopover, containerScanningHelpPath)
"
class="js-container-scanning" class="js-container-scanning"
data-qa-selector="container_scan_report" data-qa-selector="container_scan_report"
> >
...@@ -630,7 +661,7 @@ export default { ...@@ -630,7 +661,7 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="dastStatusIcon" :status-icon="dastStatusIcon"
:popover-options="dastPopover" :popover-options="getPopover($options.i18n.dastPopover, dastHelpPath)"
class="js-dast-widget" class="js-dast-widget"
data-qa-selector="dast_scan_report" data-qa-selector="dast_scan_report"
> >
...@@ -676,7 +707,9 @@ export default { ...@@ -676,7 +707,9 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="secretDetectionStatusIcon" :status-icon="secretDetectionStatusIcon"
:popover-options="secretDetectionPopover" :popover-options="
getPopover($options.i18n.secretDetectionPopover, secretDetectionHelpPath)
"
class="js-secret-detection" class="js-secret-detection"
data-testid="secret-detection-report" data-testid="secret-detection-report"
> >
...@@ -699,7 +732,9 @@ export default { ...@@ -699,7 +732,9 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="coverageFuzzingStatusIcon" :status-icon="coverageFuzzingStatusIcon"
:popover-options="coverageFuzzingPopover" :popover-options="
getPopover($options.i18n.coverageFuzzingPopover, coverageFuzzingHelpPath)
"
class="js-coverage-fuzzing-widget" class="js-coverage-fuzzing-widget"
data-qa-selector="coverage_fuzzing_report" data-qa-selector="coverage_fuzzing_report"
> >
...@@ -728,7 +763,7 @@ export default { ...@@ -728,7 +763,7 @@ export default {
<summary-row <summary-row
:nested-summary="true" :nested-summary="true"
:status-icon="apiFuzzingStatusIcon" :status-icon="apiFuzzingStatusIcon"
:popover-options="apiFuzzingPopover" :popover-options="getPopover($options.i18n.apiFuzzingPopover, apiFuzzingHelpPath)"
class="js-api-fuzzing-widget" class="js-api-fuzzing-widget"
data-qa-selector="api_fuzzing_report" data-qa-selector="api_fuzzing_report"
> >
......
import { spriteIcon } from '~/lib/utils/common_utils';
import { sprintf, s__ } from '~/locale';
// Securely open external links in a new tab.
function getLinkStartTag(url) {
return `<a href="${url}" target="_blank" rel="noopener noreferrer">`;
}
// Add in the external link icon at the end of every link.
const linkEndTag = `${spriteIcon('external-link', 's16')}</a>`;
export default {
computed: {
sastPopover() {
return {
title: s__(
'ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code.',
),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.sastHelpPath),
linkEndTag,
},
false,
),
};
},
containerScanningPopover() {
return {
title: s__(
'ciReport|Container scanning detects known vulnerabilities in your docker images.',
),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about Container Scanning %{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.containerScanningHelpPath),
linkEndTag,
},
false,
),
};
},
dastPopover() {
return {
title: s__(
'ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application.',
),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about DAST %{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.dastHelpPath),
linkEndTag,
},
false,
),
};
},
dependencyScanningPopover() {
return {
title: s__(
"ciReport|Dependency Scanning detects known vulnerabilities in your source code's dependencies.",
),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about Dependency Scanning %{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.dependencyScanningHelpPath),
linkEndTag,
},
false,
),
};
},
secretDetectionPopover() {
return {
title: s__(
'ciReport|Secret Detection detects secrets and credentials vulnerabilities in your source code.',
),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.secretDetectionHelpPath),
linkEndTag,
},
false,
),
};
},
coverageFuzzingPopover() {
return {
title: s__('ciReport|Coverage Fuzzing'),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about Coverage Fuzzing %{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.coverageFuzzingHelpPath),
linkEndTag,
},
false,
),
};
},
apiFuzzingPopover() {
return {
title: s__('ciReport|API Fuzzing'),
content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about API Fuzzing%{linkEndTag}'),
{
linkStartTag: getLinkStartTag(this.apiFuzzingHelpPath),
linkEndTag,
},
false,
),
};
},
},
};
import { shallowMount } from '@vue/test-utils';
import mixin from 'ee/vue_shared/security_reports/mixins/security_report_mixin';
describe('securityReportMixin', () => {
it.each`
key | link
${'sast'} | ${'http://fake.url/sast/help/path'}
${'containerScanning'} | ${'http://fake.url/container/scanning/help/path'}
${'dast'} | ${'http://fake.url/dast/help/path'}
${'dependencyScanning'} | ${'http://fake.url/dependency/scanning/help/path'}
`('generates correct external link with icon', ({ key, link }) => {
// Create a fake component for the mixin with the mock help path data value.
const component = {
render() {},
data: () => ({ [`${key}HelpPath`]: link }), // 'key' -> 'keyHelpPath'
mixins: [mixin],
};
// Mount the component so that the mixin's computed properties are evaluated.
const { vm } = shallowMount(component);
// Get the link that the mixin generated.
const mixinLink = vm[`${key}Popover`].content; // 'key' -> 'keyPopover'
// Check that for each link, the expected strings exist.
expect(mixinLink).toContain(`href="${link}`);
expect(mixinLink).toContain('target="_blank"');
expect(mixinLink).toContain('rel="noopener noreferrer"');
expect(mixinLink).toContain('external-link');
});
});
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