Commit 6d4e7d7a authored by Phil Hughes's avatar Phil Hughes

Merge branch 'ee-full-list-of-vulnerabilities-5239' into 'master'

Full list of vulnerabilities

Closes #5239

See merge request gitlab-org/gitlab-ee!6675
parents 8cb9f02e b5f65f51
......@@ -38,27 +38,12 @@ export default {
required: false,
default: () => [],
},
allIssues: {
type: Array,
required: false,
default: () => [],
},
component: {
type: String,
required: false,
default: '',
},
},
data() {
return {
isFullReportVisible: false,
};
},
methods: {
openFullReport() {
this.isFullReportVisible = true;
},
},
};
</script>
<template>
......@@ -72,14 +57,6 @@ export default {
class="js-mr-code-new-issues"
/>
<issues-block
v-if="isFullReportVisible"
:component="component"
:issues="allIssues"
:status="$options.failed"
class="js-mr-code-all-issues"
/>
<issues-block
v-if="neutralIssues.length"
:component="component"
......@@ -95,14 +72,5 @@ export default {
:status="$options.success"
class="js-mr-code-resolved-issues"
/>
<button
v-if="allIssues.length && !isFullReportVisible"
type="button"
class="btn-link btn-blank prepend-left-10 js-expand-full-list break-link"
@click="openFullReport"
>
{{ s__("ciReport|Show complete code vulnerabilities report") }}
</button>
</div>
</template>
......@@ -59,11 +59,6 @@ export default {
required: false,
default: () => [],
},
allIssues: {
type: Array,
required: false,
default: () => [],
},
infoText: {
type: [String, Boolean],
required: false,
......@@ -142,18 +137,10 @@ export default {
</script>
<template>
<section class="media-section">
<div
class="media"
>
<status-icon
:status="statusIconName"
/>
<div
class="media-body space-children d-flex flex-align-self-center"
>
<span
class="js-code-text code-text"
>
<div class="media">
<status-icon :status="statusIconName" />
<div class="media-body space-children d-flex flex-align-self-center">
<span class="js-code-text code-text">
{{ headerText }}
<popover
......@@ -163,10 +150,12 @@ export default {
/>
</span>
<slot name="actionButtons"></slot>
<button
v-if="isCollapsible"
type="button"
class="js-collapse-btn btn bt-default float-right btn-sm"
class="js-collapse-btn btn float-right btn-sm"
@click="toggleCollapsed"
>
{{ collapseText }}
......@@ -184,7 +173,6 @@ export default {
:unresolved-issues="unresolvedIssues"
:resolved-issues="resolvedIssues"
:neutral-issues="neutralIssues"
:all-issues="allIssues"
:component="component"
/>
</slot>
......
......@@ -291,6 +291,7 @@ export default {
:dependency-scanning-help-path="mr.dependencyScanningHelp"
:vulnerability-feedback-path="mr.vulnerabilityFeedbackPath"
:vulnerability-feedback-help-path="mr.vulnerabilityFeedbackHelpPath"
:pipeline-path="mr.pipeline.path"
:pipeline-id="mr.securityReportsPipelineId"
:can-create-issue="mr.canCreateIssue"
:can-create-feedback="mr.canCreateFeedback"
......
......@@ -102,6 +102,11 @@ export default {
required: false,
default: null,
},
pipelinePath: {
type: String,
required: false,
default: undefined,
},
canCreateFeedback: {
type: Boolean,
required: true,
......@@ -126,6 +131,9 @@ export default {
'dastStatusIcon',
'dependencyScanningStatusIcon',
]),
securityTab() {
return `${this.pipelinePath}/security`;
},
},
created() {
......@@ -210,6 +218,18 @@ export default {
:has-issues="true"
class="mr-widget-border-top grouped-security-reports"
>
<div
v-if="pipelinePath"
slot="actionButtons"
>
<a
:href="securityTab"
class="btn float-right btn-sm"
>
{{ s__("ciReport|View full report") }}
</a>
</div>
<div
slot="body"
class="mr-widget-grouped-section report-block"
......@@ -223,7 +243,7 @@ export default {
/>
<issues-list
v-if="sast.newIssues.length || sast.resolvedIssues.length || sast.allIssues.length"
v-if="sast.newIssues.length || sast.resolvedIssues.length"
:unresolved-issues="sast.newIssues"
:resolved-issues="sast.resolvedIssues"
:all-issues="sast.allIssues"
......@@ -241,8 +261,7 @@ export default {
/>
<issues-list
v-if="dependencyScanning.newIssues.length ||
dependencyScanning.resolvedIssues.length || dependencyScanning.allIssues.length"
v-if="dependencyScanning.newIssues.length || dependencyScanning.resolvedIssues.length"
:unresolved-issues="dependencyScanning.newIssues"
:resolved-issues="dependencyScanning.resolvedIssues"
:all-issues="dependencyScanning.allIssues"
......
---
title: Removes "show all" on security reports and adds a button to take you to the
pipeline page
merge_request: 6675
author:
type: changed
// eslint-disable-next-line import/prefer-default-export
export const fullReport = {
status: 'SUCCESS',
successText: 'SAST improved on 1 security vulnerability and degraded on 1 security vulnerability',
errorText: 'Failed to load security report',
hasIssues: true,
loadingText: 'Loading security report',
resolvedIssues: [
{
cve: 'CVE-2016-9999',
file: 'Gemfile.lock',
message: 'Test Information Leak Vulnerability in Action View',
title: 'Test Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
urlPath: '/Gemfile.lock',
},
],
unresolvedIssues: [
{
cve: 'CVE-2014-7829',
file: 'Gemfile.lock',
message: 'Arbitrary file existence disclosure in Action Pack',
title: 'Arbitrary file existence disclosure in Action Pack',
path: 'Gemfile.lock',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
urlPath: '/Gemfile.lock',
},
],
allIssues: [
{
cve: 'CVE-2016-0752',
file: 'Gemfile.lock',
message: 'Possible Information Leak Vulnerability in Action View',
title: 'Possible Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
urlPath: '/Gemfile.lock',
},
],
};
import Vue from 'vue';
import reportSection from '~/vue_shared/components/reports/report_section.vue';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { fullReport } from './report_section_mock_data';
describe('Report section', () => {
let vm;
const ReportSection = Vue.extend(reportSection);
afterEach(() => {
vm.$destroy();
});
describe('With full report', () => {
beforeEach(() => {
vm = mountComponent(ReportSection, {
component: componentNames.SastIssueBody,
...fullReport,
});
});
it('should render full report section', done => {
vm.$el.querySelector('button').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.js-expand-full-list').textContent.trim()).toEqual(
'Show complete code vulnerabilities report',
);
done();
});
});
it('should expand full list when clicked and hide the show all button', done => {
vm.$el.querySelector('button').click();
Vue.nextTick(() => {
vm.$el.querySelector('.js-expand-full-list').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.js-mr-code-all-issues').textContent.trim()).toContain(
'Possible Information Leak Vulnerability in Action View',
);
done();
});
});
});
});
});
......@@ -7405,9 +7405,6 @@ msgstr ""
msgid "ciReport|Severity"
msgstr ""
msgid "ciReport|Show complete code vulnerabilities report"
msgstr ""
msgid "ciReport|Solution"
msgstr ""
......@@ -7441,6 +7438,9 @@ msgstr ""
msgid "ciReport|Upgrade %{name} from %{version} to %{fixed}."
msgstr ""
msgid "ciReport|View full report"
msgstr ""
msgid "ciReport|no vulnerabilities"
msgstr ""
......
......@@ -15,4 +15,14 @@ export const mountComponentWithStore = (Component, { el, props, store }) =>
propsData: props || {},
}).$mount(el);
export const mountComponentWithSlots = (Component, { props, slots }) => {
const component = new Component({
propsData: props || {},
});
component.$slots = slots;
return component.$mount();
};
export default mountComponent;
import Vue from 'vue';
import reportSection from '~/vue_shared/components/reports/report_section.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import mountComponent, { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper';
describe('Report section', () => {
let vm;
......@@ -171,4 +171,27 @@ describe('Report section', () => {
expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report');
});
});
describe('with action buttons passed to the slot', () => {
beforeEach(() => {
vm = mountComponentWithSlots(ReportSection, {
props: {
status: 'SUCCESS',
successText: 'success',
hasIssues: true,
},
slots: {
actionButtons: ['Action!'],
},
});
});
it('should render the passed button', () => {
expect(vm.$el.textContent.trim()).toContain('Action!');
});
it('should still render the expand/collapse button', () => {
expect(vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual('Expand');
});
});
});
......@@ -258,39 +258,22 @@ describe('Grouped security reports app', () => {
canCreateFeedback: true,
});
});
});
it('render show all issues button for sast', done => {
setTimeout(() => {
expect(vm.$el.querySelector('.js-sast-issue-list .js-expand-full-list')).not.toBeNull();
vm.$el.querySelector('.js-sast-issue-list .js-expand-full-list').click();
describe('with the pipelinePath prop', () => {
const pipelinePath = '/path/to/the/pipeline';
vm
.$nextTick()
.then(() => {
expect(vm.$el.querySelector('.js-sast-issue-list').textContent).toContain(
sastHeadAllIssues[0].message,
);
})
.then(done)
.catch(done.fail);
}, 0);
beforeEach(() => {
vm = mountComponent(Component, {
headBlobPath: 'path',
canCreateFeedback: false,
canCreateIssue: false,
pipelinePath,
});
});
it('render show all issues button for dependency scanning', done => {
setTimeout(() => {
expect(vm.$el.querySelector('.js-dss-issue-list .js-expand-full-list')).not.toBeNull();
vm.$el.querySelector('.js-dss-issue-list .js-expand-full-list').click();
vm
.$nextTick()
.then(() => {
expect(vm.$el.querySelector('.js-dss-issue-list').textContent).toContain(
sastHeadAllIssues[0].message,
);
})
.then(done)
.catch(done.fail);
}, 0);
it('should calculate the security tab path', () => {
expect(vm.securityTab).toEqual(`${pipelinePath}/security`);
});
});
});
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