diff --git a/ee/app/assets/javascripts/pages/projects/security/vulnerabilities/new/index.js b/ee/app/assets/javascripts/pages/projects/security/vulnerabilities/new/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5cb420a65f77e78aa766d9890eb9bc408bfacc9c --- /dev/null +++ b/ee/app/assets/javascripts/pages/projects/security/vulnerabilities/new/index.js @@ -0,0 +1,3 @@ +import initNewVulnerability from 'ee/vulnerabilities/new_vulnerability_init'; + +initNewVulnerability(document.getElementById('js-vulnerability-new')); diff --git a/ee/app/assets/javascripts/vulnerabilities/components/new_vulnerability/new_vulnerability.vue b/ee/app/assets/javascripts/vulnerabilities/components/new_vulnerability/new_vulnerability.vue new file mode 100644 index 0000000000000000000000000000000000000000..d73b7f053b72d88df08520b85ea37852fd674f07 --- /dev/null +++ b/ee/app/assets/javascripts/vulnerabilities/components/new_vulnerability/new_vulnerability.vue @@ -0,0 +1,25 @@ +<script> +import { s__ } from '~/locale'; + +export default { + i18n: { + title: s__('VulnerabilityManagement|Add vulnerability finding'), + description: s__( + 'VulnerabilityManagement|Manually add a vulnerability entry into the vulnerability report.', + ), + }, +}; +</script> + +<template> + <div> + <header class="gl-my-4 gl-border-b-gray-100 gl-border-b-solid gl-border-b-1"> + <h2 class="gl-mt-0 gl-mb-3"> + {{ $options.i18n.title }} + </h2> + <p data-testid="page-description"> + {{ $options.i18n.description }} + </p> + </header> + </div> +</template> diff --git a/ee/app/assets/javascripts/vulnerabilities/new_vulnerability_init.js b/ee/app/assets/javascripts/vulnerabilities/new_vulnerability_init.js new file mode 100644 index 0000000000000000000000000000000000000000..7defd24afeefe50b14c9dac86d953c7207ddecd3 --- /dev/null +++ b/ee/app/assets/javascripts/vulnerabilities/new_vulnerability_init.js @@ -0,0 +1,18 @@ +import Vue from 'vue'; +import apolloProvider from 'ee/security_dashboard/graphql/provider'; +import App from 'ee/vulnerabilities/components/new_vulnerability/new_vulnerability.vue'; + +export default (el) => { + if (!el) { + return null; + } + + return new Vue({ + el, + apolloProvider, + render: (h) => + h(App, { + props: {}, + }), + }); +}; diff --git a/ee/app/controllers/projects/security/vulnerabilities_controller.rb b/ee/app/controllers/projects/security/vulnerabilities_controller.rb index 83e6a22e92c013321abe4dfa4c5e232acca7f2b0..aade28d590cea85b8c3d36345960849d1bca6b77 100644 --- a/ee/app/controllers/projects/security/vulnerabilities_controller.rb +++ b/ee/app/controllers/projects/security/vulnerabilities_controller.rb @@ -12,7 +12,8 @@ class VulnerabilitiesController < Projects::ApplicationController push_frontend_feature_flag(:create_vulnerability_jira_issue_via_graphql, @project, default_enabled: :yaml) end - before_action :vulnerability, except: :index + before_action :vulnerability, except: [:index, :new] + before_action :authorize_create_vulnerability!, only: :new alias_method :vulnerable, :project diff --git a/ee/app/views/projects/security/vulnerabilities/new.html.haml b/ee/app/views/projects/security/vulnerabilities/new.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..c90fdb68de8684ea3ce3ea07b3dca107e5e6b877 --- /dev/null +++ b/ee/app/views/projects/security/vulnerabilities/new.html.haml @@ -0,0 +1,7 @@ +- @content_class = "limit-container-width" unless fluid_layout +- add_to_breadcrumbs _("Vulnerability Report"), project_security_vulnerability_report_index_path(@project) +- breadcrumb_title _("Add vulnerability finding") +- page_title _("Add vulnerability finding") +- add_page_specific_style 'page_bundles/security_dashboard' + +#js-vulnerability-new diff --git a/ee/config/routes/project.rb b/ee/config/routes/project.rb index f777499500b9f61b4afaf42ca846590b70b09081..43ce78e6f73a5e1b5d101bd5353f316b3eb53d2e 100644 --- a/ee/config/routes/project.rb +++ b/ee/config/routes/project.rb @@ -76,7 +76,7 @@ resources :scanned_resources, only: [:index] - resources :vulnerabilities, only: [:show] do + resources :vulnerabilities, only: [:show, :new] do member do get :discussions, format: :json end diff --git a/ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb b/ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb index af91a0a582a041e70c0d9c6b6d715731700df806..5bbed9dc9b7cfd89ca3a0c4c4745240ab9840ed3 100644 --- a/ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb +++ b/ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb @@ -15,6 +15,34 @@ sign_in(user) end + describe 'GET #new' do + let(:request_new_vulnerability_page) { get :new, params: { namespace_id: project.namespace, project_id: project } } + + include_context '"Security & Compliance" permissions' do + let(:valid_request) { request_new_vulnerability_page } + end + + it 'renders the add new finding page' do + request_new_vulnerability_page + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when user can not create vulnerability' do + before do + guest = create(:user) + project.add_guest(guest) + sign_in(guest) + end + + it 'renders a 403' do + request_new_vulnerability_page + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + describe 'GET #show' do let_it_be(:pipeline) { create(:ci_pipeline, sha: project.commit.id, project: project, user: user) } let_it_be(:vulnerability) { create(:vulnerability, project: project) } diff --git a/ee/spec/frontend/vulnerabilities/new_vulnerability/new_vulnerability_spec.js b/ee/spec/frontend/vulnerabilities/new_vulnerability/new_vulnerability_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..08ff7b31b5361eefe1d21a584a7f818c4abfac77 --- /dev/null +++ b/ee/spec/frontend/vulnerabilities/new_vulnerability/new_vulnerability_spec.js @@ -0,0 +1,27 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import NewVulnerability from 'ee/vulnerabilities/components/new_vulnerability/new_vulnerability.vue'; + +describe('New vulnerability component', () => { + let wrapper; + + const createWrapper = () => { + return shallowMountExtended(NewVulnerability, {}); + }; + + beforeEach(() => { + wrapper = createWrapper(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('should render the page title and description', () => { + expect(wrapper.findByRole('heading', { name: 'Add vulnerability finding' }).exists()).toBe( + true, + ); + expect(wrapper.findByTestId('page-description').text()).toBe( + 'Manually add a vulnerability entry into the vulnerability report.', + ); + }); +}); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index afd39e9cfa5321737a8ff0baf963c605709f3a8f..f87833e829d6560d84b4e9bc04296cd7dcd4eae8 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2133,6 +2133,9 @@ msgstr "" msgid "Add variable" msgstr "" +msgid "Add vulnerability finding" +msgstr "" + msgid "Add webhook" msgstr "" @@ -38397,6 +38400,9 @@ msgstr "" msgid "VulnerabilityManagement|A true-positive and will fix" msgstr "" +msgid "VulnerabilityManagement|Add vulnerability finding" +msgstr "" + msgid "VulnerabilityManagement|Change status" msgstr "" @@ -38412,6 +38418,9 @@ msgstr "" msgid "VulnerabilityManagement|Fetching linked Jira issues" msgstr "" +msgid "VulnerabilityManagement|Manually add a vulnerability entry into the vulnerability report." +msgstr "" + msgid "VulnerabilityManagement|Needs triage" msgstr ""