Commit eb978c52 authored by Alexander Turinske's avatar Alexander Turinske

Update MR widget vulnerability message

- update message to be new format
- simplify logic
- remove deprecated functional component
- update tests
parent 78977b06
...@@ -2,27 +2,38 @@ ...@@ -2,27 +2,38 @@
import { GlSprintf } from '@gitlab/ui'; import { GlSprintf } from '@gitlab/ui';
import { SEVERITY_CLASS_NAME_MAP } from './constants'; import { SEVERITY_CLASS_NAME_MAP } from './constants';
const makeSeveritySlot = (createElement, severity) => ({ content }) =>
createElement('strong', { class: SEVERITY_CLASS_NAME_MAP[severity] }, content);
export default { export default {
functional: true, components: {
GlSprintf,
},
props: { props: {
message: { message: {
type: String, type: Object,
required: true, required: true,
}, },
}, },
render(createElement, context) { methods: {
const { message } = context.props; getSeverityClass(severity) {
return SEVERITY_CLASS_NAME_MAP[severity];
return createElement(GlSprintf, { },
props: { message },
scopedSlots: {
critical: makeSeveritySlot(createElement, 'critical'),
high: makeSeveritySlot(createElement, 'high'),
},
});
}, },
}; };
</script> </script>
<template>
<span>
<gl-sprintf :message="message.message">
<template #count="{content}">
<strong>{{ content }}</strong>
</template>
<template v-for="slotName in ['critical', 'high', 'other']" #[slotName]="{content}">
<span :key="slotName">
<strong v-if="Boolean(message[slotName])" :class="getSeverityClass(slotName)">
{{ content }}
</strong>
<span v-else>{{ content }}</span>
</span>
</template>
</gl-sprintf>
</span>
</template>
...@@ -555,7 +555,7 @@ export default { ...@@ -555,7 +555,7 @@ export default {
<template v-if="hasCoverageFuzzingReports"> <template v-if="hasCoverageFuzzingReports">
<summary-row <summary-row
:summary="groupedCoverageFuzzingText" :summary="groupedCoverageFuzzingText.message"
:status-icon="coverageFuzzingStatusIcon" :status-icon="coverageFuzzingStatusIcon"
:popover-options="coverageFuzzingPopover" :popover-options="coverageFuzzingPopover"
class="js-coverage-fuzzing-widget" class="js-coverage-fuzzing-widget"
......
...@@ -64,20 +64,20 @@ export const groupedSummaryText = (state, getters) => { ...@@ -64,20 +64,20 @@ export const groupedSummaryText = (state, getters) => {
// All reports are loading // All reports are loading
if (getters.areAllReportsLoading) { if (getters.areAllReportsLoading) {
return sprintf(messages.TRANSLATION_IS_LOADING, { reportType }); return { message: sprintf(messages.TRANSLATION_IS_LOADING, { reportType }) };
} }
// All reports returned error // All reports returned error
if (getters.allReportsHaveError) { if (getters.allReportsHaveError) {
return s__('ciReport|Security scanning failed loading any results'); return { message: s__('ciReport|Security scanning failed loading any results') };
} }
if (getters.areReportsLoading && getters.anyReportHasError) { if (getters.areReportsLoading && getters.anyReportHasError) {
status = s__('ciReport|(is loading, errors when loading results)'); status = s__('ciReport|is loading, errors when loading results');
} else if (getters.areReportsLoading && !getters.anyReportHasError) { } else if (getters.areReportsLoading && !getters.anyReportHasError) {
status = s__('ciReport|(is loading)'); status = s__('ciReport|is loading');
} else if (!getters.areReportsLoading && getters.anyReportHasError) { } else if (!getters.areReportsLoading && getters.anyReportHasError) {
status = s__('ciReport|(errors when loading results)'); status = s__('ciReport|: Loading resulted in an error');
} }
const { critical, high, other } = getters.summaryCounts; const { critical, high, other } = getters.summaryCounts;
......
...@@ -10,14 +10,14 @@ export const findIssueIndex = (issues, issue) => ...@@ -10,14 +10,14 @@ export const findIssueIndex = (issues, issue) =>
issues.findIndex(el => el.project_fingerprint === issue.project_fingerprint); issues.findIndex(el => el.project_fingerprint === issue.project_fingerprint);
/** /**
* Takes an object of options and returns an externalized string representing * Takes an object of options and returns the object with an externalized string representing
* the critical, high, and other severity vulnerabilities for a given report. * the critical, high, and other severity vulnerabilities for a given report.
* *
* The resulting string _may_ still contain sprintf-style placeholders. These * The resulting string _may_ still contain sprintf-style placeholders. These
* are left in place so they can be replaced with markup, via the * are left in place so they can be replaced with markup, via the
* SecuritySummary component. * SecuritySummary component.
* @param {{reportType: string, status: string, critical: number, high: number, other: number}} options * @param {{reportType: string, status: string, critical: number, high: number, other: number}} options
* @returns {string} * @returns {Object} the parameters with an externalized string
*/ */
export const groupedTextBuilder = ({ export const groupedTextBuilder = ({
reportType = '', reportType = '',
...@@ -26,92 +26,37 @@ export const groupedTextBuilder = ({ ...@@ -26,92 +26,37 @@ export const groupedTextBuilder = ({
high = 0, high = 0,
other = 0, other = 0,
} = {}) => { } = {}) => {
// This approach uses bitwise (ish) flags to determine which vulnerabilities const total = critical + high + other;
// we have, without the need for too many nested levels of if/else statements. const vulnMessage = n__('vulnerability', 'vulnerabilities', total);
// const otherMessage = n__('%d Other', '%d Others', other);
// Here's a video explaining how it works
// https://youtu.be/qZzKNC7TPbA
//
// Here's a link to a similar approach on MDN:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Examples
let options = 0;
const HAS_CRITICAL = 1;
const HAS_HIGH = 2;
const HAS_OTHER = 4;
let message; let message;
if (critical) { if (status) {
options += HAS_CRITICAL; message = __('%{reportType} %{status}');
} else if (!total) {
message = __('%{reportType} detected %{countStart}no%{countEnd} vulnerabilities.');
} else {
message = __(
'%{reportType} detected %{countStart}%{total}%{countEnd} potential %{vulnMessage} %{criticalStart}%{critical} critical%{criticalEnd} %{highStart}%{high} high%{highEnd} and %{otherStart}%{otherMessage}%{otherEnd}',
);
} }
if (high) {
options += HAS_HIGH;
}
if (other) {
options += HAS_OTHER;
}
switch (options) {
case HAS_CRITICAL:
message = n__(
'%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerability.',
'%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities.',
critical,
);
break;
case HAS_HIGH:
message = n__(
'%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerability.',
'%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerabilities.',
high,
);
break;
case HAS_OTHER:
message = n__(
'%{reportType} %{status} detected %{other} vulnerability.',
'%{reportType} %{status} detected %{other} vulnerabilities.',
other,
);
break;
case HAS_CRITICAL + HAS_HIGH:
message = __(
'%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities.',
);
break;
case HAS_CRITICAL + HAS_OTHER:
message = __(
'%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities out of %{total}.',
);
break;
case HAS_HIGH + HAS_OTHER:
message = __(
'%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}.',
);
break;
case HAS_CRITICAL + HAS_HIGH + HAS_OTHER: return {
message = __( message: sprintf(message, {
'%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}.', critical,
); high,
break; otherMessage,
reportType,
default: status,
message = __('%{reportType} %{status} detected no vulnerabilities.'); total,
} vulnMessage,
}).replace(/\s\s+/g, ' '),
return sprintf(message, {
reportType,
status,
critical, critical,
high, high,
other, other,
total: critical + high + other, status,
}).replace(/\s\s+/g, ' '); };
}; };
export const statusIcon = (loading = false, failed = false, newIssues = 0, neutralIssues = 0) => { export const statusIcon = (loading = false, failed = false, newIssues = 0, neutralIssues = 0) => {
...@@ -156,11 +101,11 @@ export const countVulnerabilities = (vulnerabilities = []) => { ...@@ -156,11 +101,11 @@ export const countVulnerabilities = (vulnerabilities = []) => {
*/ */
export const groupedReportText = (report, reportType, errorMessage, loadingMessage) => { export const groupedReportText = (report, reportType, errorMessage, loadingMessage) => {
if (report.hasError) { if (report.hasError) {
return errorMessage; return { message: errorMessage };
} }
if (report.isLoading) { if (report.isLoading) {
return loadingMessage; return { message: loadingMessage };
} }
return groupedTextBuilder({ return groupedTextBuilder({
......
---
title: Update MR widget vulnerability message
merge_request: 46167
author:
type: changed
...@@ -140,7 +140,7 @@ describe('ee merge request widget options', () => { ...@@ -140,7 +140,7 @@ describe('ee merge request widget options', () => {
`${SAST_SELECTOR} .report-block-list-issue-description`, `${SAST_SELECTOR} .report-block-list-issue-description`,
).textContent, ).textContent,
), ),
).toEqual('SAST detected 1 critical severity vulnerability.'); ).toEqual('SAST detected 1 potential vulnerability 1 critical 0 high and 0 Others');
done(); done();
}); });
}); });
...@@ -235,7 +235,9 @@ describe('ee merge request widget options', () => { ...@@ -235,7 +235,9 @@ describe('ee merge request widget options', () => {
`${DEPENDENCY_SCANNING_SELECTOR} .report-block-list-issue-description`, `${DEPENDENCY_SCANNING_SELECTOR} .report-block-list-issue-description`,
).textContent, ).textContent,
), ),
).toEqual('Dependency scanning detected 1 critical and 1 high severity vulnerabilities.'); ).toContain(
'Dependency scanning detected 2 potential vulnerabilities 1 critical 1 high and 0 Others',
);
done(); done();
}); });
}); });
...@@ -660,7 +662,9 @@ describe('ee merge request widget options', () => { ...@@ -660,7 +662,9 @@ describe('ee merge request widget options', () => {
`${CONTAINER_SCANNING_SELECTOR} .report-block-list-issue-description`, `${CONTAINER_SCANNING_SELECTOR} .report-block-list-issue-description`,
).textContent, ).textContent,
), ),
).toEqual('Container scanning detected 1 critical and 1 high severity vulnerabilities.'); ).toEqual(
'Container scanning detected 2 potential vulnerabilities 1 critical 1 high and 0 Others',
);
done(); done();
}); });
}); });
...@@ -733,7 +737,7 @@ describe('ee merge request widget options', () => { ...@@ -733,7 +737,7 @@ describe('ee merge request widget options', () => {
findExtendedSecurityWidget() findExtendedSecurityWidget()
.querySelector(`${DAST_SELECTOR} .report-block-list-issue-description`) .querySelector(`${DAST_SELECTOR} .report-block-list-issue-description`)
.textContent.trim(), .textContent.trim(),
).toEqual('DAST detected 1 critical severity vulnerability.'); ).toContain('DAST detected 1 potential vulnerability');
done(); done();
}); });
}); });
...@@ -809,7 +813,7 @@ describe('ee merge request widget options', () => { ...@@ -809,7 +813,7 @@ describe('ee merge request widget options', () => {
findExtendedSecurityWidget() findExtendedSecurityWidget()
.querySelector(`${COVERAGE_FUZZING_SELECTOR} .report-block-list-issue-description`) .querySelector(`${COVERAGE_FUZZING_SELECTOR} .report-block-list-issue-description`)
.textContent.trim(), .textContent.trim(),
).toEqual('Coverage fuzzing detected 1 critical and 1 high severity vulnerabilities.'); ).toContain('Coverage fuzzing detected 2 potential vulnerabilities');
done(); done();
}); });
}); });
...@@ -884,7 +888,9 @@ describe('ee merge request widget options', () => { ...@@ -884,7 +888,9 @@ describe('ee merge request widget options', () => {
`${SECRET_SCANNING_SELECTOR} .report-block-list-issue-description`, `${SECRET_SCANNING_SELECTOR} .report-block-list-issue-description`,
).textContent, ).textContent,
), ),
).toEqual('Secret scanning detected 1 critical and 1 high severity vulnerabilities.'); ).toEqual(
'Secret scanning detected 2 potential vulnerabilities 1 critical 1 high and 0 Others',
);
done(); done();
}); });
}); });
......
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Severity Summary given the message "" interpolates correctly 1`] = `<div />`; exports[`Severity Summary given the message {"critical": 0, "high": 1, "message": "Security scanning detected %{countStart}1%{countEnd} potential vulnerability %{criticalStart}0 critical%{criticalEnd} %{highStart}1 high%{highEnd} and %{otherStart}0 Others%{otherEnd}", "other": 0, "status": ""} interpolates correctly 1`] = `
<span>
exports[`Severity Summary given the message "%{criticalStart}1 critical%{criticalEnd} and %{highStart}2 high%{highEnd}" interpolates correctly 1`] = ` Security scanning detected
<div> <strong>
<strong 1
class="text-danger-800"
>
1 critical
</strong> </strong>
potential vulnerability
<span>
<span>
0 critical
</span>
</span>
<span>
<strong
class="text-danger-600"
>
1 high
</strong>
</span>
and and
<strong <span>
class="text-danger-600" <span>
> 0 Others
2 high </span>
</strong> </span>
</div> </span>
`; `;
exports[`Severity Summary given the message "%{criticalStart}1 critical%{criticalEnd}" interpolates correctly 1`] = ` exports[`Severity Summary given the message {"critical": 1, "high": 0, "message": "Security scanning detected %{countStart}1%{countEnd} potential vulnerability %{criticalStart}1 critical%{criticalEnd} %{highStart}0 high%{highEnd} and %{otherStart}0 Others%{otherEnd}", "other": 0, "status": ""} interpolates correctly 1`] = `
<div> <span>
<strong Security scanning detected
class="text-danger-800" <strong>
> 1
1 critical
</strong> </strong>
</div> potential vulnerability
<span>
<strong
class="text-danger-800"
>
1 critical
</strong>
</span>
<span>
<span>
0 high
</span>
</span>
and
<span>
<span>
0 Others
</span>
</span>
</span>
`; `;
exports[`Severity Summary given the message "%{highStart}1 high%{highEnd}" interpolates correctly 1`] = ` exports[`Severity Summary given the message {"critical": 1, "high": 2, "message": "Security scanning detected %{countStart}3%{countEnd} potential vulnerabilities %{criticalStart}1 critical%{criticalEnd} %{highStart}2 high%{highEnd} and %{otherStart}0 Others%{otherEnd}", "other": 0, "status": ""} interpolates correctly 1`] = `
<div> <span>
<strong Security scanning detected
class="text-danger-600" <strong>
> 3
1 high
</strong> </strong>
</div> potential vulnerabilities
<span>
<strong
class="text-danger-800"
>
1 critical
</strong>
</span>
<span>
<strong
class="text-danger-600"
>
2 high
</strong>
</span>
and
<span>
<span>
0 Others
</span>
</span>
</span>
`; `;
exports[`Severity Summary given the message "foo" interpolates correctly 1`] = ` exports[`Severity Summary given the message {"message": ""} interpolates correctly 1`] = `<span />`;
<div>
exports[`Severity Summary given the message {"message": "foo"} interpolates correctly 1`] = `
<span>
foo foo
</div> </span>
`; `;
import { mount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
import { groupedTextBuilder } from 'ee/vue_shared/security_reports/store/utils';
import SecuritySummary from 'ee/vue_shared/security_reports/components/security_summary.vue'; import SecuritySummary from 'ee/vue_shared/security_reports/components/security_summary.vue';
describe('Severity Summary', () => { describe('Severity Summary', () => {
let wrapper; let wrapper;
const createWrapper = message => { const createWrapper = message => {
wrapper = mount({ wrapper = shallowMount(SecuritySummary, {
components: { propsData: { message },
SecuritySummary, stubs: {
GlSprintf,
}, },
data() {
return {
message,
};
},
template: `<div><security-summary :message="message" /></div>`,
}); });
}; };
...@@ -24,11 +21,11 @@ describe('Severity Summary', () => { ...@@ -24,11 +21,11 @@ describe('Severity Summary', () => {
}); });
describe.each([ describe.each([
'', { message: '' },
'foo', { message: 'foo' },
'%{criticalStart}1 critical%{criticalEnd}', groupedTextBuilder({ reportType: 'Security scanning', critical: 1, high: 0, total: 1 }),
'%{highStart}1 high%{highEnd}', groupedTextBuilder({ reportType: 'Security scanning', critical: 0, high: 1, total: 1 }),
'%{criticalStart}1 critical%{criticalEnd} and %{highStart}2 high%{highEnd}', groupedTextBuilder({ reportType: 'Security scanning', critical: 1, high: 2, total: 3 }),
])('given the message %p', message => { ])('given the message %p', message => {
beforeEach(() => { beforeEach(() => {
createWrapper(message); createWrapper(message);
......
...@@ -93,7 +93,8 @@ describe('Grouped security reports app', () => { ...@@ -93,7 +93,8 @@ describe('Grouped security reports app', () => {
}); });
afterEach(() => { afterEach(() => {
wrapper.vm.$destroy(); wrapper.destroy();
wrapper = null;
mock.restore(); mock.restore();
}); });
...@@ -275,8 +276,8 @@ describe('Grouped security reports app', () => { ...@@ -275,8 +276,8 @@ describe('Grouped security reports app', () => {
expect(wrapper.vm.$el.querySelector('.gl-spinner')).toBeNull(); expect(wrapper.vm.$el.querySelector('.gl-spinner')).toBeNull();
// Renders the summary text // Renders the summary text
expect(wrapper.vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( expect(wrapper.vm.$el.querySelector('.js-code-text').textContent.trim()).toContain(
'Security scanning detected 6 critical and 4 high severity vulnerabilities.', 'Security scanning detected 10 potential vulnerabilities',
); );
// Renders the expand button // Renders the expand button
...@@ -286,27 +287,25 @@ describe('Grouped security reports app', () => { ...@@ -286,27 +287,25 @@ describe('Grouped security reports app', () => {
// Renders Sast result // Renders Sast result
expect(trimText(wrapper.vm.$el.textContent)).toContain( expect(trimText(wrapper.vm.$el.textContent)).toContain(
'SAST detected 1 critical severity vulnerability', 'SAST detected 1 potential vulnerability',
); );
// Renders DSS result // Renders DSS result
expect(trimText(wrapper.vm.$el.textContent)).toContain( expect(trimText(wrapper.vm.$el.textContent)).toContain(
'Dependency scanning detected 1 critical and 1 high severity vulnerabilities.', 'Dependency scanning detected 2 potential vulnerabilities',
); );
// Renders container scanning result // Renders container scanning result
expect(wrapper.vm.$el.textContent).toContain( expect(wrapper.vm.$el.textContent).toContain(
'Container scanning detected 1 critical and 1 high severity vulnerabilities.', 'Container scanning detected 2 potential vulnerabilities',
); );
// Renders DAST result // Renders DAST result
expect(wrapper.vm.$el.textContent).toContain( expect(wrapper.vm.$el.textContent).toContain('DAST detected 1 potential vulnerability');
'DAST detected 1 critical severity vulnerability.',
);
// Renders container scanning result // Renders container scanning result
expect(wrapper.vm.$el.textContent).toContain( expect(wrapper.vm.$el.textContent).toContain(
'Coverage fuzzing detected 1 critical and 1 high severity vulnerabilities.', 'Coverage fuzzing detected 2 potential vulnerabilities',
); );
}); });
...@@ -427,9 +426,7 @@ describe('Grouped security reports app', () => { ...@@ -427,9 +426,7 @@ describe('Grouped security reports app', () => {
}); });
it('should display the correct numbers of vulnerabilities', () => { it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.text()).toContain( expect(wrapper.text()).toContain('Container scanning detected 2 potential vulnerabilities');
'Container scanning detected 1 critical and 1 high severity vulnerabilities.',
);
}); });
}); });
...@@ -458,7 +455,7 @@ describe('Grouped security reports app', () => { ...@@ -458,7 +455,7 @@ describe('Grouped security reports app', () => {
it('should display the correct numbers of vulnerabilities', () => { it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.vm.$el.textContent).toContain( expect(wrapper.vm.$el.textContent).toContain(
'Dependency scanning detected 1 critical and 1 high severity vulnerabilities.', 'Dependency scanning detected 2 potential vulnerabilities',
); );
}); });
}); });
...@@ -488,9 +485,7 @@ describe('Grouped security reports app', () => { ...@@ -488,9 +485,7 @@ describe('Grouped security reports app', () => {
}); });
it('should display the correct numbers of vulnerabilities', () => { it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.vm.$el.textContent).toContain( expect(wrapper.vm.$el.textContent).toContain('DAST detected 1 potential vulnerability');
'DAST detected 1 critical severity vulnerability',
);
}); });
it('shows the scanned URLs count and opens a modal', async () => { it('shows the scanned URLs count and opens a modal', async () => {
...@@ -570,9 +565,7 @@ describe('Grouped security reports app', () => { ...@@ -570,9 +565,7 @@ describe('Grouped security reports app', () => {
}); });
it('should display the correct numbers of vulnerabilities', () => { it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.text()).toContain( expect(wrapper.text()).toContain('Secret scanning detected 2 potential vulnerabilities');
'Secret scanning detected 1 critical and 1 high severity vulnerabilities.',
);
}); });
}); });
...@@ -609,9 +602,7 @@ describe('Grouped security reports app', () => { ...@@ -609,9 +602,7 @@ describe('Grouped security reports app', () => {
}); });
it('should display the correct numbers of vulnerabilities', () => { it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.vm.$el.textContent).toContain( expect(wrapper.vm.$el.textContent).toContain('SAST detected 1 potential vulnerability');
'SAST detected 1 critical severity vulnerability.',
);
}); });
}); });
......
import createState from 'ee/vue_shared/security_reports/store/state'; import createState from 'ee/vue_shared/security_reports/store/state';
import createSastState from 'ee/vue_shared/security_reports/store/modules/sast/state'; import createSastState from 'ee/vue_shared/security_reports/store/modules/sast/state';
import { groupedTextBuilder } from 'ee/vue_shared/security_reports/store/utils';
import { import {
groupedContainerScanningText, groupedContainerScanningText,
groupedDastText, groupedDastText,
...@@ -47,20 +48,14 @@ describe('Security reports getters', () => { ...@@ -47,20 +48,14 @@ describe('Security reports getters', () => {
${'DAST'} | ${'dast'} | ${groupedDastText} ${'DAST'} | ${'dast'} | ${groupedDastText}
${'Coverage fuzzing'} | ${'coverageFuzzing'} | ${groupedCoverageFuzzingText} ${'Coverage fuzzing'} | ${'coverageFuzzing'} | ${groupedCoverageFuzzingText}
`('grouped text for $name', ({ name, scanner, getter }) => { `('grouped text for $name', ({ name, scanner, getter }) => {
describe('with no issues', () => {
it('returns no issues text', () => {
expect(getter(state)).toEqual(`${name} detected no vulnerabilities.`);
});
});
it.each` it.each`
vulnerabilities | message vulnerabilities | message
${[]} | ${`${name} detected no vulnerabilities.`} ${[]} | ${groupedTextBuilder({ reportType: name, critical: 0, high: 0, other: 0 })}
${[generateVuln(CRITICAL), generateVuln(CRITICAL)]} | ${`${name} detected %{criticalStart}2 critical%{criticalEnd} severity vulnerabilities.`} ${[generateVuln(CRITICAL), generateVuln(CRITICAL)]} | ${groupedTextBuilder({ reportType: name, critical: 2, high: 0, other: 0 })}
${[generateVuln(HIGH), generateVuln(HIGH)]} | ${`${name} detected %{highStart}2 high%{highEnd} severity vulnerabilities.`} ${[generateVuln(HIGH), generateVuln(HIGH)]} | ${groupedTextBuilder({ reportType: name, critical: 0, high: 2, other: 0 })}
${[generateVuln(LOW), generateVuln(MEDIUM)]} | ${`${name} detected 2 vulnerabilities.`} ${[generateVuln(LOW), generateVuln(MEDIUM)]} | ${groupedTextBuilder({ reportType: name, critical: 0, high: 0, other: 2 })}
${[generateVuln(CRITICAL), generateVuln(HIGH)]} | ${`${name} detected %{criticalStart}1 critical%{criticalEnd} and %{highStart}1 high%{highEnd} severity vulnerabilities.`} ${[generateVuln(CRITICAL), generateVuln(HIGH)]} | ${groupedTextBuilder({ reportType: name, critical: 1, high: 1, other: 0 })}
${[generateVuln(CRITICAL), generateVuln(LOW)]} | ${`${name} detected %{criticalStart}1 critical%{criticalEnd} severity vulnerabilities out of 2.`} ${[generateVuln(CRITICAL), generateVuln(LOW)]} | ${groupedTextBuilder({ reportType: name, critical: 1, high: 0, other: 1 })}
`('should build the message as "$message"', ({ vulnerabilities, message }) => { `('should build the message as "$message"', ({ vulnerabilities, message }) => {
state[scanner].newIssues = vulnerabilities; state[scanner].newIssues = vulnerabilities;
expect(getter(state)).toEqual(message); expect(getter(state)).toEqual(message);
...@@ -113,7 +108,7 @@ describe('Security reports getters', () => { ...@@ -113,7 +108,7 @@ describe('Security reports getters', () => {
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {}, summaryCounts: {},
}), }),
).toEqual('Security scanning failed loading any results'); ).toEqual({ message: 'Security scanning failed loading any results' });
}); });
it('returns is loading text', () => { it('returns is loading text', () => {
...@@ -123,21 +118,14 @@ describe('Security reports getters', () => { ...@@ -123,21 +118,14 @@ describe('Security reports getters', () => {
areReportsLoading: true, areReportsLoading: true,
summaryCounts: {}, summaryCounts: {},
}), }),
).toContain('(is loading)');
});
it('returns vulnerabilities while loading text', () => {
expect(
groupedSummaryText(state, {
allReportsHaveError: false,
areReportsLoading: true,
summaryCounts: {
critical: 2,
high: 4,
},
}),
).toEqual( ).toEqual(
'Security scanning (is loading) detected %{criticalStart}2 critical%{criticalEnd} and %{highStart}4 high%{highEnd} severity vulnerabilities.', groupedTextBuilder({
reportType: 'Security scanning',
critical: 0,
high: 0,
other: 0,
status: 'is loading',
}),
); );
}); });
...@@ -148,7 +136,15 @@ describe('Security reports getters', () => { ...@@ -148,7 +136,15 @@ describe('Security reports getters', () => {
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {}, summaryCounts: {},
}), }),
).toEqual('Security scanning detected no vulnerabilities.'); ).toEqual(
groupedTextBuilder({
reportType: 'Security scanning',
critical: 0,
high: 0,
other: 0,
status: '',
}),
);
}); });
}); });
......
...@@ -15,21 +15,27 @@ describe('groupedSastText', () => { ...@@ -15,21 +15,27 @@ describe('groupedSastText', () => {
const sast = createReport({ hasError: true }); const sast = createReport({ hasError: true });
const result = getters.groupedSastText(sast); const result = getters.groupedSastText(sast);
expect(result).toBe(SAST_HAS_ERROR); expect(result).toStrictEqual({ message: SAST_HAS_ERROR });
}); });
it("should return the loading message if it's still loading", () => { it("should return the loading message if it's still loading", () => {
const sast = createReport({ isLoading: true }); const sast = createReport({ isLoading: true });
const result = getters.groupedSastText(sast); const result = getters.groupedSastText(sast);
expect(result).toBe(SAST_IS_LOADING); expect(result).toStrictEqual({ message: SAST_IS_LOADING });
}); });
it('should call groupedTextBuilder if everything is fine', () => { it('should call groupedTextBuilder if everything is fine', () => {
const sast = createReport(); const sast = createReport();
const result = getters.groupedSastText(sast); const result = getters.groupedSastText(sast);
expect(result).toBe('SAST detected no vulnerabilities.'); expect(result).toStrictEqual({
critical: 0,
high: 0,
message: 'SAST detected %{countStart}no%{countEnd} vulnerabilities.',
other: 0,
status: '',
});
}); });
}); });
......
...@@ -117,38 +117,44 @@ describe('security reports utils', () => { ...@@ -117,38 +117,44 @@ describe('security reports utils', () => {
it.each` it.each`
vulnerabilities | message vulnerabilities | message
${undefined} | ${' detected no vulnerabilities.'} ${undefined} | ${' detected %{countStart}no%{countEnd} vulnerabilities.'}
${{ critical }} | ${' detected %{criticalStart}2 critical%{criticalEnd} severity vulnerabilities.'} ${{ critical }} | ${` detected %{countStart}2%{countEnd} potential vulnerabilities %{criticalStart}2 critical%{criticalEnd} %{highStart}0 high%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ high }} | ${' detected %{highStart}4 high%{highEnd} severity vulnerabilities.'} ${{ high }} | ${` detected %{countStart}4%{countEnd} potential vulnerabilities %{criticalStart}0 critical%{criticalEnd} %{highStart}4 high%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ other }} | ${' detected 7 vulnerabilities.'} ${{ other }} | ${` detected %{countStart}7%{countEnd} potential vulnerabilities %{criticalStart}0 critical%{criticalEnd} %{highStart}0 high%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
${{ critical, high }} | ${' detected %{criticalStart}2 critical%{criticalEnd} and %{highStart}4 high%{highEnd} severity vulnerabilities.'} ${{ critical, high }} | ${` detected %{countStart}6%{countEnd} potential vulnerabilities %{criticalStart}2 critical%{criticalEnd} %{highStart}4 high%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ critical, other }} | ${' detected %{criticalStart}2 critical%{criticalEnd} severity vulnerabilities out of 9.'} ${{ critical, other }} | ${` detected %{countStart}9%{countEnd} potential vulnerabilities %{criticalStart}2 critical%{criticalEnd} %{highStart}0 high%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
${{ high, other }} | ${' detected %{highStart}4 high%{highEnd} severity vulnerabilities out of 11.'} ${{ high, other }} | ${` detected %{countStart}11%{countEnd} potential vulnerabilities %{criticalStart}0 critical%{criticalEnd} %{highStart}4 high%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
${{ critical, high, other }} | ${' detected %{criticalStart}2 critical%{criticalEnd} and %{highStart}4 high%{highEnd} severity vulnerabilities out of 13.'} ${{ critical, high, other }} | ${` detected %{countStart}13%{countEnd} potential vulnerabilities %{criticalStart}2 critical%{criticalEnd} %{highStart}4 high%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
`('should build the message as "$message"', ({ vulnerabilities, message }) => { `('should build the message as "$message"', ({ vulnerabilities, message }) => {
expect(groupedTextBuilder(vulnerabilities)).toEqual(message); expect(groupedTextBuilder(vulnerabilities).message).toEqual(message);
}); });
it.each` it.each`
vulnerabilities | message vulnerabilities | message
${{ critical: 1 }} | ${' detected %{criticalStart}1 critical%{criticalEnd} severity vulnerability.'} ${{ critical: 1 }} | ${` detected %{countStart}1%{countEnd} potential vulnerability %{criticalStart}1 critical%{criticalEnd} %{highStart}0 high%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ high: 1 }} | ${' detected %{highStart}1 high%{highEnd} severity vulnerability.'} ${{ high: 1 }} | ${` detected %{countStart}1%{countEnd} potential vulnerability %{criticalStart}0 critical%{criticalEnd} %{highStart}1 high%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ other: 1 }} | ${' detected 1 vulnerability.'} ${{ other: 1 }} | ${` detected %{countStart}1%{countEnd} potential vulnerability %{criticalStart}0 critical%{criticalEnd} %{highStart}0 high%{highEnd} and %{otherStart}1 Other%{otherEnd}`}
`('should handle single vulnerabilities for "$message"', ({ vulnerabilities, message }) => { `('should handle single vulnerabilities for "$message"', ({ vulnerabilities, message }) => {
expect(groupedTextBuilder(vulnerabilities)).toEqual(message); expect(groupedTextBuilder(vulnerabilities).message).toEqual(message);
}); });
it('should pass through the report type', () => { it('should pass through the report type', () => {
const reportType = 'HAL'; const reportType = 'HAL';
expect(groupedTextBuilder({ reportType })).toEqual('HAL detected no vulnerabilities.'); expect(groupedTextBuilder({ reportType }).message).toEqual(
'HAL detected %{countStart}no%{countEnd} vulnerabilities.',
);
}); });
it('should pass through the status', () => { it('should pass through the status', () => {
const reportType = 'HAL'; const reportType = 'HAL';
const status = '(is loading)'; const status = 'is loading';
expect(groupedTextBuilder({ reportType, status })).toEqual( expect(groupedTextBuilder({ reportType, status })).toEqual({
'HAL (is loading) detected no vulnerabilities.', critical: 0,
); high: 0,
message: 'HAL is loading',
other: 0,
status: 'is loading',
});
}); });
}); });
...@@ -202,21 +208,27 @@ describe('security reports utils', () => { ...@@ -202,21 +208,27 @@ describe('security reports utils', () => {
const report = { ...baseReport, hasError: true }; const report = { ...baseReport, hasError: true };
const result = groupedReportText(report, reportType, errorMessage, loadingMessage); const result = groupedReportText(report, reportType, errorMessage, loadingMessage);
expect(result).toBe(errorMessage); expect(result).toStrictEqual({ message: errorMessage });
}); });
it("should return the loading message when it's loading", () => { it("should return the loading message when it's loading", () => {
const report = { ...baseReport, isLoading: true }; const report = { ...baseReport, isLoading: true };
const result = groupedReportText(report, reportType, errorMessage, loadingMessage); const result = groupedReportText(report, reportType, errorMessage, loadingMessage);
expect(result).toBe(loadingMessage); expect(result).toStrictEqual({ message: loadingMessage });
}); });
it("should call groupedTextBuilder if it isn't loading and doesn't have an error", () => { it("should call groupedTextBuilder if it isn't loading and doesn't have an error", () => {
const report = { ...baseReport }; const report = { ...baseReport };
const result = groupedReportText(report, reportType, errorMessage, loadingMessage); const result = groupedReportText(report, reportType, errorMessage, loadingMessage);
expect(result).toBe(`${reportType} detected no vulnerabilities.`); expect(result).toStrictEqual({
critical: 0,
high: 0,
message: 'dummyReport detected %{countStart}no%{countEnd} vulnerabilities.',
other: 0,
status: '',
});
}); });
}); });
}); });
...@@ -82,6 +82,11 @@ msgid_plural "%d Approvals" ...@@ -82,6 +82,11 @@ msgid_plural "%d Approvals"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "%d Other"
msgid_plural "%d Others"
msgstr[0] ""
msgstr[1] ""
msgid "%d Package" msgid "%d Package"
msgid_plural "%d Packages" msgid_plural "%d Packages"
msgstr[0] "" msgstr[0] ""
...@@ -710,34 +715,13 @@ msgstr[1] "" ...@@ -710,34 +715,13 @@ msgstr[1] ""
msgid "%{remaining_approvals} left" msgid "%{remaining_approvals} left"
msgstr "" msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}." msgid "%{reportType} %{status}"
msgstr "" msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities." msgid "%{reportType} detected %{countStart}%{total}%{countEnd} potential %{vulnMessage} %{criticalStart}%{critical} critical%{criticalEnd} %{highStart}%{high} high%{highEnd} and %{otherStart}%{otherMessage}%{otherEnd}"
msgstr "" msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities out of %{total}." msgid "%{reportType} detected %{countStart}no%{countEnd} vulnerabilities."
msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerability."
msgid_plural "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities."
msgstr[0] ""
msgstr[1] ""
msgid "%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}."
msgstr ""
msgid "%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerability."
msgid_plural "%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerabilities."
msgstr[0] ""
msgstr[1] ""
msgid "%{reportType} %{status} detected %{other} vulnerability."
msgid_plural "%{reportType} %{status} detected %{other} vulnerabilities."
msgstr[0] ""
msgstr[1] ""
msgid "%{reportType} %{status} detected no vulnerabilities."
msgstr "" msgstr ""
msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}." msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}."
...@@ -31539,13 +31523,7 @@ msgstr "" ...@@ -31539,13 +31523,7 @@ msgstr ""
msgid "ciReport|%{sameNum} same" msgid "ciReport|%{sameNum} same"
msgstr "" msgstr ""
msgid "ciReport|(errors when loading results)" msgid "ciReport|: Loading resulted in an error"
msgstr ""
msgid "ciReport|(is loading)"
msgstr ""
msgid "ciReport|(is loading, errors when loading results)"
msgstr "" msgstr ""
msgid "ciReport|All projects" msgid "ciReport|All projects"
...@@ -31712,6 +31690,12 @@ msgstr[1] "" ...@@ -31712,6 +31690,12 @@ msgstr[1] ""
msgid "ciReport|View full report" msgid "ciReport|View full report"
msgstr "" msgstr ""
msgid "ciReport|is loading"
msgstr ""
msgid "ciReport|is loading, errors when loading results"
msgstr ""
msgid "closed issue" msgid "closed issue"
msgstr "" msgstr ""
...@@ -32814,6 +32798,11 @@ msgstr "" ...@@ -32814,6 +32798,11 @@ msgstr ""
msgid "view the source" msgid "view the source"
msgstr "" msgstr ""
msgid "vulnerability"
msgid_plural "vulnerabilities"
msgstr[0] ""
msgstr[1] ""
msgid "vulnerability|Add a comment" msgid "vulnerability|Add a comment"
msgstr "" msgstr ""
......
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