Commit f19d356d authored by Mark Florian's avatar Mark Florian

Replace VulnerabilityDetails component

This completely removes the old `vulnerability-details` component and
replaces it with the new one.

Now that the bulk of snapshots have served their purpose, they have been
removed, along with now-unsued mocks.
parent 233f466c
......@@ -122,22 +122,6 @@ export default {
isEditingExistingFeedback() {
return this.dismissalFeedback && this.modal.isCommentingOnDismissal;
},
valuedFields() {
const { data } = this.modal;
const result = {};
Object.keys(data).forEach(key => {
if (data[key].value && data[key].value.length) {
result[key] = data[key];
if (key === 'file' && this.vulnerability.blob_path) {
result[key].isLink = true;
result[key].url = this.vulnerability.blob_path;
}
}
});
return result;
},
dismissalFeedbackObject() {
if (this.dismissalFeedback) {
return this.dismissalFeedback;
......@@ -202,7 +186,7 @@ export default {
class="modal-security-report-dast"
>
<slot>
<vulnerability-details :details="valuedFields" class="js-vulnerability-details" />
<vulnerability-details :vulnerability="vulnerability" class="js-vulnerability-details" />
<solution-card
:solution="solution"
......
<script>
import { GlFriendlyWrap } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import SafeLink from 'ee/vue_shared/components/safe_link.vue';
import Icon from '~/vue_shared/components/icon.vue';
import SeverityBadge from './severity_badge.vue';
import getFileLocation from '../store/utils/get_file_location';
import VulnerabilityDetail from './vulnerability_detail.vue';
export default {
name: 'VulnerabilityDetails2',
components: {
GlFriendlyWrap,
Icon,
SafeLink,
SeverityBadge,
VulnerabilityDetail,
},
props: {
vulnerability: {
type: Object,
required: true,
},
},
methods: {
hasMoreValues(index, values) {
return index < values.length - 1;
},
asNonEmptyListOrNull(list) {
return list?.length > 0 ? list : null;
},
},
computed: {
url() {
return getFileLocation(this.vulnerability.location);
},
file() {
const file = this.vulnerability?.location?.file;
if (!file) {
return null;
}
let lineSuffix = '';
const { start_line: startLine, end_line: endLine } = this.vulnerability.location;
if (startLine) {
lineSuffix += `:${startLine}`;
if (endLine && startLine !== endLine) {
lineSuffix += `-${endLine}`;
}
}
return `${file}${lineSuffix}`;
},
identifiers() {
return this.asNonEmptyListOrNull(this.vulnerability.identifiers);
},
className() {
return this.vulnerability.location?.class;
},
methodName() {
return this.vulnerability.location?.method;
},
image() {
return this.vulnerability.location?.image;
},
namespace() {
return this.vulnerability.location?.operating_system;
},
links() {
return this.asNonEmptyListOrNull(this.vulnerability.links);
},
instances() {
return this.asNonEmptyListOrNull(this.vulnerability.instances);
},
},
};
</script>
<template>
<div class="border-white mb-0 px-3">
<vulnerability-detail
v-if="vulnerability.description"
:label="s__('Vulnerability|Description')"
>
<gl-friendly-wrap :text="vulnerability.description" />
</vulnerability-detail>
<vulnerability-detail v-if="vulnerability.project" :label="s__('Vulnerability|Project')">
<safe-link class="js-link-project" :href="vulnerability.project.full_path" target="_blank">
<gl-friendly-wrap :text="vulnerability.project.full_name" />
</safe-link>
</vulnerability-detail>
<vulnerability-detail v-if="url" :label="__('URL')">
<safe-link class="js-link-url" :href="url" target="_blank">
<gl-friendly-wrap :text="url" />
</safe-link>
</vulnerability-detail>
<vulnerability-detail v-if="file" :label="s__('Vulnerability|File')">
<safe-link
v-if="vulnerability.blob_path"
class="js-link-file"
:href="vulnerability.blob_path"
target="_blank"
>
<gl-friendly-wrap :text="file" />
</safe-link>
<gl-friendly-wrap v-else :text="file" />
</vulnerability-detail>
<vulnerability-detail v-if="identifiers" :label="s__('Vulnerability|Identifiers')">
<span v-for="(identifier, i) in identifiers" :key="i">
<safe-link
v-if="identifier.url"
class="js-link-identifiers"
:href="identifier.url"
target="_blank"
rel="noopener noreferrer"
>
{{ identifier.name }}
</safe-link>
<span v-else> {{ identifier.name }} </span>
<span v-if="hasMoreValues(i, identifiers)">,&nbsp;</span>
</span>
</vulnerability-detail>
<vulnerability-detail v-if="vulnerability.severity" :label="s__('Vulnerability|Severity')">
<severity-badge :severity="vulnerability.severity" class="d-inline" />
</vulnerability-detail>
<vulnerability-detail
v-if="vulnerability.report_type"
:label="s__('Vulnerability|Report Type')"
>
<gl-friendly-wrap :text="vulnerability.report_type" />
</vulnerability-detail>
<vulnerability-detail v-if="className" :label="s__('Vulnerability|Class')">
<gl-friendly-wrap :text="className" />
</vulnerability-detail>
<vulnerability-detail v-if="methodName" :label="s__('Vulnerability|Method')">
<gl-friendly-wrap :text="methodName" />
</vulnerability-detail>
<vulnerability-detail v-if="image" :label="s__('Vulnerability|Image')">
<gl-friendly-wrap :text="image" />
</vulnerability-detail>
<vulnerability-detail v-if="namespace" :label="s__('Vulnerability|Namespace')">
<gl-friendly-wrap :text="namespace" />
</vulnerability-detail>
<vulnerability-detail v-if="links" :label="s__('Vulnerability|Links')">
<span v-for="(link, i) in links" :key="i">
<safe-link class="js-link-links" :href="link.url" target="_blank" rel="noopener noreferrer">
{{ link.value || link.url }}
</safe-link>
<span v-if="hasMoreValues(i, links)">,&nbsp;</span>
</span>
</vulnerability-detail>
<vulnerability-detail v-if="instances" :label="s__('Vulnerability|Instances')">
<div class="info-well">
<ul class="report-block-list">
<li v-for="(instance, i) in instances" :key="i" class="report-block-list-issue">
<div class="report-block-list-icon append-right-5 failed">
<icon :size="32" name="status_failed_borderless" />
</div>
<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 class="report-block-list-issue-description-link">
<safe-link
:href="instance.uri"
target="_blank"
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>
</li>
</ul>
</div>
</vulnerability-detail>
</div>
</template>
This source diff could not be displayed because it is too large. You can view the blob instead.
import { mount } from '@vue/test-utils';
import { mount, shallowMount } from '@vue/test-utils';
import createState from 'ee/vue_shared/security_reports/store/state';
import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue';
import VulnerabilityDetails2 from 'ee/vue_shared/security_reports/components/vulnerability_details_2.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import SafeLink from 'ee/vue_shared/components/safe_link.vue';
import { TEST_HOST } from 'helpers/test_constants';
import { cloneDeep } from 'lodash';
import { mockFindings } from '../mock_data';
function makeVulnerability(changes = {}) {
return Object.assign(cloneDeep(findings[0]), changes);
return Object.assign(cloneDeep(mockFindings[0]), changes);
}
describe('VulnerabilityDetails component', () => {
let wrapper;
const componentFactory = vulnerability => {
wrapper = mount(VulnerabilityDetails2, {
wrapper = mount(VulnerabilityDetails, {
propsData: { vulnerability },
});
};
......@@ -26,6 +26,10 @@ describe('VulnerabilityDetails component', () => {
expect(link.text()).toBe(text);
};
afterEach(() => {
wrapper.destroy();
});
it('renders severity with a badge', () => {
const vulnerability = makeVulnerability({ severity: 'critical' });
componentFactory(vulnerability);
......@@ -151,66 +155,18 @@ describe('VulnerabilityDetails component', () => {
);
});
});
});
import mutations from 'ee/vue_shared/security_reports/store/mutations';
import IssueModal from 'ee/vue_shared/security_reports/components/modal.vue';
import { findings } from './mock_findings';
import createDashboardState from 'ee/security_dashboard/store/modules/vulnerabilities/state';
import dashboardMutations from 'ee/security_dashboard/store/modules/vulnerabilities/mutations';
describe('VulnerabilityDetails component pin tests', () => {
let wrapper;
const mrFactory = vulnFinding => {
const state = createState();
mutations.SET_ISSUE_MODAL_DATA(state, { issue: vulnFinding });
const details = IssueModal.computed.valuedFields.call({
...state,
vulnerability: vulnFinding,
});
wrapper = mount(VulnerabilityDetails, {
propsData: {
details,
},
});
};
const dashboardFactory = vulnFinding => {
const state = createDashboardState();
dashboardMutations.SET_MODAL_DATA(state, { vulnerability: vulnFinding });
const details = IssueModal.computed.valuedFields.call({
...state,
vulnerability: vulnFinding,
});
wrapper = mount(VulnerabilityDetails, {
propsData: {
details,
},
});
};
const factory = vulnFinding => {
wrapper = mount(VulnerabilityDetails2, {
propsData: {
vulnerability: vulnFinding,
},
});
};
describe('in grouped_security_reports_app', () => {
it.each(findings.map(v => [v.name, v]))('works for %s', (_, finding) => {
factory(finding);
expect(wrapper.element).toMatchSnapshot();
});
});
describe('pin test', () => {
const factory = vulnFinding => {
wrapper = shallowMount(VulnerabilityDetails, {
propsData: {
vulnerability: vulnFinding,
},
});
};
describe('in Security Dashboards', () => {
it.each(findings.map(v => [v.name, v]))('works for %s', (_, finding) => {
factory(finding);
it('renders correctly', () => {
factory(makeVulnerability());
expect(wrapper.element).toMatchSnapshot();
});
});
......
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