Commit f58ce22f authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Phil Hughes

Wrap file paths in vulnerability details modal

Use gitlab-ui's FriendlyWrap component to properly wrap file paths
in the vulnerability details modal
parent a5aec1d0
<script> <script>
import { GlFriendlyWrap } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import SafeLink from 'ee/vue_shared/components/safe_link.vue'; import SafeLink from 'ee/vue_shared/components/safe_link.vue';
import SeverityBadge from './severity_badge.vue'; import SeverityBadge from './severity_badge.vue';
...@@ -6,6 +7,7 @@ import SeverityBadge from './severity_badge.vue'; ...@@ -6,6 +7,7 @@ import SeverityBadge from './severity_badge.vue';
export default { export default {
name: 'VulnerabilityDetails', name: 'VulnerabilityDetails',
components: { components: {
GlFriendlyWrap,
Icon, Icon,
SafeLink, SafeLink,
SeverityBadge, SeverityBadge,
...@@ -23,17 +25,17 @@ export default { ...@@ -23,17 +25,17 @@ export default {
hasValue(field) { hasValue(field) {
return field.value && field.value.length > 0; return field.value && field.value.length > 0;
}, },
hasInstances(field, key) { hasInstances(key) {
return key === 'instances' && this.hasValue(field); return key === 'instances';
}, },
hasIdentifiers(field, key) { hasIdentifiers(key) {
return key === 'identifiers' && this.hasValue(field); return key === 'identifiers';
}, },
hasLinks(field, key) { hasLinks(key) {
return key === 'links' && this.hasValue(field); return key === 'links';
}, },
hasSeverity(field, key) { hasSeverity(key) {
return key === 'severity' && this.hasValue(field); return key === 'severity';
}, },
}, },
}; };
...@@ -44,81 +46,85 @@ export default { ...@@ -44,81 +46,85 @@ export default {
<div v-for="(field, key, index) in details" :key="index" class="d-flex my-2"> <div v-for="(field, key, index) in details" :key="index" class="d-flex my-2">
<label class="col-2 text-right font-weight-bold pl-0">{{ field.text }}:</label> <label class="col-2 text-right font-weight-bold pl-0">{{ field.text }}:</label>
<div class="col-10 pl-0 text-secondary"> <div class="col-10 pl-0 text-secondary">
<div v-if="hasInstances(field, key)" class="info-well"> <template v-if="hasValue(field)">
<ul class="report-block-list"> <div v-if="hasInstances(key)" class="info-well">
<li v-for="(instance, i) in field.value" :key="i" class="report-block-list-issue"> <ul class="report-block-list">
<div class="report-block-list-icon append-right-5 failed"> <li v-for="(instance, i) in field.value" :key="i" class="report-block-list-issue">
<icon :size="32" name="status_failed_borderless" /> <div class="report-block-list-icon append-right-5 failed">
</div> <icon :size="32" name="status_failed_borderless" />
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<div class="report-block-list-issue-description-text">
{{ instance.method }}
</div> </div>
<div class="report-block-list-issue-description-link"> <div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<safe-link <div class="report-block-list-issue-description-text">
:href="instance.uri" {{ instance.method }}
target="_blank" </div>
rel="noopener noreferrer nofollow" <div class="report-block-list-issue-description-link">
class="break-link" <safe-link
> :href="instance.uri"
{{ instance.uri }} target="_blank"
</safe-link> rel="noopener noreferrer nofollow"
class="break-link"
>
{{ instance.uri }}
</safe-link>
</div>
<expand-button v-if="instance.evidence">
<pre
slot="expanded"
class="block report-block-dast-code prepend-top-10 report-block-issue-code"
>
{{ instance.evidence }}</pre
>
</expand-button>
</div> </div>
<expand-button v-if="instance.evidence"> </li>
<pre </ul>
slot="expanded" </div>
class="block report-block-dast-code prepend-top-10 report-block-issue-code" <template v-else-if="hasIdentifiers(key)">
> <span v-for="(identifier, i) in field.value" :key="i">
{{ instance.evidence }}</pre <safe-link
> v-if="identifier.url"
</expand-button> :class="`js-link-${key}`"
</div> :href="identifier.url"
</li> target="_blank"
</ul> rel="noopener noreferrer"
</div> >
<template v-else-if="hasIdentifiers(field, key)"> {{ identifier.name }}
<span v-for="(identifier, i) in field.value" :key="i"> </safe-link>
<span v-else> {{ identifier.name }} </span>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasLinks(key)">
<span v-for="(link, i) in field.value" :key="i">
<safe-link
:class="`js-link-${key}`"
:href="link.url"
target="_blank"
rel="noopener noreferrer"
>
{{ link.value || link.url }}
</safe-link>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasSeverity(key)">
<severity-badge :severity="field.value" class="d-inline" />
</template>
<template v-else>
<safe-link <safe-link
v-if="identifier.url" v-if="field.isLink"
:class="`js-link-${key}`" :class="`js-link-${key}`"
:href="identifier.url" :href="field.url"
target="_blank" target="_blank"
rel="noopener noreferrer"
> >
{{ identifier.name }} <gl-friendly-wrap :text="field.value" />
</safe-link> </safe-link>
<span v-else> {{ identifier.name }} </span> <gl-friendly-wrap
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span> v-else
</span> :text="field.value"
</template> :class="{ 'text-capitalize': key === 'confidence' }"
<template v-else-if="hasLinks(field, key)"> />
<span v-for="(link, i) in field.value" :key="i"> </template>
<safe-link
:class="`js-link-${key}`"
:href="link.url"
target="_blank"
rel="noopener noreferrer"
>
{{ link.value || link.url }}
</safe-link>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasSeverity(field, key)">
<severity-badge :severity="field.value" class="d-inline" />
</template>
<template v-else>
<safe-link
v-if="field.isLink"
:class="`js-link-${key}`"
:href="field.url"
target="_blank"
>
{{ field.value }}
</safe-link>
<span v-else :class="{ 'text-capitalize': key === 'confidence' }">
{{ field.value }}
</span>
</template> </template>
</div> </div>
</div> </div>
......
---
title: Prevent files paths from overflowing in vulnerability info modal
merge_request: 10606
author:
type: fixed
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, mount } from '@vue/test-utils';
import createState from 'ee/vue_shared/security_reports/store/state'; import createState from 'ee/vue_shared/security_reports/store/state';
import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue'; import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.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';
...@@ -10,7 +10,7 @@ describe('VulnerabilityDetails component', () => { ...@@ -10,7 +10,7 @@ describe('VulnerabilityDetails component', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
const componentFactory = (options = {}) => { const componentFactory = (options = {}) => {
wrapper = shallowMount(localVue.extend(VulnerabilityDetails), { wrapper = mount(localVue.extend(VulnerabilityDetails), {
...options, ...options,
localVue, localVue,
sync: false, sync: false,
...@@ -48,6 +48,34 @@ describe('VulnerabilityDetails component', () => { ...@@ -48,6 +48,34 @@ describe('VulnerabilityDetails component', () => {
}); });
}); });
it('renders wrapped file paths', () => {
const value = '/some/file/path';
const valueWrapped = '/<wbr>some/<wbr>file/<wbr>path';
const details = {
file: {
value,
url: `${TEST_HOST}/bar`,
isLink: true,
},
};
componentFactory({ propsData: { details } });
expect(wrapper.find(SafeLink).html()).toMatch(valueWrapped);
});
it('escapes wrapped file paths', () => {
const value = '/unsafe/path<script></script>';
const valueWrapped = '/<wbr>unsafe/<wbr>path&lt;script&gt;&lt;/<wbr>script&gt;';
const details = {
file: {
value,
url: `${TEST_HOST}/bar`,
isLink: true,
},
};
componentFactory({ propsData: { details } });
expect(wrapper.find(SafeLink).html()).toMatch(valueWrapped);
});
describe('does not render XSS links', () => { describe('does not render XSS links', () => {
// eslint-disable-next-line no-script-url // eslint-disable-next-line no-script-url
const badUrl = 'javascript:alert("")'; const badUrl = 'javascript:alert("")';
......
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