diff --git a/ee/app/assets/javascripts/vulnerabilities/components/header.vue b/ee/app/assets/javascripts/vulnerabilities/components/header.vue index bb5a798acde04811c5fb7ea90e9fea1180387b1a..43aa33c5de7122cbc17626e3ac66931ca28328a3 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/header.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/header.vue @@ -338,6 +338,7 @@ export default { :show-resolve-with-ai="canResolveWithAi" :show-explain-with-ai="canExplainWithAi" :ai-resolution-enabled="vulnerability.aiResolutionEnabled" + :show-public-project-warning="vulnerability.belongsToPublicProject" @create-merge-request="createMergeRequest" @download-patch="downloadPatch" @explain-vulnerability="explainVulnerability" diff --git a/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_actions_dropdown.vue b/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_actions_dropdown.vue index 9e78481f7c492da8a816e0de51ccaeb11dd04575..cfd9176935e7bfd17d5099ebea9dc3a8d0773bff 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_actions_dropdown.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/vulnerability_actions_dropdown.vue @@ -3,6 +3,7 @@ import { GlButton, GlDisclosureDropdown, GlDisclosureDropdownItem, + GlSprintf, GlLink, GlIcon, } from '@gitlab/ui'; @@ -31,6 +32,12 @@ const RESOLVE_VULNERABILITY_ACTION = { disabledStateDescription: s__( 'AI|GitLab Duo is unable to suggest a fix for this type of vulnerability.', ), + warning: { + text: s__( + 'AI|Creating an MR from a public project will publicly expose the vulnerability and offered resolution. To create the MR privately, see %{linkStart} Resolving a vulnerability privately%{linkEnd}.', + ), + link: helpPagePath('/user/project/merge_requests/confidential'), + }, }; const CREATE_MERGE_REQUEST_ACTION = { @@ -46,7 +53,14 @@ const DOWNLOAD_PATCH_ACTION = { }; export default { - components: { GlButton, GlDisclosureDropdown, GlDisclosureDropdownItem, GlLink, GlIcon }, + components: { + GlButton, + GlDisclosureDropdown, + GlDisclosureDropdownItem, + GlSprintf, + GlLink, + GlIcon, + }, props: { loading: { type: Boolean, @@ -78,6 +92,11 @@ export default { required: false, default: false, }, + showPublicProjectWarning: { + type: Boolean, + required: false, + default: false, + }, }, computed: { onlyAiActionsAvailable() { @@ -104,10 +123,6 @@ export default { availableActions.push(DOWNLOAD_PATCH_ACTION); } - if (this.showExplainWithAi) { - availableActions.push(EXPLAIN_VULNERABILITY_ACTION); - } - if (this.showResolveWithAi) { availableActions.push({ ...RESOLVE_VULNERABILITY_ACTION, @@ -116,14 +131,19 @@ export default { extraAttrs: { disabled: true }, description: RESOLVE_VULNERABILITY_ACTION.disabledStateDescription, }), + showWarning: this.showPublicProjectWarning && this.aiResolutionEnabled, }); } + if (this.showExplainWithAi) { + availableActions.push(EXPLAIN_VULNERABILITY_ACTION); + } + return availableActions; }, }, methods: { - emitActionName({ name, disabled }) { + emitSelectedActionName({ name, disabled }) { if (!disabled) { this.$emit(name); } @@ -153,56 +173,74 @@ export default { placement="bottom-end" class="gl-leading-20" > - - - +

+ + + +

+ + diff --git a/ee/app/helpers/vulnerabilities_helper.rb b/ee/app/helpers/vulnerabilities_helper.rb index 804236323b2c29792d8c31e273e055b9fe7e9cc6..384553fc96f4c7e1b02d82547fcd9089b7306503 100644 --- a/ee/app/helpers/vulnerabilities_helper.rb +++ b/ee/app/helpers/vulnerabilities_helper.rb @@ -94,6 +94,7 @@ def vulnerability_finding_data(vulnerability) data[:ai_explanation_available] = vulnerability.finding.ai_explanation_available? data[:ai_resolution_available] = vulnerability.finding.ai_resolution_available? data[:ai_resolution_enabled] = vulnerability.finding.ai_resolution_enabled? + data[:belongs_to_public_project] = vulnerability.project.public? data end diff --git a/ee/spec/frontend/vulnerabilities/header_spec.js b/ee/spec/frontend/vulnerabilities/header_spec.js index 7430ac9e982c48a1bde4140f04d674bcf1e9bd98..6b03d7aecf10254c78f1a875a6866056f40e9af0 100644 --- a/ee/spec/frontend/vulnerabilities/header_spec.js +++ b/ee/spec/frontend/vulnerabilities/header_spec.js @@ -567,5 +567,22 @@ describe('Vulnerability Header', () => { expect(MUTATION_AI_ACTION_DEFAULT_RESPONSE).toHaveBeenCalled(); }); }); + + describe('show-public-project warning', () => { + it.each([true, false])( + 'passes "vulnerability.belongsToPublicProject" prop to the component', + (belongsToPublicProject) => { + createWrapper({ + vulnerability: { + belongsToPublicProject, + }, + }); + + expect(findActionsDropdown().props('showPublicProjectWarning')).toBe( + belongsToPublicProject, + ); + }, + ); + }); }); }); diff --git a/ee/spec/frontend/vulnerabilities/vulnerability_actions_dropdown_spec.js b/ee/spec/frontend/vulnerabilities/vulnerability_actions_dropdown_spec.js index b67de162273fda41a19035d3ac1313b0cbe69d4b..46ec5343e742cc32f2e031ca62b87ba7be47105b 100644 --- a/ee/spec/frontend/vulnerabilities/vulnerability_actions_dropdown_spec.js +++ b/ee/spec/frontend/vulnerabilities/vulnerability_actions_dropdown_spec.js @@ -13,6 +13,7 @@ describe('ee/vulnerabilities/components/vulnerability_actions_dropdown.vue', () showExplainWithAi: false, showResolveWithAi: false, aiResolutionEnabled: true, + showPublicProjectWarning: false, ...propsData, }, }); @@ -214,4 +215,18 @@ describe('ee/vulnerabilities/components/vulnerability_actions_dropdown.vue', () }); }, ); + + it.each([true, false])( + 'renders/does not render a warning when "showPublicProjectWarning" is: "%s"', + (showPublicProjectWarning) => { + createWrapper({ + showExplainWithAi: true, + aiResolutionEnabled: true, + showResolveWithAi: true, + showPublicProjectWarning, + }); + + expect(wrapper.findByTestId('ai-action-warning').exists()).toBe(showPublicProjectWarning); + }, + ); }); diff --git a/ee/spec/helpers/vulnerabilities_helper_spec.rb b/ee/spec/helpers/vulnerabilities_helper_spec.rb index 7babd39bc070eade150d0cba9646e715235dfffd..d9ede4957af14f3151a4c11a11119effb1a9c261 100644 --- a/ee/spec/helpers/vulnerabilities_helper_spec.rb +++ b/ee/spec/helpers/vulnerabilities_helper_spec.rb @@ -409,7 +409,8 @@ merge_request_links: kind_of(Array), ai_explanation_available: finding.ai_explanation_available?, ai_resolution_available: finding.ai_resolution_available?, - ai_resolution_enabled: finding.ai_resolution_enabled? + ai_resolution_enabled: finding.ai_resolution_enabled?, + belongs_to_public_project: vulnerability.project.public? ) expect(subject[:location]['blob_path']).to match(kind_of(String)) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 165fc343b9b28a44d519a7e9beb297fca5732f67..f37a1d8cf21ef232edb6c138f016a16fbb7b5e2b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2286,6 +2286,9 @@ msgstr "" msgid "AI|Create issue description based on a short prompt" msgstr "" +msgid "AI|Creating an MR from a public project will publicly expose the vulnerability and offered resolution. To create the MR privately, see %{linkStart} Resolving a vulnerability privately%{linkEnd}." +msgstr "" + msgid "AI|Description is required" msgstr ""