diff --git a/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_details.vue b/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_details.vue index 4600056d0932c14c06642c6307e5a1fa066d7271..d502193628bce53c7db44eaad2bd4e7de092dc6b 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_details.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_details.vue @@ -10,6 +10,7 @@ import { import { s__, __ } from '~/locale'; import CodeBlock from '~/vue_shared/components/code_block.vue'; import DetailItem from './detail_item.vue'; +import FalsePositiveAlert from './false_positive_alert.vue'; import VulnerabilityDetailSection from './vulnerability_detail_section.vue'; import VulnerabilityTraining from './vulnerability_training.vue'; @@ -17,6 +18,7 @@ export default { name: 'VulnerabilityDetails', components: { CodeBlock, + FalsePositiveAlert, GlLink, SeverityBadge, DetailItem, @@ -57,6 +59,9 @@ export default { fileUrl() { return (this.location.blobPath || '') + (this.lineNumber ? `#L${this.lineNumber}` : ''); }, + isFalsePositive() { + return Boolean(this.vulnerability.falsePositive); + }, lineNumber() { const { startLine: start, endLine: end } = this.location; return end > start ? `${start}-${end}` : start; @@ -200,6 +205,8 @@ export default { <template> <div class="md" data-qa-selector="vulnerability_details"> + <false-positive-alert v-if="isFalsePositive" class="gl-mt-4!" /> + <h1 v-if="vulnerability.title" class="mt-3 mb-2 border-bottom-0" diff --git a/ee/spec/frontend/vulnerabilities/vulnerability_details_spec.js b/ee/spec/frontend/vulnerabilities/vulnerability_details_spec.js index 8e7a27ed1820cdce91e27f49369dfbd3c5075ce1..51505d4db0f68c90e9d0c7bd25f114e1dc73e0fc 100644 --- a/ee/spec/frontend/vulnerabilities/vulnerability_details_spec.js +++ b/ee/spec/frontend/vulnerabilities/vulnerability_details_spec.js @@ -8,6 +8,7 @@ import { VULNERABILITY_TRAINING_HEADING, } from 'ee/vulnerabilities/constants'; import VulnerabilityTraining from 'ee/vulnerabilities/components/vulnerability_training.vue'; +import FalsePositiveAlert from 'ee/vulnerabilities/components/false_positive_alert.vue'; describe('Vulnerability Details', () => { let wrapper; @@ -31,6 +32,7 @@ describe('Vulnerability Details', () => { propsData, provide: { projectFullPath: TEST_PROJECT_FULL_PATH, + canViewFalsePositive: true, }, ...options, }); @@ -42,6 +44,7 @@ describe('Vulnerability Details', () => { const getAllById = (id) => wrapper.findAll(`[data-testid="${id}"]`); const getText = (id) => getById(id).text(); const findVulnerabilityTraining = () => wrapper.findComponent(VulnerabilityTraining); + const findFalsePositiveAlert = () => wrapper.findComponent(FalsePositiveAlert); afterEach(() => { wrapper.destroy(); @@ -53,6 +56,7 @@ describe('Vulnerability Details', () => { expect(wrapper.findComponent(SeverityBadge).props('severity')).toBe(vulnerability.severity); expect(getText('reportType')).toBe(`Tool: ${vulnerability.reportType}`); + expect(findFalsePositiveAlert().exists()).toBe(false); expect(getById('title').exists()).toBe(false); expect(getById('image').exists()).toBe(false); expect(getById('os').exists()).toBe(false); @@ -65,6 +69,14 @@ describe('Vulnerability Details', () => { expect(getAllById('identifier')).toHaveLength(0); }); + it.each([true, false])( + 'shows/hides the false-positive alert when `falsePositive` is: %s', + (falsePositive) => { + createWrapper({ falsePositive }); + expect(findFalsePositiveAlert().exists()).toBe(falsePositive); + }, + ); + it('renders description when descriptionHtml is not present', () => { createWrapper({ descriptionHtml: null,