Commit b5f65f51 authored by Sam Beckham's avatar Sam Beckham Committed by Phil Hughes

Full list of vulnerabilities

parent 8cb9f02e
...@@ -38,27 +38,12 @@ export default { ...@@ -38,27 +38,12 @@ export default {
required: false, required: false,
default: () => [], default: () => [],
}, },
allIssues: {
type: Array,
required: false,
default: () => [],
},
component: { component: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
}, },
data() {
return {
isFullReportVisible: false,
};
},
methods: {
openFullReport() {
this.isFullReportVisible = true;
},
},
}; };
</script> </script>
<template> <template>
...@@ -72,14 +57,6 @@ export default { ...@@ -72,14 +57,6 @@ export default {
class="js-mr-code-new-issues" 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 <issues-block
v-if="neutralIssues.length" v-if="neutralIssues.length"
:component="component" :component="component"
...@@ -95,14 +72,5 @@ export default { ...@@ -95,14 +72,5 @@ export default {
:status="$options.success" :status="$options.success"
class="js-mr-code-resolved-issues" 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> </div>
</template> </template>
...@@ -59,11 +59,6 @@ export default { ...@@ -59,11 +59,6 @@ export default {
required: false, required: false,
default: () => [], default: () => [],
}, },
allIssues: {
type: Array,
required: false,
default: () => [],
},
infoText: { infoText: {
type: [String, Boolean], type: [String, Boolean],
required: false, required: false,
...@@ -142,18 +137,10 @@ export default { ...@@ -142,18 +137,10 @@ export default {
</script> </script>
<template> <template>
<section class="media-section"> <section class="media-section">
<div <div class="media">
class="media" <status-icon :status="statusIconName" />
> <div class="media-body space-children d-flex flex-align-self-center">
<status-icon <span class="js-code-text code-text">
:status="statusIconName"
/>
<div
class="media-body space-children d-flex flex-align-self-center"
>
<span
class="js-code-text code-text"
>
{{ headerText }} {{ headerText }}
<popover <popover
...@@ -163,10 +150,12 @@ export default { ...@@ -163,10 +150,12 @@ export default {
/> />
</span> </span>
<slot name="actionButtons"></slot>
<button <button
v-if="isCollapsible" v-if="isCollapsible"
type="button" type="button"
class="js-collapse-btn btn bt-default float-right btn-sm" class="js-collapse-btn btn float-right btn-sm"
@click="toggleCollapsed" @click="toggleCollapsed"
> >
{{ collapseText }} {{ collapseText }}
...@@ -184,7 +173,6 @@ export default { ...@@ -184,7 +173,6 @@ export default {
:unresolved-issues="unresolvedIssues" :unresolved-issues="unresolvedIssues"
:resolved-issues="resolvedIssues" :resolved-issues="resolvedIssues"
:neutral-issues="neutralIssues" :neutral-issues="neutralIssues"
:all-issues="allIssues"
:component="component" :component="component"
/> />
</slot> </slot>
......
...@@ -291,6 +291,7 @@ export default { ...@@ -291,6 +291,7 @@ export default {
:dependency-scanning-help-path="mr.dependencyScanningHelp" :dependency-scanning-help-path="mr.dependencyScanningHelp"
:vulnerability-feedback-path="mr.vulnerabilityFeedbackPath" :vulnerability-feedback-path="mr.vulnerabilityFeedbackPath"
:vulnerability-feedback-help-path="mr.vulnerabilityFeedbackHelpPath" :vulnerability-feedback-help-path="mr.vulnerabilityFeedbackHelpPath"
:pipeline-path="mr.pipeline.path"
:pipeline-id="mr.securityReportsPipelineId" :pipeline-id="mr.securityReportsPipelineId"
:can-create-issue="mr.canCreateIssue" :can-create-issue="mr.canCreateIssue"
:can-create-feedback="mr.canCreateFeedback" :can-create-feedback="mr.canCreateFeedback"
......
...@@ -102,6 +102,11 @@ export default { ...@@ -102,6 +102,11 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
pipelinePath: {
type: String,
required: false,
default: undefined,
},
canCreateFeedback: { canCreateFeedback: {
type: Boolean, type: Boolean,
required: true, required: true,
...@@ -126,6 +131,9 @@ export default { ...@@ -126,6 +131,9 @@ export default {
'dastStatusIcon', 'dastStatusIcon',
'dependencyScanningStatusIcon', 'dependencyScanningStatusIcon',
]), ]),
securityTab() {
return `${this.pipelinePath}/security`;
},
}, },
created() { created() {
...@@ -210,6 +218,18 @@ export default { ...@@ -210,6 +218,18 @@ export default {
:has-issues="true" :has-issues="true"
class="mr-widget-border-top grouped-security-reports" 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 <div
slot="body" slot="body"
class="mr-widget-grouped-section report-block" class="mr-widget-grouped-section report-block"
...@@ -223,7 +243,7 @@ export default { ...@@ -223,7 +243,7 @@ export default {
/> />
<issues-list <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" :unresolved-issues="sast.newIssues"
:resolved-issues="sast.resolvedIssues" :resolved-issues="sast.resolvedIssues"
:all-issues="sast.allIssues" :all-issues="sast.allIssues"
...@@ -241,8 +261,7 @@ export default { ...@@ -241,8 +261,7 @@ export default {
/> />
<issues-list <issues-list
v-if="dependencyScanning.newIssues.length || v-if="dependencyScanning.newIssues.length || dependencyScanning.resolvedIssues.length"
dependencyScanning.resolvedIssues.length || dependencyScanning.allIssues.length"
:unresolved-issues="dependencyScanning.newIssues" :unresolved-issues="dependencyScanning.newIssues"
:resolved-issues="dependencyScanning.resolvedIssues" :resolved-issues="dependencyScanning.resolvedIssues"
:all-issues="dependencyScanning.allIssues" :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 "" ...@@ -7405,9 +7405,6 @@ msgstr ""
msgid "ciReport|Severity" msgid "ciReport|Severity"
msgstr "" msgstr ""
msgid "ciReport|Show complete code vulnerabilities report"
msgstr ""
msgid "ciReport|Solution" msgid "ciReport|Solution"
msgstr "" msgstr ""
...@@ -7441,6 +7438,9 @@ msgstr "" ...@@ -7441,6 +7438,9 @@ msgstr ""
msgid "ciReport|Upgrade %{name} from %{version} to %{fixed}." msgid "ciReport|Upgrade %{name} from %{version} to %{fixed}."
msgstr "" msgstr ""
msgid "ciReport|View full report"
msgstr ""
msgid "ciReport|no vulnerabilities" msgid "ciReport|no vulnerabilities"
msgstr "" msgstr ""
......
...@@ -15,4 +15,14 @@ export const mountComponentWithStore = (Component, { el, props, store }) => ...@@ -15,4 +15,14 @@ export const mountComponentWithStore = (Component, { el, props, store }) =>
propsData: props || {}, propsData: props || {},
}).$mount(el); }).$mount(el);
export const mountComponentWithSlots = (Component, { props, slots }) => {
const component = new Component({
propsData: props || {},
});
component.$slots = slots;
return component.$mount();
};
export default mountComponent; export default mountComponent;
import Vue from 'vue'; import Vue from 'vue';
import reportSection from '~/vue_shared/components/reports/report_section.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', () => { describe('Report section', () => {
let vm; let vm;
...@@ -171,4 +171,27 @@ describe('Report section', () => { ...@@ -171,4 +171,27 @@ describe('Report section', () => {
expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report'); 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', () => { ...@@ -258,39 +258,22 @@ describe('Grouped security reports app', () => {
canCreateFeedback: true, canCreateFeedback: true,
}); });
}); });
});
it('render show all issues button for sast', done => { describe('with the pipelinePath prop', () => {
setTimeout(() => { const pipelinePath = '/path/to/the/pipeline';
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();
vm beforeEach(() => {
.$nextTick() vm = mountComponent(Component, {
.then(() => { headBlobPath: 'path',
expect(vm.$el.querySelector('.js-sast-issue-list').textContent).toContain( canCreateFeedback: false,
sastHeadAllIssues[0].message, canCreateIssue: false,
); pipelinePath,
}) });
.then(done)
.catch(done.fail);
}, 0);
}); });
it('render show all issues button for dependency scanning', done => { it('should calculate the security tab path', () => {
setTimeout(() => { expect(vm.securityTab).toEqual(`${pipelinePath}/security`);
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);
}); });
}); });
}); });
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