Commit 686125bc authored by Jannik Lehmann's avatar Jannik Lehmann Committed by Ezekiel Kigbo

Enhance Vulnerabilty Report Autofix Indicator

This commit enhances the Vulnerability Report
Autofix Indicator, it adds Merge Requests
and CI-Status to this Indicator.
parent 3067e314
...@@ -92,7 +92,8 @@ the **Failed jobs** tab of the pipeline page. ...@@ -92,7 +92,8 @@ the **Failed jobs** tab of the pipeline page.
The Vulnerability Report next displays the total number of vulnerabilities by severity (for example, The Vulnerability Report next displays the total number of vulnerabilities by severity (for example,
Critical, High, Medium, Low, Info, Unknown). Below this, a table shows each vulnerability's status, severity, Critical, High, Medium, Low, Info, Unknown). Below this, a table shows each vulnerability's status, severity,
and description. Clicking a vulnerability takes you to its [Vulnerability Details](../vulnerabilities) description and if there is a Merge Request related to it. Clicking a vulnerability takes you to its
[Vulnerability Details](../vulnerabilities)
page to view more information about that vulnerability. page to view more information about that vulnerability.
![Project Vulnerability Report](img/project_security_dashboard_v13_5.png) ![Project Vulnerability Report](img/project_security_dashboard_v13_5.png)
......
<script>
import { GlBadge, GlPopover, GlIcon } from '@gitlab/ui';
const ICONCOLOR = {
opened: 'gl-text-green-500',
closed: 'gl-text-red-500',
merged: 'gl-text-blue-500',
};
const ICON = {
opened: 'issue-open-m',
closed: 'issue-close',
merged: 'merge',
};
export default {
components: {
GlBadge,
GlIcon,
GlPopover,
},
props: {
mergeRequest: {
type: Object,
required: true,
},
},
methods: {
getIconColor(state) {
return ICONCOLOR[state] || 'gl-text-gray-500';
},
getIcon(state) {
return ICON[state] || 'issue-open-m';
},
},
};
</script>
<template>
<div ref="popover" data-testid="vulnerability-solutions-bulb">
<gl-badge ref="badge" variant="neutral" icon="merge-request" />
<gl-popover
data-testid="vulnerability-solutions-popover"
:target="() => $refs.popover"
placement="top"
triggers="hover focus"
>
<template #title>
<span>{{ s__('AutoRemediation| 1 Merge Request') }}</span>
</template>
<ul class="gl-list-style-none gl-pl-0 gl-mb-0">
<li class="gl-align-items-center gl-display-flex gl-mb-2">
<gl-icon
data-testid="vulnerability-solutions-popover-icon"
:name="getIcon(mergeRequest.state)"
:size="16"
:class="getIconColor(mergeRequest.state)"
/>
<a
data-testid="vulnerability-solutions-popover-link"
:href="mergeRequest.webUrl"
class="gl-ml-3"
>
<span data-testid="vulnerability-solutions-popover-link-id"
>!{{ mergeRequest.iid
}}<span
v-if="mergeRequest.securityAutoFix"
data-testid="vulnerability-solutions-popover-link-autofix"
>{{ s__('AutoRemediation|: Auto-fix') }}</span
></span
>
</a>
</li>
</ul>
</gl-popover>
</div>
</template>
...@@ -8,9 +8,9 @@ import { ...@@ -8,9 +8,9 @@ import {
GlSkeletonLoading, GlSkeletonLoading,
GlTooltipDirective, GlTooltipDirective,
GlTable, GlTable,
GlBadge,
} from '@gitlab/ui'; } from '@gitlab/ui';
import RemediatedBadge from 'ee/vulnerabilities/components/remediated_badge.vue'; import RemediatedBadge from 'ee/vulnerabilities/components/remediated_badge.vue';
import AutoFixHelpText from 'ee/security_dashboard/components/auto_fix_help_text.vue';
import FiltersProducedNoResults from 'ee/security_dashboard/components/empty_states/filters_produced_no_results.vue'; import FiltersProducedNoResults from 'ee/security_dashboard/components/empty_states/filters_produced_no_results.vue';
import DashboardHasNoVulnerabilities from 'ee/security_dashboard/components/empty_states/dashboard_has_no_vulnerabilities.vue'; import DashboardHasNoVulnerabilities from 'ee/security_dashboard/components/empty_states/dashboard_has_no_vulnerabilities.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
...@@ -37,10 +37,10 @@ export default { ...@@ -37,10 +37,10 @@ export default {
GlSkeletonLoading, GlSkeletonLoading,
GlSprintf, GlSprintf,
GlTable, GlTable,
GlBadge,
GlTruncate, GlTruncate,
IssuesBadge, IssuesBadge,
LocalStorageSync, LocalStorageSync,
AutoFixHelpText,
RemediatedBadge, RemediatedBadge,
SecurityScannerAlert, SecurityScannerAlert,
SelectionSummary, SelectionSummary,
...@@ -439,14 +439,7 @@ export default { ...@@ -439,14 +439,7 @@ export default {
<template #cell(activity)="{ item }"> <template #cell(activity)="{ item }">
<div class="gl-display-flex gl-justify-content-end"> <div class="gl-display-flex gl-justify-content-end">
<gl-badge <auto-fix-help-text v-if="item.hasSolutions" :merge-request="item.mergeRequest" />
v-if="item.hasSolutions"
v-gl-tooltip
data-testid="vulnerability-solutions-bulb"
variant="neutral"
icon="bulb"
:title="s__('AutoRemediation|Auto-fix solution available')"
/>
<issues-badge v-if="issues(item).length > 0" :issues="issues(item)" /> <issues-badge v-if="issues(item).length > 0" :issues="issues(item)" />
<remediated-badge v-if="item.resolvedOnDefaultBranch" class="gl-ml-3" /> <remediated-badge v-if="item.resolvedOnDefaultBranch" class="gl-ml-3" />
</div> </div>
......
...@@ -24,6 +24,12 @@ query project( ...@@ -24,6 +24,12 @@ query project(
nodes { nodes {
...Vulnerability ...Vulnerability
hasSolutions hasSolutions
mergeRequest {
webUrl
state
securityAutoFix
iid
}
} }
pageInfo { pageInfo {
...PageInfo ...PageInfo
......
import { mount } from '@vue/test-utils';
import AutoFixHelpText from 'ee/security_dashboard/components/auto_fix_help_text.vue';
const TEST_MERGE_REQUEST_DATA = {
webUrl: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48820',
state: 'merged',
securityAutoFix: true,
iid: 48820,
};
describe('AutoFix Help Text component', () => {
let wrapper;
const createWrapper = ({ props = {} } = {}) => {
return mount(AutoFixHelpText, {
propsData: {
mergeRequest: TEST_MERGE_REQUEST_DATA,
...props,
},
stubs: {
GlPopover: true,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
beforeEach(() => {
wrapper = createWrapper();
});
const findByTestId = id => wrapper.find(`[data-testid="${id}"]`);
it('popover should have wrapping div as target', () => {
expect(
findByTestId('vulnerability-solutions-popover')
.props()
.target()
.isSameNode(wrapper.find('[data-testid="vulnerability-solutions-bulb"]').element),
).toBe(true);
});
it('popover should contain Icon with passed status', () => {
expect(findByTestId('vulnerability-solutions-popover-icon').props().name).toBe('merge');
});
it('popover should contain Link with passed href', () => {
expect(findByTestId('vulnerability-solutions-popover-link').attributes('href')).toBe(
TEST_MERGE_REQUEST_DATA.webUrl,
);
});
it('popover should contain passed MergeRequest ID', () => {
expect(findByTestId('vulnerability-solutions-popover-link-id').text()).toContain(
`!${TEST_MERGE_REQUEST_DATA.iid}`,
);
});
it('popover should contain Autofix Indicator when available', () => {
expect(findByTestId('vulnerability-solutions-popover-link-autofix').text()).toBe(': Auto-fix');
});
describe('with autofix not available', () => {
beforeEach(() => {
wrapper = createWrapper({
props: {
mergeRequest: {
...TEST_MERGE_REQUEST_DATA,
securityAutoFix: false,
},
},
});
});
it('popover should not contain Autofix Indicator', () => {
expect(findByTestId('vulnerability-solutions-popover-link-autofix').exists()).toBe(false);
});
});
});
...@@ -3,6 +3,12 @@ export const generateVulnerabilities = () => [ ...@@ -3,6 +3,12 @@ export const generateVulnerabilities = () => [
id: 'id_0', id: 'id_0',
detectedAt: '2020-07-29T15:36:54Z', detectedAt: '2020-07-29T15:36:54Z',
hasSolutions: true, hasSolutions: true,
mergeRequest: {
webUrl: 'www.testmr.com/1',
state: 'status_warning',
securityAutoFix: true,
iid: 1,
},
identifiers: [ identifiers: [
{ {
externalType: 'cve', externalType: 'cve',
......
...@@ -4175,10 +4175,13 @@ msgstr "" ...@@ -4175,10 +4175,13 @@ msgstr ""
msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found." msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found."
msgstr "" msgstr ""
msgid "AutoRemediation| 1 Merge Request"
msgstr ""
msgid "AutoRemediation|%{mrsCount} ready for review" msgid "AutoRemediation|%{mrsCount} ready for review"
msgstr "" msgstr ""
msgid "AutoRemediation|Auto-fix solution available" msgid "AutoRemediation|: Auto-fix"
msgstr "" msgstr ""
msgid "AutoRemediation|Auto-fix solutions" msgid "AutoRemediation|Auto-fix solutions"
......
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