summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 18:07:07 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 18:07:07 +0000
commit8746f6e79d7717a8cb16737fecdb977feaa22cdb (patch)
treecd1080192931a17e459fc5b476f3c5d91f83dde3 /spec
parent30785cadee10a5deaa45ada13def96bcfa6663b0 (diff)
downloadgitlab-ce-8746f6e79d7717a8cb16737fecdb977feaa22cdb.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/ci/reports/security/findings.rb1
-rw-r--r--spec/fixtures/security_reports/master/gl-common-scanning-report.json6
-rw-r--r--spec/frontend/super_sidebar/components/frequent_items_list_spec.js28
-rw-r--r--spec/frontend/super_sidebar/components/help_center_spec.js6
-rw-r--r--spec/frontend/super_sidebar/components/items_list_spec.js44
-rw-r--r--spec/frontend/super_sidebar/components/sidebar_menu_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/chronic_duration_input_spec.js7
-rw-r--r--spec/graphql/mutations/environments/update_spec.rb56
-rw-r--r--spec/helpers/safe_format_helper_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/parsers/security/common_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/reports/security/report_spec.rb4
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb23
-rw-r--r--spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb24
-rw-r--r--spec/requests/api/graphql/mutations/environments/update_spec.rb70
-rw-r--r--spec/services/environments/update_service_spec.rb55
-rw-r--r--spec/services/security/merge_reports_service_spec.rb58
16 files changed, 338 insertions, 91 deletions
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('<b>%{value}</b>', value: '<br>')
+ end
+ end
+ end
+
+ it 'safetly formats' do
+ expect(view_component.new.call)
+ .to eq('&lt;b&gt;&lt;br&gt;&lt;/b&gt;')
+ 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,