diff --git a/ee/app/assets/javascripts/vue_shared/security_reports/components/vulnerability_details.vue b/ee/app/assets/javascripts/vue_shared/security_reports/components/vulnerability_details.vue index 6e60486fbb2ecbdb854437487d999778349f7541..4d1c9e33566f5d24475e25fa9c447740306aa1b2 100644 --- a/ee/app/assets/javascripts/vue_shared/security_reports/components/vulnerability_details.vue +++ b/ee/app/assets/javascripts/vue_shared/security_reports/components/vulnerability_details.vue @@ -58,6 +58,9 @@ export default { namespace() { return this.vulnLocation?.operating_system; }, + assets() { + return this.asNonEmptyListOrNull(this.vulnerability.assets); + }, links() { return this.asNonEmptyListOrNull(this.vulnerability.links); }, @@ -258,5 +261,21 @@ export default { <span v-if="hasMoreValues(i, links)">, </span> </span> </vulnerability-detail> + <vulnerability-detail v-if="assets" :label="s__('Vulnerability|Reproduction Assets')"> + <span v-for="(asset, i) in assets" :key="i"> + <gl-link + v-if="asset.url" + ref="assetsLink" + class="gl-word-break-all" + :href="asset.url" + target="_blank" + rel="nofollow" + > + {{ s__('Vulnerability|Download') }} {{ asset.name }} + </gl-link> + <span v-else> {{ asset.name }} </span> + <span v-if="hasMoreValues(i, assets)">, </span> + </span> + </vulnerability-detail> </div> </template> diff --git a/ee/app/assets/javascripts/vulnerabilities/components/details.vue b/ee/app/assets/javascripts/vulnerabilities/components/details.vue index dd0dfde62ee49b5ac768f00d3629acc5024d9700..1da310d25e6cf5f7e06e8081473eb51e7864dd50 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/details.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/details.vue @@ -377,5 +377,24 @@ export default { </detail-item> </ul> </template> + + <template v-if="vulnerability.assets && vulnerability.assets.length"> + <h3>{{ s__('Vulnerability|Reproduction Assets') }}</h3> + <ul> + <li + v-for="(asset, index) in vulnerability.assets" + :key="`${index}:${asset.url}`" + class="gl-ml-0! gl-list-style-position-inside" + > + <component + :is="asset.url ? 'gl-link' : 'span'" + v-bind="asset.url && { href: asset.url, target: '_blank' }" + data-testid="asset" + > + {{ asset.name }} + </component> + </li> + </ul> + </template> </div> </template> diff --git a/ee/changelogs/unreleased/292890-artifact-download-reproduction-assets.yml b/ee/changelogs/unreleased/292890-artifact-download-reproduction-assets.yml new file mode 100644 index 0000000000000000000000000000000000000000..f845e1328db4619c10fffeb533b7562a4bf5750d --- /dev/null +++ b/ee/changelogs/unreleased/292890-artifact-download-reproduction-assets.yml @@ -0,0 +1,5 @@ +--- +title: Show Vulnerability reproduction asset downloads +merge_request: 50748 +author: +type: added diff --git a/ee/spec/frontend/vue_shared/security_reports/components/__snapshots__/vulnerability_details_spec.js.snap b/ee/spec/frontend/vue_shared/security_reports/components/__snapshots__/vulnerability_details_spec.js.snap index 7b6a1325e3e3682f0cb0d19d948e7ed05a704551..c4163fc812c115d012751ca10487816a5cdbd61a 100644 --- a/ee/spec/frontend/vue_shared/security_reports/components/__snapshots__/vulnerability_details_spec.js.snap +++ b/ee/spec/frontend/vue_shared/security_reports/components/__snapshots__/vulnerability_details_spec.js.snap @@ -182,5 +182,7 @@ exports[`VulnerabilityDetails component pin test renders correctly 1`] = ` <!----> </span> </vulnerability-detail-stub> + + <!----> </div> `; diff --git a/ee/spec/frontend/vue_shared/security_reports/components/vulnerability_details_spec.js b/ee/spec/frontend/vue_shared/security_reports/components/vulnerability_details_spec.js index 9df868d6f5410c68b3262f2264343e542b24cc23..7051d0a7a22b70923cadd8e62785074e1ff27ba4 100644 --- a/ee/spec/frontend/vue_shared/security_reports/components/vulnerability_details_spec.js +++ b/ee/spec/frontend/vue_shared/security_reports/components/vulnerability_details_spec.js @@ -112,6 +112,7 @@ describe('VulnerabilityDetails component', () => { }, links: [{ url: badUrl }], identifiers: [{ name: 'BAD_URL', url: badUrl }], + assets: [{ name: 'BAD_URL', url: badUrl }], }); componentFactory(vulnerability); @@ -125,6 +126,10 @@ describe('VulnerabilityDetails component', () => { expectSafeLink({ link: findLink('identifiers'), href: 'about:blank', text: 'BAD_URL' }); }); + it('for the assets field', () => { + expectSafeLink({ link: findLink('assets'), href: 'about:blank', text: 'Download BAD_URL' }); + }); + it('for the file field', () => { expectSafeLink({ link: findLink('file'), diff --git a/ee/spec/frontend/vulnerabilities/details_spec.js b/ee/spec/frontend/vulnerabilities/details_spec.js index c350cf8a75be501236b3f02bfcdf8ba1a3e10855..78140f125a84f0f44b474da7f1efde235a2732e9 100644 --- a/ee/spec/frontend/vulnerabilities/details_spec.js +++ b/ee/spec/frontend/vulnerabilities/details_spec.js @@ -124,6 +124,41 @@ describe('Vulnerability Details', () => { identifiersData.forEach(checkIdentifier); }); + it('shows the vulnerability assets if they exist', () => { + const assetsData = [ + { name: 'Postman Collection', url: 'http://example.com/postman' }, + { name: 'HTTP Messages', url: 'http://example.com/http-messages' }, + { name: 'Foo' }, + { name: 'Bar' }, + ]; + + createWrapper({ + assets: assetsData, + }); + + const assets = getAllById('asset'); + + expect(assets).toHaveLength(assetsData.length); + + const checkIdentifier = ({ name, url }, index) => { + const asset = assets.at(index); + + expect(asset.text()).toBe(name); + + if (url) { + expect(asset.is(GlLink)).toBe(true); + expect(asset.attributes()).toMatchObject({ + target: '_blank', + href: url, + }); + } else { + expect(asset.is(GlLink)).toBe(false); + } + }; + + assetsData.forEach(checkIdentifier); + }); + describe('file link', () => { const file = () => getById('file').find(GlLink); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7d1c64d960f6d7ac46da3f00464a2b81a250c741..1c0c26c75a86854c2d93e60d84f7edef72cc4b14 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -31192,6 +31192,9 @@ msgstr "" msgid "Vulnerability|Detected" msgstr "" +msgid "Vulnerability|Download" +msgstr "" + msgid "Vulnerability|Evidence" msgstr "" @@ -31219,6 +31222,9 @@ msgstr "" msgid "Vulnerability|Project" msgstr "" +msgid "Vulnerability|Reproduction Assets" +msgstr "" + msgid "Vulnerability|Request" msgstr ""