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 */
import { invert } from 'lodash';
import { s__ } from '~/locale';
import {
reportTypeToSecurityReportTypeEnum as reportTypeToSecurityReportTypeEnumCE,
REPORT_TYPE_API_FUZZING,
......@@ -43,3 +45,49 @@ export const reportTypeToSecurityReportTypeEnum = {
* A mapping from SecurityReportTypeEnum values to security scan report types.
*/
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 {
GlModalDirective,
GlTooltipDirective as GlTooltip,
} 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 { fetchPolicies } from '~/lib/graphql';
import { mrStates } from '~/mr_popover/constants';
......@@ -22,12 +23,18 @@ import SecuritySummary from '~/vue_shared/security_reports/components/security_s
import {
REPORT_TYPE_DAST,
securityReportTypeEnumToReportType,
sastPopover,
containerScanningPopover,
dastPopover,
dependencyScanningPopover,
secretDetectionPopover,
coverageFuzzingPopover,
apiFuzzingPopover,
} from 'ee/vue_shared/security_reports/constants';
import DastModal from './components/dast_modal.vue';
import IssueModal from './components/modal.vue';
import securityReportSummaryQuery from './graphql/mr_security_report_summary.graphql';
import securityReportsMixin from './mixins/security_report_mixin';
import { vulnerabilityModalMixin } from './mixins/vulnerability_modal_mixin';
import createStore from './store';
import {
......@@ -60,23 +67,7 @@ export default {
'gl-modal': GlModalDirective,
GlTooltip,
},
mixins: [securityReportsMixin, 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;
},
},
},
mixins: [vulnerabilityModalMixin()],
props: {
enabledReports: {
type: Object,
......@@ -250,7 +241,30 @@ export default {
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: {
sastPopover,
containerScanningPopover,
dastPopover,
dependencyScanningPopover,
secretDetectionPopover,
coverageFuzzingPopover,
apiFuzzingPopover,
scannedResources: s__('SecurityReports|scanned resources'),
viewReport: s__('ciReport|View full report'),
divergedFromTargetBranch: __(
......@@ -494,6 +508,19 @@ export default {
// 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'],
reportTypes: {
......@@ -561,7 +588,7 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="sastStatusIcon"
:popover-options="sastPopover"
:popover-options="getPopover($options.i18n.sastPopover, sastHelpPath)"
class="js-sast-widget"
data-qa-selector="sast_scan_report"
>
......@@ -584,7 +611,9 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="dependencyScanningStatusIcon"
:popover-options="dependencyScanningPopover"
:popover-options="
getPopover($options.i18n.dependencyScanningPopover, dependencyScanningHelpPath)
"
class="js-dependency-scanning-widget"
data-qa-selector="dependency_scan_report"
>
......@@ -607,7 +636,9 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="containerScanningStatusIcon"
:popover-options="containerScanningPopover"
:popover-options="
getPopover($options.i18n.containerScanningPopover, containerScanningHelpPath)
"
class="js-container-scanning"
data-qa-selector="container_scan_report"
>
......@@ -630,7 +661,7 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="dastStatusIcon"
:popover-options="dastPopover"
:popover-options="getPopover($options.i18n.dastPopover, dastHelpPath)"
class="js-dast-widget"
data-qa-selector="dast_scan_report"
>
......@@ -676,7 +707,9 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="secretDetectionStatusIcon"
:popover-options="secretDetectionPopover"
:popover-options="
getPopover($options.i18n.secretDetectionPopover, secretDetectionHelpPath)
"
class="js-secret-detection"
data-testid="secret-detection-report"
>
......@@ -699,7 +732,9 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="coverageFuzzingStatusIcon"
:popover-options="coverageFuzzingPopover"
:popover-options="
getPopover($options.i18n.coverageFuzzingPopover, coverageFuzzingHelpPath)
"
class="js-coverage-fuzzing-widget"
data-qa-selector="coverage_fuzzing_report"
>
......@@ -728,7 +763,7 @@ export default {
<summary-row
:nested-summary="true"
:status-icon="apiFuzzingStatusIcon"
:popover-options="apiFuzzingPopover"
:popover-options="getPopover($options.i18n.apiFuzzingPopover, apiFuzzingHelpPath)"
class="js-api-fuzzing-widget"
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