Commit 18544247 authored by Filipa Lacerda's avatar Filipa Lacerda

Adds dast and container scanning reports to summary widget in pipeline view

parent 6ae6fea5
...@@ -12,13 +12,19 @@ export default { ...@@ -12,13 +12,19 @@ export default {
LoadingIcon, LoadingIcon,
}, },
computed: { computed: {
...mapState(['sast', 'dependencyScanning']), ...mapState(['sast', 'dependencyScanning', 'dast', 'sastContainer']),
sastLink() { sastLink() {
return this.link(this.sast.newIssues.length); return this.link(this.sast.newIssues.length);
}, },
dependencyScanningLink() { dependencyScanningLink() {
return this.link(this.dependencyScanning.newIssues.length); return this.link(this.dependencyScanning.newIssues.length);
}, },
dastLink() {
return this.link(this.dast.newIssues.length);
},
sastContainerLink() {
return this.link(this.sastContainer.newIssues.length);
},
sastIcon() { sastIcon() {
return this.statusIcon(this.hasSastError, this.sast.newIssues.length); return this.statusIcon(this.hasSastError, this.sast.newIssues.length);
}, },
...@@ -28,24 +34,48 @@ export default { ...@@ -28,24 +34,48 @@ export default {
this.dependencyScanning.newIssues.length, this.dependencyScanning.newIssues.length,
); );
}, },
dastIcon() {
return this.statusIcon(this.hasDastError, this.dast.newIssues.length);
},
sastContainerIcon() {
return this.statusIcon(this.hasSastContainerError, this.sastContainer.newIssues.length);
},
hasSast() { hasSast() {
return this.sast.paths.head !== null; return this.sast.paths.head !== null;
}, },
hasDependencyScanning() { hasDependencyScanning() {
return this.dependencyScanning.paths.head !== null; return this.dependencyScanning.paths.head !== null;
}, },
hasDast() {
return this.dast.paths.head !== null;
},
hasSastContainer() {
return this.sastContainer.paths.head !== null;
},
isLoadingSast() { isLoadingSast() {
return this.sast.isLoading; return this.sast.isLoading;
}, },
isLoadingDependencyScanning() { isLoadingDependencyScanning() {
return this.dependencyScanning.isLoading; return this.dependencyScanning.isLoading;
}, },
isLoadingDast() {
return this.dast.isLoading;
},
isLoadingSastContainer() {
return this.sastContainer.isLoading;
},
hasSastError() { hasSastError() {
return this.sast.hasError; return this.sast.hasError;
}, },
hasDependencyScanningError() { hasDependencyScanningError() {
return this.dependencyScanning.hasError; return this.dependencyScanning.hasError;
}, },
hasDastError() {
return this.dast.hasError;
},
hasSastContainerError() {
return this.sastContainer.hasError;
},
}, },
methods: { methods: {
openTab() { openTab() {
...@@ -117,7 +147,7 @@ export default { ...@@ -117,7 +147,7 @@ export default {
v-if="hasDependencyScanning" v-if="hasDependencyScanning"
> >
<loading-icon <loading-icon
v-if="dependencyScanning.isLoading" v-if="isLoadingDependencyScanning"
/> />
<ci-icon <ci-icon
v-else v-else
...@@ -146,5 +176,73 @@ export default { ...@@ -146,5 +176,73 @@ export default {
</template> </template>
</span> </span>
</div> </div>
<div
class="well-segment flex js-sast-container-summary"
v-if="hasSastContainer"
>
<loading-icon
v-if="isLoadingSastContainer"
/>
<ci-icon
v-else
:status="sastContainerIcon"
class="flex flex-align-self-center"
/>
<span
class="prepend-left-10 flex flex-align-self-center"
>
<template v-if="hasSastContainerError">
{{ s__('ciReport|Container scanning resulted in error while loading results') }}
</template>
<template v-else-if="isLoadingSastContainer">
{{ s__('ciReport|Container scanning is loading') }}
</template>
<template v-else>
{{ s__('ciReport|Container scanning detected') }}
<button
type="button"
class="btn-link btn-blank prepend-left-5"
@click="openTab"
>
{{ sastContainerLink }}
</button>
</template>
</span>
</div>
<div
class="well-segment flex js-dast-summary"
v-if="hasDast"
>
<loading-icon
v-if="isLoadingDast"
/>
<ci-icon
v-else
:status="dastIcon"
class="flex flex-align-self-center"
/>
<span
class="prepend-left-10 flex flex-align-self-center"
>
<template v-if="hasDastError">
{{ s__('ciReport|DAST resulted in error while loading results') }}
</template>
<template v-else-if="isLoadingDast">
{{ s__('ciReport|DAST is loading') }}
</template>
<template v-else>
{{ s__('ciReport|DAST detected') }}
<button
type="button"
class="btn-link btn-blank prepend-left-5"
@click="openTab"
>
{{ dastLink }}
</button>
</template>
</span>
</div>
</div> </div>
</template> </template>
...@@ -170,7 +170,7 @@ export default { ...@@ -170,7 +170,7 @@ export default {
state.dast.isLoading = false; state.dast.isLoading = false;
state.summaryCounts.added += newIssues.length; state.summaryCounts.added += newIssues.length;
state.summaryCounts.fixed += resolvedIssues.length; state.summaryCounts.fixed += resolvedIssues.length;
} else if (reports.head && !reports.base) { } else if (reports.head && reports.head.site && !reports.base) {
const newIssues = parseDastIssues(reports.head.site.alerts, reports.enrichData); const newIssues = parseDastIssues(reports.head.site.alerts, reports.enrichData);
state.dast.newIssues = newIssues; state.dast.newIssues = newIssues;
......
...@@ -3,7 +3,7 @@ import store from 'ee/vue_shared/security_reports/store'; ...@@ -3,7 +3,7 @@ import store from 'ee/vue_shared/security_reports/store';
import state from 'ee/vue_shared/security_reports/store/state'; import state from 'ee/vue_shared/security_reports/store/state';
import reportSummary from 'ee/pipelines/components/security_reports/report_summary_widget.vue'; import reportSummary from 'ee/pipelines/components/security_reports/report_summary_widget.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { sastIssues } from '../../vue_shared/security_reports/mock_data'; import { sastIssues, dast, dockerReport } from '../../vue_shared/security_reports/mock_data';
describe('Report summary widget', () => { describe('Report summary widget', () => {
const Component = Vue.extend(reportSummary); const Component = Vue.extend(reportSummary);
...@@ -30,9 +30,13 @@ describe('Report summary widget', () => { ...@@ -30,9 +30,13 @@ describe('Report summary widget', () => {
beforeEach(() => { beforeEach(() => {
vm.$store.dispatch('setSastHeadPath', 'head.json'); vm.$store.dispatch('setSastHeadPath', 'head.json');
vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json'); vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json');
vm.$store.dispatch('setDastHeadPath', 'head.json');
vm.$store.dispatch('setSastContainerHeadPath', 'head.json');
vm.$store.dispatch('requestSastReports'); vm.$store.dispatch('requestSastReports');
vm.$store.dispatch('requestDependencyScanningReports'); vm.$store.dispatch('requestDependencyScanningReports');
vm.$store.dispatch('requestDastReports');
vm.$store.dispatch('requestSastContainerReports');
}); });
it('renders loading icon and text for sast', done => { it('renders loading icon and text for sast', done => {
...@@ -62,15 +66,47 @@ describe('Report summary widget', () => { ...@@ -62,15 +66,47 @@ describe('Report summary widget', () => {
done(); done();
}); });
}); });
it('renders loading icon and text for container scanning', done => {
vm.$nextTick(() => {
expect(
vm.$el
.querySelector('.js-sast-container-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('Container scanning is loading');
expect(vm.$el.querySelector('.js-sast-container-summary .fa-spinner')).not.toBeNull();
done();
});
});
it('renders loading icon and text for dast', done => {
vm.$nextTick(() => {
expect(
vm.$el
.querySelector('.js-dast-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('DAST is loading');
expect(vm.$el.querySelector('.js-dast-summary .fa-spinner')).not.toBeNull();
done();
});
});
}); });
describe('with error', () => { describe('with error', () => {
beforeEach(() => { beforeEach(() => {
vm.$store.dispatch('setSastHeadPath', 'head.json'); vm.$store.dispatch('setSastHeadPath', 'head.json');
vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json'); vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json');
vm.$store.dispatch('setDastHeadPath', 'head.json');
vm.$store.dispatch('setSastContainerHeadPath', 'head.json');
vm.$store.dispatch('receiveSastError'); vm.$store.dispatch('receiveSastError');
vm.$store.dispatch('receiveDependencyScanningError'); vm.$store.dispatch('receiveDependencyScanningError');
vm.$store.dispatch('receiveSastContainerError');
vm.$store.dispatch('receiveDastError');
}); });
it('renders warning icon and error text for sast', done => { it('renders warning icon and error text for sast', done => {
...@@ -102,12 +138,46 @@ describe('Report summary widget', () => { ...@@ -102,12 +138,46 @@ describe('Report summary widget', () => {
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('renders warnin icon and error text for container scanning', done => {
vm.$nextTick()
.then(() => {
expect(
vm.$el
.querySelector('.js-sast-container-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('Container scanning resulted in error while loading results');
expect(vm.$el.querySelector('.js-sast-container-summary .js-ci-status-icon-warning')).not.toBeNull();
})
.then(done)
.catch(done.fail);
});
it('renders warnin icon and error text for DAST', done => {
vm.$nextTick()
.then(() => {
expect(
vm.$el
.querySelector('.js-dast-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('DAST resulted in error while loading results');
expect(vm.$el.querySelector('.js-dast-summary .js-ci-status-icon-warning')).not.toBeNull();
})
.then(done)
.catch(done.fail);
});
}); });
describe('with vulnerabilities', () => { describe('with vulnerabilities', () => {
beforeEach(() => { beforeEach(() => {
vm.$store.dispatch('setSastHeadPath', 'head.json'); vm.$store.dispatch('setSastHeadPath', 'head.json');
vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json'); vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json');
vm.$store.dispatch('setDastHeadPath', 'head.json');
vm.$store.dispatch('setSastContainerHeadPath', 'head.json');
vm.$store.dispatch('receiveSastReports', { vm.$store.dispatch('receiveSastReports', {
head: sastIssues, head: sastIssues,
...@@ -115,6 +185,12 @@ describe('Report summary widget', () => { ...@@ -115,6 +185,12 @@ describe('Report summary widget', () => {
vm.$store.dispatch('receiveDependencyScanningReports', { vm.$store.dispatch('receiveDependencyScanningReports', {
head: sastIssues, head: sastIssues,
}); });
vm.$store.dispatch('receiveSastContainerReports', {
head: dockerReport,
});
vm.$store.dispatch('receiveDastReports', {
head: dast,
});
}); });
it('renders warning icon and vulnerabilities text for sast', done => { it('renders warning icon and vulnerabilities text for sast', done => {
...@@ -144,12 +220,42 @@ describe('Report summary widget', () => { ...@@ -144,12 +220,42 @@ describe('Report summary widget', () => {
done(); done();
}); });
}); });
it('renders warning icon and vulnerabilities text for container scanning', done => {
vm.$nextTick(() => {
expect(
vm.$el
.querySelector('.js-sast-container-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('Container scanning detected 2 vulnerabilities');
expect(vm.$el.querySelector('.js-sast-container-summary .js-ci-status-icon-warning')).not.toBeNull();
done();
});
});
it('renders warning icon and vulnerabilities text for dast', done => {
vm.$nextTick(() => {
expect(
vm.$el
.querySelector('.js-dast-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('DAST detected 2 vulnerabilities');
expect(vm.$el.querySelector('.js-dast-summary .js-ci-status-icon-warning')).not.toBeNull();
done();
});
});
}); });
describe('without vulnerabilities', () => { describe('without vulnerabilities', () => {
beforeEach(() => { beforeEach(() => {
vm.$store.dispatch('setSastHeadPath', 'head.json'); vm.$store.dispatch('setSastHeadPath', 'head.json');
vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json'); vm.$store.dispatch('setDependencyScanningHeadPath', 'head.json');
vm.$store.dispatch('setDastHeadPath', 'head.json');
vm.$store.dispatch('setSastContainerHeadPath', 'head.json');
vm.$store.dispatch('receiveSastReports', { vm.$store.dispatch('receiveSastReports', {
head: [], head: [],
...@@ -157,6 +263,12 @@ describe('Report summary widget', () => { ...@@ -157,6 +263,12 @@ describe('Report summary widget', () => {
vm.$store.dispatch('receiveDependencyScanningReports', { vm.$store.dispatch('receiveDependencyScanningReports', {
head: [], head: [],
}); });
vm.$store.dispatch('receiveSastContainerReports', {
head: [],
});
vm.$store.dispatch('receiveDastReports', {
head: [],
});
}); });
it('renders success icon and vulnerabilities text for sast', done => { it('renders success icon and vulnerabilities text for sast', done => {
...@@ -186,5 +298,33 @@ describe('Report summary widget', () => { ...@@ -186,5 +298,33 @@ describe('Report summary widget', () => {
done(); done();
}); });
}); });
it('renders success icon and vulnerabilities text for container scanning', done => {
vm.$nextTick(() => {
expect(
vm.$el
.querySelector('.js-sast-container-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('Container scanning detected no vulnerabilities');
expect(vm.$el.querySelector('.js-sast-container-summary .js-ci-status-icon-success')).not.toBeNull();
done();
});
});
it('renders success icon and vulnerabilities text for dast', done => {
vm.$nextTick(() => {
expect(
vm.$el
.querySelector('.js-dast-summary')
.textContent.trim()
.replace(/\s\s+/g, ' '),
).toEqual('DAST detected no vulnerabilities');
expect(vm.$el.querySelector('.js-dast-summary .js-ci-status-icon-success')).not.toBeNull();
done();
});
});
}); });
}); });
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