Commit 13bb4008 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '217552-evidence-summary-no-longer-appears-on-the-vulnerability-finding' into 'master'

Add evidence and scanner fields to standalone vulnerability page

See merge request gitlab-org/gitlab!34498
parents f2a49133 92bc1bbd
......@@ -9,10 +9,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13561) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.0.
Each security vulnerability in the [Vulnerability List](../dependency_list/index.md) has its own standalone
Each security vulnerability in the [Security Dashboard](../security_dashboard/index.md#project-security-dashboard) has its own standalone
page.
![Standalone vulnerability page](img/standalone_vulnerability_page_v12_10.png)
![Standalone vulnerability page](img/standalone_vulnerability_page_v13_1.png)
On the standalone vulnerability page, you can interact with the vulnerability in
several different ways:
......
<script>
import { GlLink } from '@gitlab/ui';
import { GlLink, GlSprintf } from '@gitlab/ui';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import SafeLink from 'ee/vue_shared/components/safe_link.vue';
import DetailItem from './detail_item.vue';
export default {
name: 'VulnerabilityDetails',
components: { GlLink, SeverityBadge, DetailItem },
components: { GlLink, SeverityBadge, DetailItem, SafeLink, GlSprintf },
props: {
vulnerability: {
type: Object,
......@@ -20,6 +21,9 @@ export default {
location() {
return this.finding.location || {};
},
scanner() {
return this.finding.scanner || {};
},
fileText() {
return (this.location.file || '') + (this.lineNumber ? `:${this.lineNumber}` : '');
},
......@@ -30,6 +34,9 @@ export default {
const { start_line: start, end_line: end } = this.location;
return end > start ? `${start}-${end}` : start;
},
scannerUrl() {
return this.scanner.url || '';
},
},
};
</script>
......@@ -44,12 +51,34 @@ export default {
<detail-item :sprintf-message="__('%{labelStart}Severity:%{labelEnd} %{severity}')">
<severity-badge :severity="vulnerability.severity" class="gl-display-inline ml-1" />
</detail-item>
<detail-item :sprintf-message="__('%{labelStart}Confidence:%{labelEnd} %{confidence}')"
>{{ vulnerability.confidence }}
<detail-item
v-if="finding.evidence"
:sprintf-message="__('%{labelStart}Evidence:%{labelEnd} %{evidence}')"
>{{ finding.evidence }}
</detail-item>
<detail-item :sprintf-message="__('%{labelStart}Report Type:%{labelEnd} %{reportType}')"
>{{ vulnerability.report_type }}
</detail-item>
<detail-item
v-if="scanner.name"
:sprintf-message="__('%{labelStart}Scanner:%{labelEnd} %{scanner}')"
>
<safe-link
:href="scannerUrl"
target="_blank"
rel="noopener noreferrer"
data-testid="scannerSafeLink"
>
<gl-sprintf
v-if="scanner.version"
:message="s__('Vulnerability|%{scannerName} (version %{scannerVersion})')"
>
<template #scannerName>{{ scanner.name }}</template>
<template #scannerVersion>{{ scanner.version }}</template>
</gl-sprintf>
<template v-else>{{ scanner.name }}</template>
</safe-link>
</detail-item>
<detail-item
v-if="location.image"
:sprintf-message="__('%{labelStart}Image:%{labelEnd} %{image}')"
......
......@@ -43,7 +43,9 @@ module VulnerabilitiesHelper
:issue_feedback,
:merge_request_feedback,
:project,
:remediations
:remediations,
:evidence,
:scanner
).merge(
solution: remediation ? remediation['summary'] : finding[:solution]
)
......
---
title: Add evidence and scanner fields to standalone vulnerability page
merge_request: 34498
author:
type: changed
......@@ -39,14 +39,15 @@ describe('Vulnerability Details', () => {
expect(getText('title')).toBe(vulnerability.title);
expect(getText('description')).toBe(finding.description);
expect(wrapper.find(SeverityBadge).props('severity')).toBe(vulnerability.severity);
expect(getText('confidence')).toBe(`Confidence: ${vulnerability.confidence}`);
expect(getText('reportType')).toBe(`Report Type: ${vulnerability.report_type}`);
expect(getById('image').exists()).toBeFalsy();
expect(getById('os').exists()).toBeFalsy();
expect(getById('file').exists()).toBeFalsy();
expect(getById('class').exists()).toBeFalsy();
expect(getById('method').exists()).toBeFalsy();
expect(getById('image').exists()).toBe(false);
expect(getById('os').exists()).toBe(false);
expect(getById('file').exists()).toBe(false);
expect(getById('class').exists()).toBe(false);
expect(getById('method').exists()).toBe(false);
expect(getById('evidence').exists()).toBe(false);
expect(getById('scanner').exists()).toBe(false);
expect(getAllById('link')).toHaveLength(0);
expect(getAllById('identifier')).toHaveLength(0);
});
......@@ -71,6 +72,11 @@ describe('Vulnerability Details', () => {
expect(getText('method')).toBe(`Method: method name`);
});
it('shows the evidence if it exists', () => {
createWrapper({ evidence: 'some evidence' });
expect(getText('evidence')).toBe(`Evidence: some evidence`);
});
it('shows the links if they exist', () => {
createWrapper({ links: [{ url: '0' }, { url: '1' }, { url: '2' }] });
const links = getAllById('link');
......@@ -138,4 +144,33 @@ describe('Vulnerability Details', () => {
expect(file().text()).toBe('test.txt:24');
});
});
describe('scanner', () => {
const link = () => getById('scannerSafeLink');
const scannerText = () => getById('scanner').text();
it('shows the scanner name only but no link', () => {
createWrapper({ scanner: { name: 'some scanner' } });
expect(scannerText()).toBe('Scanner: some scanner');
expect(link().vm.$el instanceof HTMLSpanElement).toBe(true);
});
it('shows the scanner name and version but no link', () => {
createWrapper({ scanner: { name: 'some scanner', version: '1.2.3' } });
expect(scannerText()).toBe('Scanner: some scanner (version 1.2.3)');
expect(link().vm.$el instanceof HTMLSpanElement).toBe(true);
});
it('shows the scanner name only with a link', () => {
createWrapper({ scanner: { name: 'some scanner', url: '//link' } });
expect(scannerText()).toBe('Scanner: some scanner');
expect(link().props('href')).toBe('//link');
});
it('shows the scanner name and version with a link', () => {
createWrapper({ scanner: { name: 'some scanner', version: '1.2.3', url: '//link' } });
expect(scannerText()).toBe('Scanner: some scanner (version 1.2.3)');
expect(link().props('href')).toBe('//link');
});
});
});
......@@ -116,7 +116,9 @@ RSpec.describe VulnerabilitiesHelper do
name: finding.name,
project: kind_of(Grape::Entity::Exposure::NestingExposure::OutputBuilder),
remediations: finding.remediations,
solution: kind_of(String)
solution: kind_of(String),
evidence: kind_of(String),
scanner: kind_of(Grape::Entity::Exposure::NestingExposure::OutputBuilder)
)
expect(subject[:location]['blob_path']).to match(kind_of(String))
......
......@@ -395,7 +395,7 @@ msgstr ""
msgid "%{labelStart}Class:%{labelEnd} %{class}"
msgstr ""
msgid "%{labelStart}Confidence:%{labelEnd} %{confidence}"
msgid "%{labelStart}Evidence:%{labelEnd} %{evidence}"
msgstr ""
msgid "%{labelStart}File:%{labelEnd} %{file}"
......@@ -413,6 +413,9 @@ msgstr ""
msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
msgstr ""
msgid "%{labelStart}Severity:%{labelEnd} %{severity}"
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