Commit 41611031 authored by Mark Florian's avatar Mark Florian

Merge branch '267103-update-mr-widget-vulnerability-message' into 'master'

Update MR widget vulnerability message

See merge request gitlab-org/gitlab!46167
parents 0d0f9a2e 3ca43788
......@@ -2,27 +2,58 @@
import { GlSprintf } from '@gitlab/ui';
import { SEVERITY_CLASS_NAME_MAP } from './constants';
const makeSeveritySlot = (createElement, severity) => ({ content }) =>
createElement('strong', { class: SEVERITY_CLASS_NAME_MAP[severity] }, content);
export default {
functional: true,
components: {
GlSprintf,
},
props: {
message: {
type: String,
type: Object,
required: true,
},
},
render(createElement, context) {
const { message } = context.props;
return createElement(GlSprintf, {
props: { message },
scopedSlots: {
critical: makeSeveritySlot(createElement, 'critical'),
high: makeSeveritySlot(createElement, 'high'),
computed: {
shouldShowCountMessage() {
return !this.message.status && Boolean(this.message.countMessage);
},
},
});
methods: {
getSeverityClass(severity) {
return SEVERITY_CLASS_NAME_MAP[severity];
},
},
slotNames: ['critical', 'high', 'other'],
spacingClasses: {
critical: 'gl-pl-4',
high: 'gl-px-2',
other: 'gl-px-2',
},
};
</script>
<template>
<span>
<gl-sprintf :message="message.message">
<template #total="{content}">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
<span v-if="shouldShowCountMessage" class="gl-font-sm">
<gl-sprintf :message="message.countMessage">
<template v-for="slotName in $options.slotNames" #[slotName]="{content}">
<span :key="slotName">
<strong
v-if="message[slotName] > 0"
:class="[getSeverityClass(slotName), $options.spacingClasses[slotName]]"
>
{{ content }}
</strong>
<span v-else :class="$options.spacingClasses[slotName]">
{{ content }}
</span>
</span>
</template>
</gl-sprintf>
</span>
</span>
</template>
......@@ -555,7 +555,6 @@ export default {
<template v-if="hasCoverageFuzzingReports">
<summary-row
:summary="groupedCoverageFuzzingText"
:status-icon="coverageFuzzingStatusIcon"
:popover-options="coverageFuzzingPopover"
class="js-coverage-fuzzing-widget"
......
......@@ -64,20 +64,20 @@ export const groupedSummaryText = (state, getters) => {
// All reports are loading
if (getters.areAllReportsLoading) {
return sprintf(messages.TRANSLATION_IS_LOADING, { reportType });
return { message: sprintf(messages.TRANSLATION_IS_LOADING, { reportType }) };
}
// All reports returned error
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) {
status = s__('ciReport|(is loading, errors when loading results)');
status = s__('ciReport|is loading, errors when loading results');
} else if (getters.areReportsLoading && !getters.anyReportHasError) {
status = s__('ciReport|(is loading)');
status = s__('ciReport|is loading');
} 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;
......
......@@ -9,15 +9,38 @@ import { __, n__, sprintf } from '~/locale';
export const findIssueIndex = (issues, issue) =>
issues.findIndex(el => el.project_fingerprint === issue.project_fingerprint);
const createCountMessage = ({ critical, high, other, total }) => {
const otherMessage = n__('%d Other', '%d Others', other);
const countMessage = __(
'%{criticalStart}%{critical} Critical%{criticalEnd} %{highStart}%{high} High%{highEnd} and %{otherStart}%{otherMessage}%{otherEnd}',
);
return total ? sprintf(countMessage, { critical, high, otherMessage }) : '';
};
const createStatusMessage = ({ reportType, status, total }) => {
const vulnMessage = n__('vulnerability', 'vulnerabilities', total);
let message;
if (status) {
message = __('%{reportType} %{status}');
} else if (!total) {
message = __('%{reportType} detected %{totalStart}no%{totalEnd} vulnerabilities.');
} else {
message = __(
'%{reportType} detected %{totalStart}%{total}%{totalEnd} potential %{vulnMessage}',
);
}
return sprintf(message, { reportType, status, total, vulnMessage });
};
/**
* 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 resulting string _may_ still contain sprintf-style placeholders. These
* are left in place so they can be replaced with markup, via the
* SecuritySummary component.
* @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 = ({
reportType = '',
......@@ -26,92 +49,17 @@ export const groupedTextBuilder = ({
high = 0,
other = 0,
} = {}) => {
// This approach uses bitwise (ish) flags to determine which vulnerabilities
// we have, without the need for too many nested levels of if/else statements.
//
// 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;
const total = critical + high + other;
if (critical) {
options += HAS_CRITICAL;
}
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.',
return {
countMessage: createCountMessage({ critical, high, other, total }),
message: createStatusMessage({ reportType, status, total }),
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:
message = __(
'%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}.',
);
break;
default:
message = __('%{reportType} %{status} detected no vulnerabilities.');
}
return sprintf(message, {
reportType,
status,
critical,
high,
other,
total: critical + high + other,
}).replace(/\s\s+/g, ' ');
total,
};
};
export const statusIcon = (loading = false, failed = false, newIssues = 0, neutralIssues = 0) => {
......@@ -156,11 +104,11 @@ export const countVulnerabilities = (vulnerabilities = []) => {
*/
export const groupedReportText = (report, reportType, errorMessage, loadingMessage) => {
if (report.hasError) {
return errorMessage;
return { message: errorMessage };
}
if (report.isLoading) {
return loadingMessage;
return { message: loadingMessage };
}
return groupedTextBuilder({
......
---
title: Update MR widget vulnerability message
merge_request: 46167
author:
type: changed
......@@ -140,7 +140,7 @@ describe('ee merge request widget options', () => {
`${SAST_SELECTOR} .report-block-list-issue-description`,
).textContent,
),
).toEqual('SAST detected 1 critical severity vulnerability.');
).toEqual('SAST detected 1 potential vulnerability 1 Critical 0 High and 0 Others');
done();
});
});
......@@ -235,7 +235,9 @@ describe('ee merge request widget options', () => {
`${DEPENDENCY_SCANNING_SELECTOR} .report-block-list-issue-description`,
).textContent,
),
).toEqual('Dependency scanning detected 1 critical and 1 high severity vulnerabilities.');
).toEqual(
'Dependency scanning detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
done();
});
});
......@@ -660,7 +662,9 @@ describe('ee merge request widget options', () => {
`${CONTAINER_SCANNING_SELECTOR} .report-block-list-issue-description`,
).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();
});
});
......@@ -730,10 +734,12 @@ describe('ee merge request widget options', () => {
it('should render provided data', done => {
setImmediate(() => {
expect(
findExtendedSecurityWidget()
.querySelector(`${DAST_SELECTOR} .report-block-list-issue-description`)
.textContent.trim(),
).toEqual('DAST detected 1 critical severity vulnerability.');
trimText(
findExtendedSecurityWidget().querySelector(
`${DAST_SELECTOR} .report-block-list-issue-description`,
).textContent,
),
).toEqual('DAST detected 1 potential vulnerability 1 Critical 0 High and 0 Others');
done();
});
});
......@@ -806,10 +812,14 @@ describe('ee merge request widget options', () => {
it('should render provided data', done => {
setImmediate(() => {
expect(
findExtendedSecurityWidget()
.querySelector(`${COVERAGE_FUZZING_SELECTOR} .report-block-list-issue-description`)
.textContent.trim(),
).toEqual('Coverage fuzzing detected 1 critical and 1 high severity vulnerabilities.');
trimText(
findExtendedSecurityWidget().querySelector(
`${COVERAGE_FUZZING_SELECTOR} .report-block-list-issue-description`,
).textContent,
),
).toEqual(
'Coverage fuzzing detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
done();
});
});
......@@ -884,7 +894,9 @@ describe('ee merge request widget options', () => {
`${SECRET_SCANNING_SELECTOR} .report-block-list-issue-description`,
).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();
});
});
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Severity Summary given the message "" interpolates correctly 1`] = `<div />`;
exports[`Severity Summary given the message {"countMessage": "%{criticalStart}0 Critical%{criticalEnd} %{highStart}1 High%{highEnd} and %{otherStart}0 Others%{otherEnd}", "critical": 0, "high": 1, "message": "Security scanning detected %{totalStart}1%{totalEnd} potential vulnerability", "other": 0, "status": "", "total": 1} interpolates correctly 1`] = `
<span>
Security scanning detected
<strong>
1
</strong>
potential vulnerability
<span
class="gl-font-sm"
>
<span>
<span
class="gl-pl-4"
>
0 Critical
</span>
</span>
exports[`Severity Summary given the message "%{criticalStart}1 critical%{criticalEnd} and %{highStart}2 high%{highEnd}" interpolates correctly 1`] = `
<div>
<span>
<strong
class="text-danger-800"
class="text-danger-600 gl-px-2"
>
1 critical
1 High
</strong>
</span>
and
<span>
<span
class="gl-px-2"
>
0 Others
</span>
</span>
</span>
</span>
`;
exports[`Severity Summary given the message {"countMessage": "%{criticalStart}1 Critical%{criticalEnd} %{highStart}0 High%{highEnd} and %{otherStart}0 Others%{otherEnd}", "critical": 1, "high": 0, "message": "Security scanning detected %{totalStart}1%{totalEnd} potential vulnerability", "other": 0, "status": "", "total": 1} interpolates correctly 1`] = `
<span>
Security scanning detected
<strong>
1
</strong>
potential vulnerability
<span
class="gl-font-sm"
>
<span>
<strong
class="text-danger-600"
class="text-danger-800 gl-pl-4"
>
2 high
1 Critical
</strong>
</div>
</span>
<span>
<span
class="gl-px-2"
>
0 High
</span>
</span>
and
<span>
<span
class="gl-px-2"
>
0 Others
</span>
</span>
</span>
</span>
`;
exports[`Severity Summary given the message "%{criticalStart}1 critical%{criticalEnd}" interpolates correctly 1`] = `
<div>
exports[`Severity Summary given the message {"countMessage": "%{criticalStart}1 Critical%{criticalEnd} %{highStart}2 High%{highEnd} and %{otherStart}0 Others%{otherEnd}", "critical": 1, "high": 2, "message": "Security scanning detected %{totalStart}3%{totalEnd} potential vulnerabilities", "other": 0, "status": "", "total": 3} interpolates correctly 1`] = `
<span>
Security scanning detected
<strong>
3
</strong>
potential vulnerabilities
<span
class="gl-font-sm"
>
<span>
<strong
class="text-danger-800"
class="text-danger-800 gl-pl-4"
>
1 critical
1 Critical
</strong>
</div>
`;
</span>
exports[`Severity Summary given the message "%{highStart}1 high%{highEnd}" interpolates correctly 1`] = `
<div>
<span>
<strong
class="text-danger-600"
class="text-danger-600 gl-px-2"
>
1 high
2 High
</strong>
</div>
</span>
and
<span>
<span
class="gl-px-2"
>
0 Others
</span>
</span>
</span>
</span>
`;
exports[`Severity Summary given the message {"message": ""} interpolates correctly 1`] = `
<span>
<!---->
</span>
`;
exports[`Severity Summary given the message "foo" interpolates correctly 1`] = `
<div>
exports[`Severity Summary given the message {"message": "foo"} interpolates correctly 1`] = `
<span>
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';
describe('Severity Summary', () => {
let wrapper;
const createWrapper = message => {
wrapper = mount({
components: {
SecuritySummary,
wrapper = shallowMount(SecuritySummary, {
propsData: { message },
stubs: {
GlSprintf,
},
data() {
return {
message,
};
},
template: `<div><security-summary :message="message" /></div>`,
});
};
......@@ -24,11 +21,11 @@ describe('Severity Summary', () => {
});
describe.each([
'',
'foo',
'%{criticalStart}1 critical%{criticalEnd}',
'%{highStart}1 high%{highEnd}',
'%{criticalStart}1 critical%{criticalEnd} and %{highStart}2 high%{highEnd}',
{ message: '' },
{ message: 'foo' },
groupedTextBuilder({ reportType: 'Security scanning', critical: 1, high: 0, total: 1 }),
groupedTextBuilder({ reportType: 'Security scanning', critical: 0, high: 1, total: 1 }),
groupedTextBuilder({ reportType: 'Security scanning', critical: 1, high: 2, total: 3 }),
])('given the message %p', message => {
beforeEach(() => {
createWrapper(message);
......
......@@ -93,7 +93,8 @@ describe('Grouped security reports app', () => {
});
afterEach(() => {
wrapper.vm.$destroy();
wrapper.destroy();
wrapper = null;
mock.restore();
});
......@@ -143,9 +144,11 @@ describe('Grouped security reports app', () => {
it('renders error state', () => {
expect(wrapper.vm.$el.querySelector('.gl-spinner')).toBeNull();
expect(wrapper.vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
'Security scanning failed loading any results',
);
expect(
wrapper.vm.$el
.querySelector('[data-testid="report-section-code-text"]')
.textContent.trim(),
).toEqual('Security scanning failed loading any results');
expect(wrapper.vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual(
'Expand',
......@@ -184,9 +187,11 @@ describe('Grouped security reports app', () => {
it('renders loading summary text + spinner', () => {
expect(wrapper.vm.$el.querySelector('.gl-spinner')).not.toBeNull();
expect(wrapper.vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
'Security scanning is loading',
);
expect(
wrapper.vm.$el
.querySelector('[data-testid="report-section-code-text"]')
.textContent.trim(),
).toEqual('Security scanning is loading');
expect(wrapper.vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual(
'Expand',
......@@ -227,9 +232,11 @@ describe('Grouped security reports app', () => {
expect(wrapper.vm.$el.querySelector('.gl-spinner')).toBeNull();
// Renders the summary text
expect(wrapper.vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
'Security scanning detected no vulnerabilities.',
);
expect(
wrapper.vm.$el
.querySelector('[data-testid="report-section-code-text"]')
.textContent.trim(),
).toEqual('Security scanning detected no vulnerabilities.');
// Renders Sast result
expect(trimText(wrapper.vm.$el.textContent)).toContain('SAST detected no vulnerabilities.');
......@@ -275,8 +282,12 @@ describe('Grouped security reports app', () => {
expect(wrapper.vm.$el.querySelector('.gl-spinner')).toBeNull();
// Renders the summary text
expect(wrapper.vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
'Security scanning detected 6 critical and 4 high severity vulnerabilities.',
expect(
trimText(
wrapper.vm.$el.querySelector('[data-testid="report-section-code-text"]').textContent,
),
).toEqual(
'Security scanning detected 10 potential vulnerabilities 6 Critical 4 High and 0 Others',
);
// Renders the expand button
......@@ -286,27 +297,27 @@ describe('Grouped security reports app', () => {
// Renders Sast result
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'SAST detected 1 critical severity vulnerability',
'SAST detected 1 potential vulnerability 1 Critical 0 High and 0 Others',
);
// Renders DSS result
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'Dependency scanning detected 1 critical and 1 high severity vulnerabilities.',
'Dependency scanning detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
// Renders container scanning result
expect(wrapper.vm.$el.textContent).toContain(
'Container scanning detected 1 critical and 1 high severity vulnerabilities.',
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'Container scanning detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
// Renders DAST result
expect(wrapper.vm.$el.textContent).toContain(
'DAST detected 1 critical severity vulnerability.',
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'DAST detected 1 potential vulnerability 1 Critical 0 High and 0 Others',
);
// Renders container scanning result
expect(wrapper.vm.$el.textContent).toContain(
'Coverage fuzzing detected 1 critical and 1 high severity vulnerabilities.',
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'Coverage fuzzing detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
});
......@@ -427,8 +438,8 @@ describe('Grouped security reports app', () => {
});
it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.text()).toContain(
'Container scanning detected 1 critical and 1 high severity vulnerabilities.',
expect(trimText(wrapper.text())).toContain(
'Container scanning detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
});
});
......@@ -457,8 +468,8 @@ describe('Grouped security reports app', () => {
});
it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.vm.$el.textContent).toContain(
'Dependency scanning detected 1 critical and 1 high severity vulnerabilities.',
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'Dependency scanning detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
});
});
......@@ -488,8 +499,8 @@ describe('Grouped security reports app', () => {
});
it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.vm.$el.textContent).toContain(
'DAST detected 1 critical severity vulnerability',
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'DAST detected 1 potential vulnerability 1 Critical 0 High and 0 Others',
);
});
......@@ -570,8 +581,8 @@ describe('Grouped security reports app', () => {
});
it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.text()).toContain(
'Secret scanning detected 1 critical and 1 high severity vulnerabilities.',
expect(trimText(wrapper.text())).toContain(
'Secret scanning detected 2 potential vulnerabilities 1 Critical 1 High and 0 Others',
);
});
});
......@@ -609,8 +620,8 @@ describe('Grouped security reports app', () => {
});
it('should display the correct numbers of vulnerabilities', () => {
expect(wrapper.vm.$el.textContent).toContain(
'SAST detected 1 critical severity vulnerability.',
expect(trimText(wrapper.vm.$el.textContent)).toContain(
'SAST detected 1 potential vulnerability 1 Critical 0 High and 0 Others',
);
});
});
......
import createState from 'ee/vue_shared/security_reports/store/state';
import createSastState from 'ee/vue_shared/security_reports/store/modules/sast/state';
import { groupedTextBuilder } from 'ee/vue_shared/security_reports/store/utils';
import {
groupedContainerScanningText,
groupedDastText,
......@@ -47,20 +48,14 @@ describe('Security reports getters', () => {
${'DAST'} | ${'dast'} | ${groupedDastText}
${'Coverage fuzzing'} | ${'coverageFuzzing'} | ${groupedCoverageFuzzingText}
`('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`
vulnerabilities | message
${[]} | ${`${name} detected no vulnerabilities.`}
${[generateVuln(CRITICAL), generateVuln(CRITICAL)]} | ${`${name} detected %{criticalStart}2 critical%{criticalEnd} severity vulnerabilities.`}
${[generateVuln(HIGH), generateVuln(HIGH)]} | ${`${name} detected %{highStart}2 high%{highEnd} severity vulnerabilities.`}
${[generateVuln(LOW), generateVuln(MEDIUM)]} | ${`${name} detected 2 vulnerabilities.`}
${[generateVuln(CRITICAL), generateVuln(HIGH)]} | ${`${name} detected %{criticalStart}1 critical%{criticalEnd} and %{highStart}1 high%{highEnd} severity vulnerabilities.`}
${[generateVuln(CRITICAL), generateVuln(LOW)]} | ${`${name} detected %{criticalStart}1 critical%{criticalEnd} severity vulnerabilities out of 2.`}
${[]} | ${groupedTextBuilder({ reportType: name, critical: 0, high: 0, other: 0 })}
${[generateVuln(CRITICAL), generateVuln(CRITICAL)]} | ${groupedTextBuilder({ reportType: name, critical: 2, high: 0, other: 0 })}
${[generateVuln(HIGH), generateVuln(HIGH)]} | ${groupedTextBuilder({ reportType: name, critical: 0, high: 2, other: 0 })}
${[generateVuln(LOW), generateVuln(MEDIUM)]} | ${groupedTextBuilder({ reportType: name, critical: 0, high: 0, other: 2 })}
${[generateVuln(CRITICAL), generateVuln(HIGH)]} | ${groupedTextBuilder({ reportType: name, critical: 1, high: 1, other: 0 })}
${[generateVuln(CRITICAL), generateVuln(LOW)]} | ${groupedTextBuilder({ reportType: name, critical: 1, high: 0, other: 1 })}
`('should build the message as "$message"', ({ vulnerabilities, message }) => {
state[scanner].newIssues = vulnerabilities;
expect(getter(state)).toEqual(message);
......@@ -113,7 +108,7 @@ describe('Security reports getters', () => {
areReportsLoading: false,
summaryCounts: {},
}),
).toEqual('Security scanning failed loading any results');
).toEqual({ message: 'Security scanning failed loading any results' });
});
it('returns is loading text', () => {
......@@ -123,21 +118,14 @@ describe('Security reports getters', () => {
areReportsLoading: true,
summaryCounts: {},
}),
).toContain('(is loading)');
});
it('returns vulnerabilities while loading text', () => {
expect(
groupedSummaryText(state, {
allReportsHaveError: false,
areReportsLoading: true,
summaryCounts: {
critical: 2,
high: 4,
},
}),
).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', () => {
areReportsLoading: false,
summaryCounts: {},
}),
).toEqual('Security scanning detected no vulnerabilities.');
).toEqual(
groupedTextBuilder({
reportType: 'Security scanning',
critical: 0,
high: 0,
other: 0,
status: '',
}),
);
});
});
......
......@@ -15,21 +15,29 @@ describe('groupedSastText', () => {
const sast = createReport({ hasError: true });
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", () => {
const sast = createReport({ isLoading: true });
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', () => {
const sast = createReport();
const result = getters.groupedSastText(sast);
expect(result).toBe('SAST detected no vulnerabilities.');
expect(result).toStrictEqual({
countMessage: '',
critical: 0,
high: 0,
message: 'SAST detected %{totalStart}no%{totalEnd} vulnerabilities.',
other: 0,
status: '',
total: 0,
});
});
});
......
......@@ -116,39 +116,52 @@ describe('security reports utils', () => {
const other = 7;
it.each`
vulnerabilities | message
${undefined} | ${' detected no vulnerabilities.'}
${{ critical }} | ${' detected %{criticalStart}2 critical%{criticalEnd} severity vulnerabilities.'}
${{ high }} | ${' detected %{highStart}4 high%{highEnd} severity vulnerabilities.'}
${{ other }} | ${' detected 7 vulnerabilities.'}
${{ critical, high }} | ${' detected %{criticalStart}2 critical%{criticalEnd} and %{highStart}4 high%{highEnd} severity vulnerabilities.'}
${{ critical, other }} | ${' detected %{criticalStart}2 critical%{criticalEnd} severity vulnerabilities out of 9.'}
${{ high, other }} | ${' detected %{highStart}4 high%{highEnd} severity vulnerabilities out of 11.'}
${{ critical, high, other }} | ${' detected %{criticalStart}2 critical%{criticalEnd} and %{highStart}4 high%{highEnd} severity vulnerabilities out of 13.'}
`('should build the message as "$message"', ({ vulnerabilities, message }) => {
expect(groupedTextBuilder(vulnerabilities)).toEqual(message);
vulnerabilities | message | countMessage
${undefined} | ${' detected %{totalStart}no%{totalEnd} vulnerabilities.'} | ${''}
${{ critical }} | ${` detected %{totalStart}2%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}2 Critical%{criticalEnd} %{highStart}0 High%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ high }} | ${` detected %{totalStart}4%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}0 Critical%{criticalEnd} %{highStart}4 High%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ other }} | ${` detected %{totalStart}7%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}0 Critical%{criticalEnd} %{highStart}0 High%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
${{ critical, high }} | ${` detected %{totalStart}6%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}2 Critical%{criticalEnd} %{highStart}4 High%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ critical, other }} | ${` detected %{totalStart}9%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}2 Critical%{criticalEnd} %{highStart}0 High%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
${{ high, other }} | ${` detected %{totalStart}11%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}0 Critical%{criticalEnd} %{highStart}4 High%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
${{ critical, high, other }} | ${` detected %{totalStart}13%{totalEnd} potential vulnerabilities`} | ${`%{criticalStart}2 Critical%{criticalEnd} %{highStart}4 High%{highEnd} and %{otherStart}7 Others%{otherEnd}`}
`('should build the message as "$message"', ({ vulnerabilities, message, countMessage }) => {
expect(groupedTextBuilder(vulnerabilities).message).toEqual(message);
expect(groupedTextBuilder(vulnerabilities).countMessage).toEqual(countMessage);
});
it.each`
vulnerabilities | message
${{ critical: 1 }} | ${' detected %{criticalStart}1 critical%{criticalEnd} severity vulnerability.'}
${{ high: 1 }} | ${' detected %{highStart}1 high%{highEnd} severity vulnerability.'}
${{ other: 1 }} | ${' detected 1 vulnerability.'}
`('should handle single vulnerabilities for "$message"', ({ vulnerabilities, message }) => {
expect(groupedTextBuilder(vulnerabilities)).toEqual(message);
});
vulnerabilities | message | countMessage
${{ critical: 1 }} | ${` detected %{totalStart}1%{totalEnd} potential vulnerability`} | ${`%{criticalStart}1 Critical%{criticalEnd} %{highStart}0 High%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ high: 1 }} | ${` detected %{totalStart}1%{totalEnd} potential vulnerability`} | ${`%{criticalStart}0 Critical%{criticalEnd} %{highStart}1 High%{highEnd} and %{otherStart}0 Others%{otherEnd}`}
${{ other: 1 }} | ${` detected %{totalStart}1%{totalEnd} potential vulnerability`} | ${`%{criticalStart}0 Critical%{criticalEnd} %{highStart}0 High%{highEnd} and %{otherStart}1 Other%{otherEnd}`}
`(
'should handle single vulnerabilities for "$message"',
({ vulnerabilities, message, countMessage }) => {
expect(groupedTextBuilder(vulnerabilities).message).toEqual(message);
expect(groupedTextBuilder(vulnerabilities).countMessage).toEqual(countMessage);
},
);
it('should pass through the report type', () => {
const reportType = 'HAL';
expect(groupedTextBuilder({ reportType })).toEqual('HAL detected no vulnerabilities.');
expect(groupedTextBuilder({ reportType }).message).toEqual(
'HAL detected %{totalStart}no%{totalEnd} vulnerabilities.',
);
});
it('should pass through the status', () => {
const reportType = 'HAL';
const status = '(is loading)';
expect(groupedTextBuilder({ reportType, status })).toEqual(
'HAL (is loading) detected no vulnerabilities.',
);
const status = 'is loading';
expect(groupedTextBuilder({ reportType, status })).toEqual({
countMessage: '',
critical: 0,
high: 0,
message: 'HAL is loading',
other: 0,
status: 'is loading',
total: 0,
});
});
});
......@@ -187,7 +200,7 @@ describe('security reports utils', () => {
${[{ severity: LOW }, { severity: MEDIUM }]} | ${{ critical: 0, high: 0, other: 2 }}
${[{ severity: CRITICAL }, { severity: HIGH }]} | ${{ critical: 1, high: 1, other: 0 }}
${[{ severity: CRITICAL }, { severity: LOW }]} | ${{ critical: 1, high: 0, other: 1 }}
`('should count the vulnerabilities correctly', ({ vulnerabilities, response }) => {
`('should total the vulnerabilities correctly', ({ vulnerabilities, response }) => {
expect(countVulnerabilities(vulnerabilities)).toEqual(response);
});
});
......@@ -202,21 +215,29 @@ describe('security reports utils', () => {
const report = { ...baseReport, hasError: true };
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", () => {
const report = { ...baseReport, isLoading: true };
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", () => {
const report = { ...baseReport };
const result = groupedReportText(report, reportType, errorMessage, loadingMessage);
expect(result).toBe(`${reportType} detected no vulnerabilities.`);
expect(result).toStrictEqual({
countMessage: '',
critical: 0,
high: 0,
message: 'dummyReport detected %{totalStart}no%{totalEnd} vulnerabilities.',
other: 0,
status: '',
total: 0,
});
});
});
});
......@@ -82,6 +82,11 @@ msgid_plural "%d Approvals"
msgstr[0] ""
msgstr[1] ""
msgid "%d Other"
msgid_plural "%d Others"
msgstr[0] ""
msgstr[1] ""
msgid "%d Package"
msgid_plural "%d Packages"
msgstr[0] ""
......@@ -445,6 +450,9 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
msgid "%{criticalStart}%{critical} Critical%{criticalEnd} %{highStart}%{high} High%{highEnd} and %{otherStart}%{otherMessage}%{otherEnd}"
msgstr ""
msgid "%{dashboard_path} could not be found."
msgstr ""
......@@ -710,34 +718,13 @@ msgstr[1] ""
msgid "%{remaining_approvals} left"
msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}."
msgid "%{reportType} %{status}"
msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities."
msgid "%{reportType} detected %{totalStart}%{total}%{totalEnd} potential %{vulnMessage}"
msgstr ""
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities out of %{total}."
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."
msgid "%{reportType} detected %{totalStart}no%{totalEnd} vulnerabilities."
msgstr ""
msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}."
......@@ -31551,13 +31538,7 @@ msgstr ""
msgid "ciReport|%{sameNum} same"
msgstr ""
msgid "ciReport|(errors when loading results)"
msgstr ""
msgid "ciReport|(is loading)"
msgstr ""
msgid "ciReport|(is loading, errors when loading results)"
msgid "ciReport|: Loading resulted in an error"
msgstr ""
msgid "ciReport|All projects"
......@@ -31724,6 +31705,12 @@ msgstr[1] ""
msgid "ciReport|View full report"
msgstr ""
msgid "ciReport|is loading"
msgstr ""
msgid "ciReport|is loading, errors when loading results"
msgstr ""
msgid "closed issue"
msgstr ""
......@@ -32826,6 +32813,11 @@ msgstr ""
msgid "view the source"
msgstr ""
msgid "vulnerability"
msgid_plural "vulnerabilities"
msgstr[0] ""
msgstr[1] ""
msgid "vulnerability|Add a comment"
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