Commit 0d9f0596 authored by Mark Florian's avatar Mark Florian

Merge branch '216873-use-glsprintf-for-notes' into 'master'

Use GlSprintf instead of v-html for security scanning notes

See merge request gitlab-org/gitlab!34136
parents 912f43fc ad124dd0
<script> <script>
import { escape } from 'lodash'; import { GlSprintf, GlLink } from '@gitlab/ui';
import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue'; import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue';
import { __, sprintf } from '~/locale'; import { __ } from '~/locale';
export default { export default {
components: { components: {
EventItem, EventItem,
GlSprintf,
GlLink,
}, },
props: { props: {
feedback: { feedback: {
...@@ -19,23 +21,15 @@ export default { ...@@ -19,23 +21,15 @@ export default {
}, },
}, },
computed: { computed: {
eventText() { hasProjectUrl() {
const { project, feedback } = this; return this.project?.value && this.project?.url;
const issueLink = `<a href="${feedback.issue_url}">#${feedback.issue_iid}</a>`;
if (project && project.value && project.url) {
const projectLink = `<a href="${escape(project.url)}">${escape(project.value)}</a>`;
return sprintf(
__('Created issue %{issueLink} at %{projectLink}'),
{
issueLink,
projectLink,
}, },
false, eventText() {
); if (this.hasProjectUrl) {
return __('Created issue %{issueLink} at %{projectLink}');
} }
return sprintf(__('Created issue %{issueLink}'), { issueLink }, false);
return __('Created issue %{issueLink}');
}, },
}, },
}; };
...@@ -43,6 +37,13 @@ export default { ...@@ -43,6 +37,13 @@ export default {
<template> <template>
<event-item :author="feedback.author" :created-at="feedback.created_at" icon-name="issue-created"> <event-item :author="feedback.author" :created-at="feedback.created_at" icon-name="issue-created">
<div v-html="eventText"></div> <gl-sprintf :message="eventText">
<template #issueLink>
<gl-link :href="feedback.issue_url">#{{ feedback.issue_iid }}</gl-link>
</template>
<template v-if="hasProjectUrl" #projectLink>
<gl-link :href="project.url">{{ project.value }}</gl-link>
</template>
</gl-sprintf>
</event-item> </event-item>
</template> </template>
<script> <script>
import { escape } from 'lodash'; import { GlSprintf, GlLink } from '@gitlab/ui';
import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue'; import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue';
import { __, sprintf } from '~/locale'; import { __ } from '~/locale';
export default { export default {
components: { components: {
EventItem, EventItem,
GlSprintf,
GlLink,
}, },
props: { props: {
feedback: { feedback: {
...@@ -19,23 +21,15 @@ export default { ...@@ -19,23 +21,15 @@ export default {
}, },
}, },
computed: { computed: {
eventText() { hasProjectUrl() {
const { project, feedback } = this; return this.project?.value && this.project?.url;
const mergeRequestLink = `<a href="${feedback.merge_request_path}">!${feedback.merge_request_iid}</a>`;
if (project && project.value && project.url) {
const projectLink = `<a href="${escape(project.url)}">${escape(project.value)}</a>`;
return sprintf(
__('Created merge request %{mergeRequestLink} at %{projectLink}'),
{
mergeRequestLink,
projectLink,
}, },
false, eventText() {
); if (this.hasProjectUrl) {
return __('Created merge request %{mergeRequestLink} at %{projectLink}');
} }
return sprintf(__('Created merge request %{mergeRequestLink}'), { mergeRequestLink }, false);
return __('Created merge request %{mergeRequestLink}');
}, },
}, },
}; };
...@@ -43,6 +37,13 @@ export default { ...@@ -43,6 +37,13 @@ export default {
<template> <template>
<event-item :author="feedback.author" :created-at="feedback.created_at" icon-name="merge-request"> <event-item :author="feedback.author" :created-at="feedback.created_at" icon-name="merge-request">
<div v-html="eventText"></div> <gl-sprintf :message="eventText">
<template #mergeRequestLink>
<gl-link :href="feedback.merge_request_path">!{{ feedback.merge_request_iid }}</gl-link>
</template>
<template v-if="hasProjectUrl" #projectLink>
<gl-link :href="project.url">{{ project.value }}</gl-link>
</template>
</gl-sprintf>
</event-item> </event-item>
</template> </template>
...@@ -84,9 +84,6 @@ export default { ...@@ -84,9 +84,6 @@ export default {
isResolved() { isResolved() {
return Boolean(this.modal.isResolved); return Boolean(this.modal.isResolved);
}, },
hasRemediation() {
return Boolean(this.remediation);
},
project() { project() {
return this.modal.project; return this.modal.project;
}, },
...@@ -207,7 +204,6 @@ export default { ...@@ -207,7 +204,6 @@ export default {
:solution="solution" :solution="solution"
:remediation="remediation" :remediation="remediation"
:has-mr="vulnerability.hasMergeRequest" :has-mr="vulnerability.hasMergeRequest"
:has-remediation="hasRemediation"
:has-download="canDownloadPatchForThisVulnerability" :has-download="canDownloadPatchForThisVulnerability"
:vulnerability-feedback-help-path="vulnerabilityFeedbackHelpPath" :vulnerability-feedback-help-path="vulnerabilityFeedbackHelpPath"
/> />
......
...@@ -26,11 +26,6 @@ export default { ...@@ -26,11 +26,6 @@ export default {
default: false, default: false,
required: false, required: false,
}, },
hasRemediation: {
type: Boolean,
default: false,
required: false,
},
vulnerabilityFeedbackHelpPath: { vulnerabilityFeedbackHelpPath: {
type: String, type: String,
default: '', default: '',
...@@ -53,13 +48,10 @@ export default { ...@@ -53,13 +48,10 @@ export default {
); );
}, },
showCreateMergeRequestMsg() { showCreateMergeRequestMsg() {
return !this.hasMr && this.hasRemediation && this.hasDownload; return !this.hasMr && Boolean(this.remediation) && this.hasDownload;
}, },
showLearnAboutRemedationMsg() { showLearnAboutRemedationMsg() {
if (this.hasMr) { return !this.hasMr;
return false;
}
return true;
}, },
showMsg() { showMsg() {
return ( return (
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
import component from 'ee/vue_shared/security_reports/components/issue_note.vue'; import component from 'ee/vue_shared/security_reports/components/issue_note.vue';
import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue'; import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue';
...@@ -23,6 +24,7 @@ describe('Issue note', () => { ...@@ -23,6 +24,7 @@ describe('Issue note', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
stubs: { GlSprintf },
propsData: { feedback }, propsData: { feedback },
}); });
}); });
...@@ -45,6 +47,7 @@ describe('Issue note', () => { ...@@ -45,6 +47,7 @@ describe('Issue note', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
stubs: { GlSprintf },
propsData: { feedback, project }, propsData: { feedback, project },
}); });
}); });
...@@ -63,6 +66,7 @@ describe('Issue note', () => { ...@@ -63,6 +66,7 @@ describe('Issue note', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
stubs: { GlSprintf },
propsData: { propsData: {
feedback, feedback,
project: unsafeProject, project: unsafeProject,
...@@ -71,13 +75,8 @@ describe('Issue note', () => { ...@@ -71,13 +75,8 @@ describe('Issue note', () => {
}); });
it('should escape the project name', () => { it('should escape the project name', () => {
// Note: We have to check the computed prop here because // Test that the XSS text has been rendered literally as safe text.
// vue test utils unescapes the result of wrapper.text() expect(wrapper.text()).toContain(unsafeProject.value);
expect(wrapper.vm.eventText).not.toContain(project.value);
expect(wrapper.vm.eventText).toContain(
'Foo &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;',
);
}); });
}); });
}); });
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
import component from 'ee/vue_shared/security_reports/components/merge_request_note.vue'; import component from 'ee/vue_shared/security_reports/components/merge_request_note.vue';
import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue'; import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue';
...@@ -23,6 +24,7 @@ describe('Merge request note', () => { ...@@ -23,6 +24,7 @@ describe('Merge request note', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
stubs: { GlSprintf },
propsData: { feedback }, propsData: { feedback },
}); });
}); });
...@@ -45,6 +47,7 @@ describe('Merge request note', () => { ...@@ -45,6 +47,7 @@ describe('Merge request note', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
stubs: { GlSprintf },
propsData: { feedback, project }, propsData: { feedback, project },
}); });
}); });
...@@ -65,6 +68,7 @@ describe('Merge request note', () => { ...@@ -65,6 +68,7 @@ describe('Merge request note', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
stubs: { GlSprintf },
propsData: { propsData: {
feedback, feedback,
project: unsafeProject, project: unsafeProject,
...@@ -73,13 +77,8 @@ describe('Merge request note', () => { ...@@ -73,13 +77,8 @@ describe('Merge request note', () => {
}); });
it('should escape the project name', () => { it('should escape the project name', () => {
// Note: We have to check the computed prop here because // Test that the XSS text has been rendered literally as safe text.
// vue test utils unescapes the result of wrapper.text() expect(wrapper.text()).toContain(unsafeProject.value);
expect(wrapper.vm.eventText).not.toContain(project.value);
expect(wrapper.vm.eventText).toContain(
'Foo &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;',
);
}); });
}); });
}); });
...@@ -37,7 +37,6 @@ describe('Vulnerability Footer', () => { ...@@ -37,7 +37,6 @@ describe('Vulnerability Footer', () => {
const solutionInfoProp = { const solutionInfoProp = {
hasDownload: true, hasDownload: true,
hasMr: false, hasMr: false,
hasRemediation: true,
isStandaloneVulnerability: true, isStandaloneVulnerability: true,
remediation: {}, remediation: {},
solution: 'Upgrade to fixed version.\n', solution: 'Upgrade to fixed version.\n',
......
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