From 8746f6e79d7717a8cb16737fecdb977feaa22cdb Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 17 May 2023 18:07:07 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- spec/factories/ci/reports/security/findings.rb | 1 - .../master/gl-common-scanning-report.json | 6 +- .../components/frequent_items_list_spec.js | 28 +++++---- .../super_sidebar/components/help_center_spec.js | 6 +- .../super_sidebar/components/items_list_spec.js | 44 +------------- .../super_sidebar/components/sidebar_menu_spec.js | 8 +++ .../components/chronic_duration_input_spec.js | 7 +-- spec/graphql/mutations/environments/update_spec.rb | 56 +++++++++++++++++ spec/helpers/safe_format_helper_spec.rb | 17 ++++++ spec/lib/gitlab/ci/parsers/security/common_spec.rb | 22 ++++--- spec/lib/gitlab/ci/reports/security/report_spec.rb | 4 +- .../schema_validation/schema_inconsistency_spec.rb | 23 +++++++ .../schema_validation/track_inconsistency_spec.rb | 24 ++++++-- .../graphql/mutations/environments/update_spec.rb | 70 ++++++++++++++++++++++ spec/services/environments/update_service_spec.rb | 55 +++++++++++++++++ .../security/merge_reports_service_spec.rb | 58 ++++++++++++++---- 16 files changed, 338 insertions(+), 91 deletions(-) create mode 100644 spec/graphql/mutations/environments/update_spec.rb create mode 100644 spec/requests/api/graphql/mutations/environments/update_spec.rb create mode 100644 spec/services/environments/update_service_spec.rb (limited to 'spec') diff --git a/spec/factories/ci/reports/security/findings.rb b/spec/factories/ci/reports/security/findings.rb index c57a2dd479f..2641c618b09 100644 --- a/spec/factories/ci/reports/security/findings.rb +++ b/spec/factories/ci/reports/security/findings.rb @@ -2,7 +2,6 @@ FactoryBot.define do factory :ci_reports_security_finding, class: '::Gitlab::Ci::Reports::Security::Finding' do - compare_key { "#{identifiers.first&.external_type}:#{identifiers.first&.external_id}:#{location.fingerprint}" } confidence { :medium } identifiers { Array.new(1) { association(:ci_reports_security_identifier) } } location factory: :ci_reports_security_locations_sast diff --git a/spec/fixtures/security_reports/master/gl-common-scanning-report.json b/spec/fixtures/security_reports/master/gl-common-scanning-report.json index 4c494963a79..d1f824b90fa 100644 --- a/spec/fixtures/security_reports/master/gl-common-scanning-report.json +++ b/spec/fixtures/security_reports/master/gl-common-scanning-report.json @@ -90,6 +90,7 @@ "message": "Remediation for this vulnerability should remediate CVE-2140 as well", "description": "", "cve": "CVE-2139", + "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d4", "severity": "High", "solution": "Upgrade to latest version.", "scanner": { @@ -132,6 +133,7 @@ "message": "Remediation for this vulnerability should remediate CVE-2139 as well", "description": "", "cve": "CVE-2140", + "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d5", "severity": "High", "solution": "Upgrade to latest version.", "scanner": { @@ -439,10 +441,10 @@ { "fixes": [ { - "cve": "CVE-2139" + "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d4" }, { - "cve": "CVE-2140" + "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d5" } ], "summary": "this remediates CVE-2139 and CVE-2140", diff --git a/spec/frontend/super_sidebar/components/frequent_items_list_spec.js b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js index 5329a8f5da3..63dd941974a 100644 --- a/spec/frontend/super_sidebar/components/frequent_items_list_spec.js +++ b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js @@ -1,4 +1,4 @@ -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; import { s__ } from '~/locale'; import FrequentItemsList from '~/super_sidebar/components//frequent_items_list.vue'; import ItemsList from '~/super_sidebar/components/items_list.vue'; @@ -18,18 +18,20 @@ describe('FrequentItemsList component', () => { const findListTitle = () => wrapper.findByTestId('list-title'); const findItemsList = () => wrapper.findComponent(ItemsList); const findEmptyText = () => wrapper.findByTestId('empty-text'); + const findRemoveItemButton = () => wrapper.findByTestId('item-remove'); - const createWrapper = ({ props = {} } = {}) => { - wrapper = shallowMountExtended(FrequentItemsList, { + const createWrapperFactory = (mountFn = shallowMountExtended) => () => { + wrapper = mountFn(FrequentItemsList, { propsData: { title, pristineText, storageKey, maxItems, - ...props, }, }); }; + const createWrapper = createWrapperFactory(); + const createFullWrapper = createWrapperFactory(mountExtended); describe('default', () => { beforeEach(() => { @@ -64,16 +66,20 @@ describe('FrequentItemsList component', () => { it('does not render the empty text slot', () => { expect(findEmptyText().exists()).toBe(false); }); + }); - describe('items editing', () => { - it('remove-item event emission from items-list causes list item to be removed', async () => { - const localStorageProjects = findItemsList().props('items'); + describe('items editing', () => { + beforeEach(() => { + window.localStorage.setItem(storageKey, cachedFrequentProjects); + createFullWrapper(); + }); - await findItemsList().vm.$emit('remove-item', localStorageProjects[0]); + it('remove-item event emission from items-list causes list item to be removed', async () => { + const localStorageProjects = findItemsList().props('items'); + await findRemoveItemButton().trigger('click'); - expect(findItemsList().props('items')).toHaveLength(maxItems - 1); - expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]); - }); + expect(findItemsList().props('items')).toHaveLength(maxItems - 1); + expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]); }); }); }); diff --git a/spec/frontend/super_sidebar/components/help_center_spec.js b/spec/frontend/super_sidebar/components/help_center_spec.js index 808c30436a3..a727fe6c243 100644 --- a/spec/frontend/super_sidebar/components/help_center_spec.js +++ b/spec/frontend/super_sidebar/components/help_center_spec.js @@ -4,7 +4,7 @@ import toggleWhatsNewDrawer from '~/whats_new'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import HelpCenter from '~/super_sidebar/components/help_center.vue'; import { helpPagePath } from '~/helpers/help_page_helper'; -import { DOMAIN, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility'; +import { DOCS_URL, FORUM_URL, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility'; import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { STORAGE_KEY } from '~/whats_new/utils/notification'; import { helpCenterState } from '~/super_sidebar/constants'; @@ -52,7 +52,7 @@ describe('HelpCenter component', () => { }, { text: HelpCenter.i18n.docs, - href: `https://docs.${DOMAIN}`, + href: DOCS_URL, extraAttrs: trackingAttrs('gitlab_documentation'), }, { @@ -62,7 +62,7 @@ describe('HelpCenter component', () => { }, { text: HelpCenter.i18n.forum, - href: `https://forum.${DOMAIN}/`, + href: FORUM_URL, extraAttrs: trackingAttrs('community_forum'), }, { diff --git a/spec/frontend/super_sidebar/components/items_list_spec.js b/spec/frontend/super_sidebar/components/items_list_spec.js index d5e8043cce9..8e00984f500 100644 --- a/spec/frontend/super_sidebar/components/items_list_spec.js +++ b/spec/frontend/super_sidebar/components/items_list_spec.js @@ -1,5 +1,4 @@ -import { GlIcon } from '@gitlab/ui'; -import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ItemsList from '~/super_sidebar/components/items_list.vue'; import NavItem from '~/super_sidebar/components/nav_item.vue'; import { cachedFrequentProjects } from '../mock_data'; @@ -12,8 +11,8 @@ describe('ItemsList component', () => { const findNavItems = () => wrapper.findAllComponents(NavItem); - const createWrapper = ({ props = {}, slots = {}, mountFn = shallowMountExtended } = {}) => { - wrapper = mountFn(ItemsList, { + const createWrapper = ({ props = {}, slots = {} } = {}) => { + wrapper = shallowMountExtended(ItemsList, { propsData: { ...props, }, @@ -61,41 +60,4 @@ describe('ItemsList component', () => { expect(wrapper.findByTestId(testId).exists()).toBe(true); }); - - describe('item removal', () => { - const findRemoveButton = () => wrapper.findByTestId('item-remove'); - const mockProject = { - ...firstMockedProject, - title: firstMockedProject.name, - }; - - beforeEach(() => { - createWrapper({ - props: { - items: [mockProject], - }, - mountFn: mountExtended, - }); - }); - - it('renders the remove button', () => { - const itemRemoveButton = findRemoveButton(); - - expect(itemRemoveButton.exists()).toBe(true); - expect(itemRemoveButton.attributes('title')).toBe('Remove'); - expect(itemRemoveButton.findComponent(GlIcon).props('name')).toBe('dash'); - }); - - it('emits `remove-item` event with item param when remove button is clicked', () => { - const itemRemoveButton = findRemoveButton(); - - itemRemoveButton.vm.$emit( - 'click', - { stopPropagation: jest.fn(), preventDefault: jest.fn() }, - mockProject, - ); - - expect(wrapper.emitted('remove-item')).toEqual([[mockProject]]); - }); - }); }); diff --git a/spec/frontend/super_sidebar/components/sidebar_menu_spec.js b/spec/frontend/super_sidebar/components/sidebar_menu_spec.js index 9b726b620dd..19471f28fab 100644 --- a/spec/frontend/super_sidebar/components/sidebar_menu_spec.js +++ b/spec/frontend/super_sidebar/components/sidebar_menu_spec.js @@ -1,4 +1,5 @@ import { mountExtended } from 'helpers/vue_test_utils_helper'; +import { s__ } from '~/locale'; import SidebarMenu from '~/super_sidebar/components/sidebar_menu.vue'; import PinnedSection from '~/super_sidebar/components/pinned_section.vue'; import { PANELS_WITH_PINS } from '~/super_sidebar/constants'; @@ -181,4 +182,11 @@ describe('SidebarMenu component', () => { expect(findMainMenuSeparator().exists()).toBe(false); }); }); + + describe('template', () => { + it('adds aria-label attribute to nav element', () => { + createWrapper({ ...sidebarData }); + expect(wrapper.find('nav').attributes('aria-label')).toBe(s__('Navigation|Main navigation')); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/chronic_duration_input_spec.js b/spec/frontend/vue_shared/components/chronic_duration_input_spec.js index 2a40511affb..374babe3a97 100644 --- a/spec/frontend/vue_shared/components/chronic_duration_input_spec.js +++ b/spec/frontend/vue_shared/components/chronic_duration_input_spec.js @@ -310,12 +310,11 @@ describe('vue_shared/components/chronic_duration_input', () => { }); it('passes updated prop via v-model', async () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ value: MOCK_VALUE }); + textElement.value = '2hr20min'; + textElement.dispatchEvent(new Event('input')); await nextTick(); - expect(textElement.value).toBe('2 hrs 20 mins'); + expect(textElement.value).toBe('2hr20min'); expect(hiddenElement.value).toBe(MOCK_VALUE.toString()); }); }); diff --git a/spec/graphql/mutations/environments/update_spec.rb b/spec/graphql/mutations/environments/update_spec.rb new file mode 100644 index 00000000000..87c1bd5a44b --- /dev/null +++ b/spec/graphql/mutations/environments/update_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Environments::Update, feature_category: :environment_management do + let_it_be(:project) { create(:project) } + let_it_be(:environment) { create(:environment, project: project) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:reporter) { create(:user) } + + let(:user) { maintainer } + + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } + + before_all do + project.add_maintainer(maintainer) + project.add_reporter(reporter) + end + + describe '#resolve' do + subject { mutation.resolve(id: environment_id, external_url: external_url) } + + let(:environment_id) { environment.to_global_id } + let(:external_url) { 'https://gitlab.com/' } + + context 'when service execution succeeded' do + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + + it 'updates the environment' do + expect(subject[:environment][:external_url]).to eq(external_url) + end + end + + context 'when service cannot update the attribute' do + let(:external_url) { 'http://${URL}' } + + it 'returns an error' do + expect(subject) + .to eq({ + environment: environment, + errors: ['External url URI is invalid'] + }) + end + end + + context 'when user is reporter who does not have permission to access the environment' do + let(:user) { reporter } + + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR) + end + end + end +end diff --git a/spec/helpers/safe_format_helper_spec.rb b/spec/helpers/safe_format_helper_spec.rb index ced48b0c9c1..33c4c86ecc8 100644 --- a/spec/helpers/safe_format_helper_spec.rb +++ b/spec/helpers/safe_format_helper_spec.rb @@ -37,5 +37,22 @@ RSpec.describe SafeFormatHelper, feature_category: :shared do .to raise_error ArgumentError, message end end + + context 'with a view component' do + let(:view_component) do + Class.new(ViewComponent::Base) do + include SafeFormatHelper + + def call + safe_format('%{value}', value: '
') + end + end + end + + it 'safetly formats' do + expect(view_component.new.call) + .to eq('<b><br></b>') + end + end end end diff --git a/spec/lib/gitlab/ci/parsers/security/common_spec.rb b/spec/lib/gitlab/ci/parsers/security/common_spec.rb index 421aa29f860..bce82a5fb4a 100644 --- a/spec/lib/gitlab/ci/parsers/security/common_spec.rb +++ b/spec/lib/gitlab/ci/parsers/security/common_spec.rb @@ -184,8 +184,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera let(:artifact) { build(:ci_job_artifact, :common_security_report_with_blank_names) } context 'when message is provided' do + let(:finding) { report.findings.first } + it 'sets message from the report as a finding name' do - finding = report.findings.find { |x| x.compare_key == 'CVE-1020' } expected_name = Gitlab::Json.parse(finding.raw_metadata)['message'] expect(finding.name).to eq(expected_name) @@ -194,8 +195,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera context 'when message is not provided' do context 'and name is provided' do + let(:finding) { report.findings.second } + it 'sets name from the report as a name' do - finding = report.findings.find { |x| x.compare_key == 'CVE-1030' } expected_name = Gitlab::Json.parse(finding.raw_metadata)['name'] expect(finding.name).to eq(expected_name) @@ -203,11 +205,12 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera end context 'and name is not provided' do + let(:finding) { report.findings[2] } + context 'when location does not exist' do let(:location) { nil } it 'returns only identifier name' do - finding = report.findings.find { |x| x.compare_key == 'CVE-2017-11429' } expect(finding.name).to eq("CVE-2017-11429") end end @@ -215,21 +218,22 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera context 'when location exists' do context 'when CVE identifier exists' do it 'combines identifier with location to create name' do - finding = report.findings.find { |x| x.compare_key == 'CVE-2017-11429' } expect(finding.name).to eq("CVE-2017-11429 in yarn.lock") end end context 'when CWE identifier exists' do + let(:finding) { report.findings[3] } + it 'combines identifier with location to create name' do - finding = report.findings.find { |x| x.compare_key == 'CWE-2017-11429' } expect(finding.name).to eq("CWE-2017-11429 in yarn.lock") end end context 'when neither CVE nor CWE identifier exist' do + let(:finding) { report.findings[4] } + it 'combines identifier with location to create name' do - finding = report.findings.find { |x| x.compare_key == 'OTHER-2017-11429' } expect(finding.name).to eq("other-2017-11429 in yarn.lock") end end @@ -240,8 +244,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera describe 'parsing finding.details' do context 'when details are provided' do + let(:finding) { report.findings[4] } + it 'sets details from the report' do - finding = report.findings.find { |x| x.compare_key == 'CVE-1020' } expected_details = Gitlab::Json.parse(finding.raw_metadata)['details'] expect(finding.details).to eq(expected_details) @@ -249,8 +254,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera end context 'when details are not provided' do + let(:finding) { report.findings[5] } + it 'sets empty hash' do - finding = report.findings.find { |x| x.compare_key == 'CVE-1030' } expect(finding.details).to eq({}) end end diff --git a/spec/lib/gitlab/ci/reports/security/report_spec.rb b/spec/lib/gitlab/ci/reports/security/report_spec.rb index d7f967f1c55..dabee0f32de 100644 --- a/spec/lib/gitlab/ci/reports/security/report_spec.rb +++ b/spec/lib/gitlab/ci/reports/security/report_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Reports::Security::Report do +RSpec.describe Gitlab::Ci::Reports::Security::Report, feature_category: :vulnerability_management do let_it_be(:pipeline) { create(:ci_pipeline) } let(:created_at) { 2.weeks.ago } @@ -89,7 +89,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do let(:other_report) do create( :ci_reports_security_report, - findings: [create(:ci_reports_security_finding, compare_key: 'other_finding')], + findings: [create(:ci_reports_security_finding)], scanners: [create(:ci_reports_security_scanner, external_id: 'other_scanner', name: 'Other Scanner')], identifiers: [create(:ci_reports_security_identifier, external_id: 'other_id', name: 'other_scanner')] ) diff --git a/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb index 7d6a279def9..653ca0a2b2b 100644 --- a/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb +++ b/spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb @@ -14,4 +14,27 @@ RSpec.describe Gitlab::Database::SchemaValidation::SchemaInconsistency, type: :m it { is_expected.to validate_presence_of(:valitador_name) } it { is_expected.to validate_presence_of(:table_name) } end + + describe 'scopes' do + describe '.with_open_issues' do + subject(:inconsistencies) { described_class.with_open_issues } + + let(:closed_issue) { create(:issue, :closed) } + let(:open_issue) { create(:issue, :opened) } + + let!(:schema_inconsistency_with_issue_closed) do + create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements', + valitador_name: 'different_definition_indexes', issue: closed_issue) + end + + let!(:schema_inconsistency_with_issue_opened) do + create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements', + valitador_name: 'different_definition_indexes', issue: open_issue) + end + + it 'returns only schema inconsistencies with GitLab issues open' do + expect(inconsistencies).to eq([schema_inconsistency_with_issue_opened]) + end + end + end end diff --git a/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb b/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb index 84db721fc2d..bb83dfa796f 100644 --- a/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb +++ b/spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb @@ -63,19 +63,31 @@ RSpec.describe Gitlab::Database::SchemaValidation::TrackInconsistency, feature_c end context 'when the schema inconsistency already exists' do + let!(:schema_inconsistency) do + create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements', + valitador_name: 'different_definition_indexes') + end + before do project.add_developer(user) end - let!(:schema_inconsistency) do - create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements', - valitador_name: 'different_definition_indexes') + context 'when the GitLab issue is open' do + it 'does not create a new schema inconsistency record' do + allow(Gitlab).to receive(:com?).and_return(true) + schema_inconsistency.issue.update!(state_id: Issue.available_states[:opened]) + + expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count } + end end - it 'does not create a schema inconsistency record' do - allow(Gitlab).to receive(:com?).and_return(true) + context 'when the GitLab is not open' do + it 'creates a new schema inconsistency record' do + allow(Gitlab).to receive(:com?).and_return(true) + schema_inconsistency.issue.update!(state_id: Issue.available_states[:closed]) - expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count } + expect { execute }.to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count } + end end end end diff --git a/spec/requests/api/graphql/mutations/environments/update_spec.rb b/spec/requests/api/graphql/mutations/environments/update_spec.rb new file mode 100644 index 00000000000..9c68b3a024c --- /dev/null +++ b/spec/requests/api/graphql/mutations/environments/update_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Update Environment', feature_category: :deployment_management do + include GraphqlHelpers + + let_it_be(:project) { create(:project, :repository) } + let_it_be(:environment) { create(:environment, project: project) } + let_it_be(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } + let_it_be(:developer) { create(:user).tap { |u| project.add_maintainer(u) } } + + let(:environment_id) { environment.to_global_id.to_s } + let(:current_user) { developer } + + let(:mutation) do + graphql_mutation(:environment_update, input) + end + + context 'when updating external URL' do + let(:input) do + { + id: environment_id, + external_url: 'https://gitlab.com/' + } + end + + it 'updates successfully' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to change { environment.reload.external_url }.to('https://gitlab.com/') + + expect(graphql_mutation_response(:environment_update)['errors']).to be_empty + end + + context 'when url is invalid' do + let(:input) do + { + id: environment_id, + external_url: 'http://${URL}' + } + end + + it 'returns error' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.not_to change { environment.reload.external_url } + + expect(graphql_mutation_response(:environment_update)['errors'].first).to include('URI is invalid') + end + end + end + + context 'when updating tier' do + let(:input) do + { + id: environment_id, + tier: 'STAGING' + } + end + + it 'updates successfully' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to change { environment.reload.tier }.to('staging') + + expect(graphql_mutation_response(:environment_update)['errors']).to be_empty + end + end +end diff --git a/spec/services/environments/update_service_spec.rb b/spec/services/environments/update_service_spec.rb new file mode 100644 index 00000000000..72ace3b050e --- /dev/null +++ b/spec/services/environments/update_service_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Environments::UpdateService, feature_category: :environment_management do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } } + let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } } + let_it_be(:environment) { create(:environment, project: project) } + + let(:service) { described_class.new(project, current_user, params) } + let(:current_user) { developer } + let(:params) { {} } + + describe '#execute' do + subject { service.execute(environment) } + + let(:params) { { external_url: 'https://gitlab.com/' } } + + it 'updates the external URL' do + expect { subject }.to change { environment.reload.external_url }.to('https://gitlab.com/') + end + + it 'returns successful response' do + response = subject + + expect(response).to be_success + expect(response.payload[:environment]).to eq(environment) + end + + context 'when params contain invalid value' do + let(:params) { { external_url: 'http://${URL}' } } + + it 'returns an error' do + response = subject + + expect(response).to be_error + expect(response.message).to match_array("External url URI is invalid") + expect(response.payload[:environment]).to eq(environment) + end + end + + context 'when user is reporter' do + let(:current_user) { reporter } + + it 'returns an error' do + response = subject + + expect(response).to be_error + expect(response.message).to eq('Unauthorized to update the environment') + expect(response.payload[:environment]).to eq(environment) + end + end + end +end diff --git a/spec/services/security/merge_reports_service_spec.rb b/spec/services/security/merge_reports_service_spec.rb index 809d0b27c20..a101003a7dd 100644 --- a/spec/services/security/merge_reports_service_spec.rb +++ b/spec/services/security/merge_reports_service_spec.rb @@ -19,7 +19,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod build(:ci_reports_security_finding, identifiers: [identifier_1_primary, identifier_1_cve], scanner: scanner_1, - severity: :low + severity: :low, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94610' ) end @@ -27,7 +28,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod build(:ci_reports_security_finding, identifiers: [identifier_1_primary, identifier_1_cve], scanner: scanner_1, - severity: :low + severity: :low, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94611' ) end @@ -36,7 +38,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod identifiers: [identifier_2_primary, identifier_2_cve], location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34), scanner: scanner_2, - severity: :medium + severity: :medium, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94612' ) end @@ -45,7 +48,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod identifiers: [identifier_2_primary, identifier_2_cve], location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34), scanner: scanner_2, - severity: :medium + severity: :medium, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94613' ) end @@ -54,7 +58,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod identifiers: [identifier_2_primary, identifier_2_cve], location: build(:ci_reports_security_locations_sast, start_line: 42, end_line: 44), scanner: scanner_2, - severity: :medium + severity: :medium, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94614' ) end @@ -62,7 +67,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod build(:ci_reports_security_finding, identifiers: [identifier_cwe], scanner: scanner_3, - severity: :high + severity: :high, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94615' ) end @@ -70,7 +76,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod build(:ci_reports_security_finding, identifiers: [identifier_cwe], scanner: scanner_1, - severity: :critical + severity: :critical, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94616' ) end @@ -78,7 +85,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod build(:ci_reports_security_finding, identifiers: [identifier_wasc], scanner: scanner_1, - severity: :medium + severity: :medium, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94617' ) end @@ -86,7 +94,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod build(:ci_reports_security_finding, identifiers: [identifier_wasc], scanner: scanner_2, - severity: :critical + severity: :critical, + uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94618' ) end @@ -190,8 +199,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod finding_cwe_2, finding_wasc_2, finding_cwe_1, - finding_id_2_loc_2, finding_id_2_loc_1, + finding_id_2_loc_2, finding_wasc_1, finding_id_1 ]) @@ -217,9 +226,32 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod let(:identifier_cve) { build(:ci_reports_security_identifier, external_id: 'CVE-2019-123', external_type: 'cve') } let(:identifier_semgrep) { build(:ci_reports_security_identifier, external_id: 'rules.bandit.B105', external_type: 'semgrep_id') } - let(:finding_id_1) { build(:ci_reports_security_finding, identifiers: [identifier_bandit, identifier_cve], scanner: bandit_scanner, report_type: :sast) } - let(:finding_id_2) { build(:ci_reports_security_finding, identifiers: [identifier_cve], scanner: semgrep_scanner, report_type: :sast) } - let(:finding_id_3) { build(:ci_reports_security_finding, identifiers: [identifier_semgrep], scanner: semgrep_scanner, report_type: :sast) } + let(:finding_id_1) do + build( + :ci_reports_security_finding, + identifiers: [identifier_bandit, identifier_cve], + scanner: bandit_scanner, + report_type: :sast, + uuid: '21ab978a-7052-5428-af0b-c7a4b3fe5020') + end + + let(:finding_id_2) do + build( + :ci_reports_security_finding, + identifiers: [identifier_cve], + scanner: semgrep_scanner, + report_type: :sast, + uuid: '21ab978a-7052-5428-af0b-c7a4b3fe5021') + end + + let(:finding_id_3) do + build( + :ci_reports_security_finding, + identifiers: [identifier_semgrep], + scanner: semgrep_scanner, + report_type: :sast, + uuid: '21ab978a-7052-5428-af0b-c7a4b3fe5022') + end let(:bandit_report) do build(:ci_reports_security_report, -- cgit v1.2.1