Commit 20247dde authored by Mark Florian's avatar Mark Florian

Merge branch 'djadmin-refactor-mrwidget' into 'master'

Resolve "Consolidate Merge Request Widget Report Issue Bodies"

See merge request gitlab-org/gitlab!29229
parents c3254bca b4f6acaf
......@@ -2,10 +2,7 @@ import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/perform
import CodequalityIssueBody from 'ee/vue_merge_request_widget/components/codequality_issue_body.vue';
import BlockingMergeRequestsBody from 'ee/vue_merge_request_widget/components/blocking_merge_requests/blocking_merge_request_body.vue';
import LicenseIssueBody from 'ee/vue_shared/license_compliance/components/license_issue_body.vue';
import SastIssueBody from 'ee/vue_shared/security_reports/components/sast_issue_body.vue';
import ContainerScanningIssueBody from 'ee/vue_shared/security_reports/components/container_scanning_issue_body.vue';
import DastIssueBody from 'ee/vue_shared/security_reports/components/dast_issue_body.vue';
import SecretScanningIssueBody from 'ee/vue_shared/security_reports/components/secret_scanning_issue_body.vue';
import SecurityIssueBody from 'ee/vue_shared/security_reports/components/security_issue_body.vue';
import MetricsReportsIssueBody from 'ee/vue_shared/metrics_reports/components/metrics_reports_issue_body.vue';
import {
components as componentsCE,
......@@ -17,10 +14,7 @@ export const components = {
PerformanceIssueBody,
CodequalityIssueBody,
LicenseIssueBody,
ContainerScanningIssueBody,
SastIssueBody,
DastIssueBody,
SecretScanningIssueBody,
SecurityIssueBody,
MetricsReportsIssueBody,
BlockingMergeRequestsBody,
};
......@@ -30,10 +24,7 @@ export const componentNames = {
PerformanceIssueBody: PerformanceIssueBody.name,
CodequalityIssueBody: CodequalityIssueBody.name,
LicenseIssueBody: LicenseIssueBody.name,
ContainerScanningIssueBody: ContainerScanningIssueBody.name,
SastIssueBody: SastIssueBody.name,
DastIssueBody: DastIssueBody.name,
SecretScanningIssueBody: SecretScanningIssueBody.name,
SecurityIssueBody: SecurityIssueBody.name,
MetricsReportsIssueBody: MetricsReportsIssueBody.name,
BlockingMergeRequestsBody: BlockingMergeRequestsBody.name,
};
<script>
/**
* Renders CONTAINER SCANNING body text
* [severity-badge] [name] in [link]:[line]
*/
import ModalOpenName from '~/reports/components/modal_open_name.vue';
import SeverityBadge from './severity_badge.vue';
export default {
name: 'ContainerScanningIssueBody',
components: {
ModalOpenName,
SeverityBadge,
},
props: {
issue: {
type: Object,
required: true,
},
// failed || success
status: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<div class="report-block-list-issue-description-text">
<severity-badge v-if="issue.severity" class="d-inline-block" :severity="issue.severity" />
<modal-open-name :issue="issue" :status="status" />
</div>
</div>
</template>
<script>
/**
* Renders DAST body text
* [severity-badge] [name] in [link]:[line]
*/
import ModalOpenName from '~/reports/components/modal_open_name.vue';
import SeverityBadge from './severity_badge.vue';
export default {
name: 'DastIssueBody',
components: {
ModalOpenName,
SeverityBadge,
},
props: {
issue: {
type: Object,
required: true,
},
// failed || success
status: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<div class="report-block-list-issue-description-text">
<severity-badge v-if="issue.severity" class="d-inline-block" :severity="issue.severity" />
<modal-open-name :issue="issue" :status="status" class="js-modal-dast" />
</div>
</div>
</template>
<script>
/**
* Renders SECRET SCANNING body text
* [severity-badge] [name] in [link]:[line]
*/
import ModalOpenName from '~/reports/components/modal_open_name.vue';
import SeverityBadge from './severity_badge.vue';
export default {
name: 'SecretScanningIssueBody',
components: {
ModalOpenName,
SeverityBadge,
},
props: {
issue: {
type: Object,
required: true,
},
// failed || success
status: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<div class="report-block-list-issue-description-text">
<severity-badge v-if="issue.severity" class="d-inline-block" :severity="issue.severity" />
<modal-open-name :issue="issue" :status="status" />
</div>
</div>
</template>
<script>
/**
* Renders SAST body text
* Renders Security Issues (SAST, DAST, Container
* Scanning, Secret Scanning) body text
* [severity-badge] [name] in [link]:[line]
*/
import ReportLink from '~/reports/components/report_link.vue';
......@@ -8,7 +9,7 @@ import ModalOpenName from '~/reports/components/modal_open_name.vue';
import SeverityBadge from './severity_badge.vue';
export default {
name: 'SastIssueBody',
name: 'SecurityIssueBody',
components: {
ReportLink,
ModalOpenName,
......@@ -25,6 +26,11 @@ export default {
required: true,
},
},
computed: {
showReportLink() {
return this.issue.report_type === 'sast' || this.issue.report_type === 'dependency_scanning';
},
},
};
</script>
<template>
......@@ -33,6 +39,6 @@ export default {
<severity-badge v-if="issue.severity" class="d-inline-block" :severity="issue.severity" />
<modal-open-name :issue="issue" :status="status" />
</div>
<report-link v-if="issue.path" :issue="issue" />
<report-link v-if="showReportLink && issue.path" :issue="issue" />
</div>
</template>
......@@ -351,7 +351,7 @@ export default {
:unresolved-issues="sast.newIssues"
:resolved-issues="sast.resolvedIssues"
:all-issues="sast.allIssues"
:component="$options.componentNames.SastIssueBody"
:component="$options.componentNames.SecurityIssueBody"
class="js-sast-issue-list report-block-group-list"
/>
</template>
......@@ -369,7 +369,7 @@ export default {
v-if="dependencyScanning.newIssues.length || dependencyScanning.resolvedIssues.length"
:unresolved-issues="dependencyScanning.newIssues"
:resolved-issues="dependencyScanning.resolvedIssues"
:component="$options.componentNames.SastIssueBody"
:component="$options.componentNames.SecurityIssueBody"
class="js-dss-issue-list report-block-group-list"
/>
</template>
......@@ -387,7 +387,7 @@ export default {
v-if="containerScanning.newIssues.length || containerScanning.resolvedIssues.length"
:unresolved-issues="containerScanning.newIssues"
:resolved-issues="containerScanning.resolvedIssues"
:component="$options.componentNames.ContainerScanningIssueBody"
:component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
/>
</template>
......@@ -418,7 +418,7 @@ export default {
v-if="dast.newIssues.length || dast.resolvedIssues.length"
:unresolved-issues="dast.newIssues"
:resolved-issues="dast.resolvedIssues"
:component="$options.componentNames.DastIssueBody"
:component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
/>
</template>
......@@ -436,7 +436,7 @@ export default {
v-if="secretScanning.newIssues.length || secretScanning.resolvedIssues.length"
:unresolved-issues="secretScanning.newIssues"
:resolved-issues="secretScanning.resolvedIssues"
:component="$options.componentNames.SecretScanningIssueBody"
:component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
/>
</template>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Container Scanning Issue Body matches snapshot 1`] = `
<div
class="report-block-list-issue-description prepend-top-5 append-bottom-5"
>
<div
class="report-block-list-issue-description-text"
>
<severity-badge-stub
class="d-inline-block"
severity="Low"
/>
<modal-open-name-stub
issue="[object Object]"
status="Failed"
/>
</div>
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Dast Issue Body matches the snaphot 1`] = `
<div
class="report-block-list-issue-description prepend-top-5 append-bottom-5"
>
<div
class="report-block-list-issue-description-text"
>
<severity-badge-stub
class="d-inline-block"
severity="Low"
/>
<modal-open-name-stub
class="js-modal-dast"
issue="[object Object]"
status="failed"
/>
</div>
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Sast Issue Body matches snapshot 1`] = `
<div
class="report-block-list-issue-description prepend-top-5 append-bottom-5"
>
<div
class="report-block-list-issue-description-text"
>
<severity-badge-stub
class="d-inline-block"
severity="Medium"
/>
<modal-open-name-stub
issue="[object Object]"
status="failed"
/>
</div>
<!---->
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Secret Scanning Issue Body matches snapshot 1`] = `
<div
class="report-block-list-issue-description prepend-top-5 append-bottom-5"
>
<div
class="report-block-list-issue-description-text"
>
<severity-badge-stub
class="d-inline-block"
severity="Critical"
/>
<modal-open-name-stub
issue="[object Object]"
status="Failed"
/>
</div>
</div>
`;
import { shallowMount } from '@vue/test-utils';
import ContainerScanningIssueBody from 'ee/vue_shared/security_reports/components/container_scanning_issue_body.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
describe('Container Scanning Issue Body', () => {
let wrapper;
const createComponent = (severity = undefined) => {
wrapper = shallowMount(ContainerScanningIssueBody, {
propsData: {
issue: {
title: 'CVE-2017-11671',
namespace: 'debian:8',
path: 'debian:8',
severity,
vulnerability: 'CVE-2017-11671',
},
status: 'Failed',
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('matches snapshot', () => {
createComponent('Low');
expect(wrapper.element).toMatchSnapshot();
});
it('does show SeverityBadge if severity is present', () => {
createComponent('Low');
expect(wrapper.find(SeverityBadge).props('severity')).toBe('Low');
});
it('does not show SeverityBadge if severity is not present', () => {
createComponent();
expect(wrapper.contains(SeverityBadge)).toBe(false);
});
});
import { shallowMount } from '@vue/test-utils';
import DastIssueBody from 'ee/vue_shared/security_reports/components/dast_issue_body.vue';
describe('Dast Issue Body', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(DastIssueBody, {
propsData: {
issue: {
alert: 'X-Content-Type-Options Header Missing',
severity: 'Low',
count: '17',
cweid: '16',
desc:
'<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff". </p>',
title: 'X-Content-Type-Options Header Missing',
reference:
'<p>http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx</p><p>https://www.owasp.org/index.php/List_of_useful_HTTP_headers</p>',
riskcode: '1',
riskdesc: 'Low (Medium)',
},
status: 'failed',
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('matches the snaphot', () => {
createComponent();
expect(wrapper.element).toMatchSnapshot();
});
});
import { shallowMount } from '@vue/test-utils';
import SecretScanningIssueBody from 'ee/vue_shared/security_reports/components/secret_scanning_issue_body.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
describe('Secret Scanning Issue Body', () => {
let wrapper;
const createComponent = (severity = undefined) => {
wrapper = shallowMount(SecretScanningIssueBody, {
propsData: {
issue: {
title: 'AWS SecretKey Found',
severity,
},
status: 'Failed',
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('matches snapshot', () => {
createComponent('Critical');
expect(wrapper.element).toMatchSnapshot();
});
it('does show SeverityBadge if severity is present', () => {
createComponent('Critical');
expect(wrapper.find(SeverityBadge).props('severity')).toBe('Critical');
});
it('does not show SeverityBadge if severity is not present', () => {
createComponent();
expect(wrapper.contains(SeverityBadge)).toBe(false);
});
});
import { shallowMount } from '@vue/test-utils';
import { STATUS_FAILED } from '~/reports/constants';
import SastIssueBody from 'ee/vue_shared/security_reports/components/sast_issue_body.vue';
import SecurityIssueBody from 'ee/vue_shared/security_reports/components/security_issue_body.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import ReportLink from '~/reports/components/report_link.vue';
describe('Sast Issue Body', () => {
import {
sastParsedIssues,
dockerReportParsed,
parsedDast,
dependencyScanningIssues,
secretScanningParsedIssues,
} from '../mock_data';
describe('Security Issue Body', () => {
let wrapper;
const findReportLink = () => wrapper.find(ReportLink);
const createComponent = issue => {
wrapper = shallowMount(SastIssueBody, {
wrapper = shallowMount(SecurityIssueBody, {
propsData: {
issue,
status: STATUS_FAILED,
......@@ -23,36 +30,29 @@ describe('Sast Issue Body', () => {
wrapper = null;
});
it('matches snapshot', () => {
createComponent({
severity: 'Medium',
describe.each([
['SAST', sastParsedIssues[0], true, 'High'],
['DAST', parsedDast[0], false, 'Low'],
['Container Scanning', dockerReportParsed.vulnerabilities[0], false, 'Medium'],
['Dependency Scanning', dependencyScanningIssues[0], true],
['Secret Scanning', secretScanningParsedIssues[0], false, 'Critical'],
])('for a %s vulnerability', (name, vuln, hasReportLink, severity) => {
beforeEach(() => {
createComponent(vuln);
});
expect(wrapper.element).toMatchSnapshot();
});
it('does show SeverityBadge if severity is present', () => {
createComponent({
severity: 'Medium',
if (severity) {
it(`shows SeverityBadge if severity is present`, () => {
expect(wrapper.find(SeverityBadge).props('severity')).toBe(severity);
});
} else {
it(`does not show SeverityBadge if severity is not present`, () => {
expect(wrapper.contains(SeverityBadge)).toBe(false);
});
}
it(`does ${hasReportLink ? '' : 'not '}render report link`, () => {
expect(findReportLink().exists()).toBe(hasReportLink);
});
expect(wrapper.find(SeverityBadge).props('severity')).toBe('Medium');
});
it('does not show SeverityBadge if severity is not present', () => {
createComponent({});
expect(wrapper.contains(SeverityBadge)).toBe(false);
});
it('does not render report link if no path is passed', () => {
createComponent({});
expect(findReportLink().exists()).toBe(false);
});
it('renders report link if path is passed', () => {
createComponent({ path: 'test-path' });
expect(findReportLink().exists()).toBe(true);
});
});
......@@ -7,6 +7,23 @@ export const sastParsedIssues = [
line: 12,
severity: 'High',
urlPath: 'foo/Gemfile.lock',
report_type: 'sast',
},
];
export const dependencyScanningIssues = [
{
id: null,
report_type: 'dependency_scanning',
name: 'Cross-site Scripting in serialize-javascript',
description:
'The serialize-javascript npm package is vulnerable to Cross-site Scripting (XSS). It does not properly mitigate against unsafe characters in serialized regular expressions. If serialized data of regular expression objects are used in an environment other than Node.js, it is affected by this vulnerability.',
links: [{ url: 'https://nvd.nist.gov/vuln/detail/CVE-2019-16769' }],
location: {
file: 'yarn.lock',
dependency: { package: { name: 'serialize-javascript' }, version: '1.7.0' },
},
path: 'yarn.lock',
},
];
......
......@@ -61,7 +61,7 @@ describe('Report issues', () => {
it('should render location', () => {
vm = mountComponent(ReportIssues, {
issue: sastParsedIssues[0],
component: componentNames.SastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
});
......@@ -78,7 +78,7 @@ describe('Report issues', () => {
issue: {
title: 'foo',
},
component: componentNames.SastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_SUCCESS,
});
......@@ -91,7 +91,7 @@ describe('Report issues', () => {
beforeEach(() => {
vm = mountComponent(ReportIssues, {
issue: dockerReportParsed.unapproved[0],
component: componentNames.ContainerScanningIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
});
});
......@@ -113,7 +113,7 @@ describe('Report issues', () => {
store,
props: {
issue: parsedDast[0],
component: componentNames.DastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
},
});
......@@ -129,7 +129,7 @@ describe('Report issues', () => {
beforeEach(() => {
vm = mountComponent(ReportIssues, {
issue: secretScanningParsedIssues[0],
component: componentNames.SecretScanningIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
});
});
......
......@@ -61,7 +61,7 @@ describe('Report issue', () => {
it('should render location', () => {
vm = mountComponent(ReportIssue, {
issue: sastParsedIssues[0],
component: componentNames.SastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
});
......@@ -78,7 +78,7 @@ describe('Report issue', () => {
issue: {
title: 'foo',
},
component: componentNames.SastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_SUCCESS,
});
......@@ -91,7 +91,7 @@ describe('Report issue', () => {
beforeEach(() => {
vm = mountComponent(ReportIssue, {
issue: dockerReportParsed.unapproved[0],
component: componentNames.ContainerScanningIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
});
});
......@@ -113,7 +113,7 @@ describe('Report issue', () => {
store,
props: {
issue: parsedDast[0],
component: componentNames.DastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
},
});
......@@ -129,7 +129,7 @@ describe('Report issue', () => {
beforeEach(() => {
vm = mountComponent(ReportIssue, {
issue: secretScanningParsedIssues[0],
component: componentNames.SecretScanningIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_FAILED,
});
});
......@@ -151,7 +151,7 @@ describe('Report issue', () => {
store,
props: {
issue: parsedDast[0],
component: componentNames.DastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_SUCCESS,
showReportSectionStatusIcon: false,
},
......@@ -165,7 +165,7 @@ describe('Report issue', () => {
store,
props: {
issue: parsedDast[0],
component: componentNames.DastIssueBody,
component: componentNames.SecurityIssueBody,
status: STATUS_SUCCESS,
},
});
......
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