Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-07 18:12:19 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-07 18:12:19 +0300
commit9a940dabf04df126e7978c0ab4b8770b86dcaaa8 (patch)
treef8b244f0cd4bf455015b97ba72ea3d4b51419d05 /spec
parent8e81ce50767bd5c785072c2487ffb61fe075977c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/channels/application_cable/connection_spec.rb10
-rw-r--r--spec/features/projects/work_items/work_item_children_spec.rb2
-rw-r--r--spec/frontend/projects/components/shared/delete_modal_spec.js2
-rw-r--r--spec/frontend/projects/settings_service_desk/components/custom_email_spec.js24
-rw-r--r--spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js27
-rw-r--r--spec/frontend/vue_shared/components/entity_select/entity_select_spec.js10
-rw-r--r--spec/frontend/vue_shared/components/entity_select/organization_select_spec.js44
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb72
-rw-r--r--spec/mailers/emails/service_desk_spec.rb5
-rw-r--r--spec/models/application_setting_spec.rb18
-rw-r--r--spec/models/packages/package_spec.rb24
-rw-r--r--spec/requests/acme_challenges_controller_spec.rb9
-rw-r--r--spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb20
-rw-r--r--spec/requests/api/graphql/mutations/packages/destroy_spec.rb11
-rw-r--r--spec/requests/api/settings_spec.rb14
-rw-r--r--spec/requests/api/users_spec.rb3
-rw-r--r--spec/requests/application_controller_spec.rb15
-rw-r--r--spec/requests/chaos_controller_spec.rb14
-rw-r--r--spec/requests/content_security_policy_spec.rb79
-rw-r--r--spec/requests/health_controller_spec.rb8
-rw-r--r--spec/requests/metrics_controller_spec.rb9
-rw-r--r--spec/requests/oauth/authorizations_controller_spec.rb4
-rw-r--r--spec/requests/registrations_controller_spec.rb6
-rw-r--r--spec/requests/sessions_spec.rb4
-rw-r--r--spec/services/packages/mark_package_for_destruction_service_spec.rb2
-rw-r--r--spec/services/packages/mark_packages_for_destruction_service_spec.rb71
-rw-r--r--spec/services/service_desk/custom_email_verifications/update_service_spec.rb64
-rw-r--r--spec/support/rspec_order_todo.yml1
-rw-r--r--spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb80
29 files changed, 456 insertions, 196 deletions
diff --git a/spec/channels/application_cable/connection_spec.rb b/spec/channels/application_cable/connection_spec.rb
index 4943669bde0..fa2518e1970 100644
--- a/spec/channels/application_cable/connection_spec.rb
+++ b/spec/channels/application_cable/connection_spec.rb
@@ -43,6 +43,16 @@ RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_sessions do
end
end
+ context 'when bearer header is provided' do
+ let(:user_pat) { create(:personal_access_token) }
+
+ it 'finds user by PAT' do
+ connect(ActionCable.server.config.mount_path, headers: { Authorization: "Bearer #{user_pat.token}" })
+
+ expect(connection.current_user).to eq(user_pat.user)
+ end
+ end
+
context 'when session cookie is not set' do
it 'sets current_user to nil' do
connect
diff --git a/spec/features/projects/work_items/work_item_children_spec.rb b/spec/features/projects/work_items/work_item_children_spec.rb
index 0970752157d..28f7ee2db10 100644
--- a/spec/features/projects/work_items/work_item_children_spec.rb
+++ b/spec/features/projects/work_items/work_item_children_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Work item children', :js, feature_category: :team_planning do
it 'are not displayed when issue does not have work item children', :aggregate_failures do
page.within('[data-testid="work-item-links"]') do
- expect(find('[data-testid="links-empty"]')).to have_content(_('No tasks are currently assigned.'))
+ expect(find('[data-testid="links-empty"]')).to have_content(_('No child items are currently assigned.'))
expect(page).not_to have_selector('[data-testid="add-links-form"]')
expect(page).not_to have_selector('[data-testid="links-child"]')
end
diff --git a/spec/frontend/projects/components/shared/delete_modal_spec.js b/spec/frontend/projects/components/shared/delete_modal_spec.js
index c6213fd4b6d..7e040db4beb 100644
--- a/spec/frontend/projects/components/shared/delete_modal_spec.js
+++ b/spec/frontend/projects/components/shared/delete_modal_spec.js
@@ -49,7 +49,7 @@ describe('DeleteModal', () => {
attributes: {
variant: 'danger',
disabled: true,
- 'data-qa-selector': 'confirm_delete_button',
+ 'data-testid': 'confirm-delete-button',
},
},
actionCancel: {
diff --git a/spec/frontend/projects/settings_service_desk/components/custom_email_spec.js b/spec/frontend/projects/settings_service_desk/components/custom_email_spec.js
index faef932fc7f..0a593f3812a 100644
--- a/spec/frontend/projects/settings_service_desk/components/custom_email_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/custom_email_spec.js
@@ -3,7 +3,6 @@ import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import CustomEmail from '~/projects/settings_service_desk/components/custom_email.vue';
import {
- I18N_VERIFICATION_ERRORS,
I18N_STATE_VERIFICATION_STARTED,
I18N_STATE_VERIFICATION_FAILED,
I18N_STATE_VERIFICATION_FAILED_RESET_PARAGRAPH,
@@ -15,6 +14,7 @@ describe('CustomEmail', () => {
let wrapper;
const defaultProps = {
+ incomingEmail: 'incoming+test-1-issue-@example.com',
customEmail: 'user@example.com',
smtpAddress: 'smtp.example.com',
verificationState: 'started',
@@ -70,19 +70,21 @@ describe('CustomEmail', () => {
});
describe('verification error', () => {
- it.each([
- 'smtp_host_issue',
- 'invalid_credentials',
- 'mail_not_received_within_timeframe',
- 'incorrect_from',
- 'incorrect_token',
- 'read_timeout',
- ])('displays %s label and description', (error) => {
+ it.each`
+ error | label | description
+ ${'smtp_host_issue'} | ${'SMTP host issue'} | ${'A connection to the specified host could not be made or an SSL issue occurred.'}
+ ${'invalid_credentials'} | ${'Invalid credentials'} | ${'The given credentials (username and password) were rejected by the SMTP server, or you need to explicitly set an authentication method.'}
+ ${'mail_not_received_within_timeframe'} | ${'Verification email not received within timeframe'} | ${"The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."}
+ ${'incorrect_from'} | ${'Incorrect From header'} | ${'Check your forwarding settings and make sure the original email sender remains in the From header.'}
+ ${'incorrect_token'} | ${'Incorrect verification token'} | ${"The received email didn't contain the verification token that was sent to your email address."}
+ ${'read_timeout'} | ${'Read timeout'} | ${'The SMTP server did not respond in time.'}
+ ${'incorrect_forwarding_target'} | ${'Incorrect forwarding target'} | ${`Forward all emails to the custom email address to ${defaultProps.incomingEmail}`}
+ `('displays $error label and description', ({ error, label, description }) => {
createWrapper({ verificationError: error });
const text = wrapper.text();
- expect(text).toContain(I18N_VERIFICATION_ERRORS[error].label);
- expect(text).toContain(I18N_VERIFICATION_ERRORS[error].description);
+ expect(text).toContain(label);
+ expect(text).toContain(description);
});
});
diff --git a/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js b/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js
index 174e05ceeee..8d3a7a5fde5 100644
--- a/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js
@@ -38,6 +38,12 @@ describe('CustomEmailWrapper', () => {
customEmailEndpoint: '/flightjs/Flight/-/service_desk/custom_email',
};
+ const defaultCustomEmailProps = {
+ incomingEmail: defaultProps.incomingEmail,
+ customEmail: 'user@example.com',
+ smtpAddress: 'smtp.example.com',
+ };
+
const showToast = jest.fn();
const createWrapper = (props = {}) => {
@@ -117,8 +123,7 @@ describe('CustomEmailWrapper', () => {
expect(showToast).toHaveBeenCalledWith(I18N_TOAST_SAVED);
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'started',
verificationError: null,
isEnabled: false,
@@ -140,8 +145,7 @@ describe('CustomEmailWrapper', () => {
it('displays CustomEmail component', () => {
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'started',
verificationError: null,
isEnabled: false,
@@ -193,8 +197,7 @@ describe('CustomEmailWrapper', () => {
it('fetches data from endpoint and displays CustomEmail component', () => {
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'failed',
verificationError: 'smtp_host_issue',
isEnabled: false,
@@ -225,8 +228,7 @@ describe('CustomEmailWrapper', () => {
it('fetches data from endpoint and displays CustomEmail component', () => {
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'finished',
verificationError: null,
isEnabled: false,
@@ -257,8 +259,7 @@ describe('CustomEmailWrapper', () => {
expect(showToast).toHaveBeenCalledWith(I18N_TOAST_ENABLED);
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'finished',
verificationError: null,
isEnabled: true,
@@ -279,8 +280,7 @@ describe('CustomEmailWrapper', () => {
it('fetches data from endpoint and displays CustomEmail component', () => {
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'finished',
verificationError: null,
isEnabled: true,
@@ -301,8 +301,7 @@ describe('CustomEmailWrapper', () => {
expect(showToast).toHaveBeenCalledWith(I18N_TOAST_DISABLED);
expect(findCustomEmail().props()).toEqual({
- customEmail: 'user@example.com',
- smtpAddress: 'smtp.example.com',
+ ...defaultCustomEmailProps,
verificationState: 'finished',
verificationError: null,
isEnabled: false,
diff --git a/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js b/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js
index 1376133ec37..02da6079466 100644
--- a/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js
+++ b/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js
@@ -8,7 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises';
describe('EntitySelect', () => {
let wrapper;
let fetchItemsMock;
- let fetchInitialSelectionTextMock;
+ let fetchInitialSelectionMock;
// Mocks
const itemMock = {
@@ -96,16 +96,16 @@ describe('EntitySelect', () => {
});
it("fetches the initially selected value's name", async () => {
- fetchInitialSelectionTextMock = jest.fn().mockImplementation(() => itemMock.text);
+ fetchInitialSelectionMock = jest.fn().mockImplementation(() => itemMock);
createComponent({
props: {
- fetchInitialSelectionText: fetchInitialSelectionTextMock,
+ fetchInitialSelection: fetchInitialSelectionMock,
initialSelection: itemMock.value,
},
});
await nextTick();
- expect(fetchInitialSelectionTextMock).toHaveBeenCalledTimes(1);
+ expect(fetchInitialSelectionMock).toHaveBeenCalledTimes(1);
expect(findListbox().props('toggleText')).toBe(itemMock.text);
});
});
@@ -188,7 +188,7 @@ describe('EntitySelect', () => {
findListbox().vm.$emit('reset');
await nextTick();
- expect(Object.keys(wrapper.emitted('input')[2][0]).length).toBe(0);
+ expect(wrapper.emitted('input')[2][0]).toEqual({});
});
});
});
diff --git a/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js b/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js
index 02a85edc523..6dc38bbd0c6 100644
--- a/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js
+++ b/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js
@@ -1,8 +1,8 @@
import VueApollo from 'vue-apollo';
-import Vue, { nextTick } from 'vue';
-import { GlCollapsibleListbox } from '@gitlab/ui';
+import Vue from 'vue';
+import { GlCollapsibleListbox, GlAlert } from '@gitlab/ui';
import { chunk } from 'lodash';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import OrganizationSelect from '~/vue_shared/components/entity_select/organization_select.vue';
import EntitySelect from '~/vue_shared/components/entity_select/entity_select.vue';
import { DEFAULT_PER_PAGE } from '~/api';
@@ -17,6 +17,7 @@ import getOrganizationQuery from '~/organizations/shared/graphql/queries/organiz
import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data';
import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
Vue.use(VueApollo);
@@ -31,11 +32,6 @@ describe('OrganizationSelect', () => {
pageInfo,
};
- // Stubs
- const GlAlert = {
- template: '<div><slot /></div>',
- };
-
// Props
const label = 'label';
const description = 'description';
@@ -67,7 +63,7 @@ describe('OrganizationSelect', () => {
} = {}) => {
mockApollo = createMockApollo(handlers);
- wrapper = shallowMountExtended(OrganizationSelect, {
+ wrapper = mountExtended(OrganizationSelect, {
apolloProvider: mockApollo,
propsData: {
label,
@@ -77,10 +73,6 @@ describe('OrganizationSelect', () => {
toggleClass,
...props,
},
- stubs: {
- GlAlert,
- EntitySelect,
- },
listeners: {
input: handleInput,
},
@@ -88,10 +80,6 @@ describe('OrganizationSelect', () => {
};
const openListbox = () => findListbox().vm.$emit('shown');
- afterEach(() => {
- mockApollo = null;
- });
-
describe('entity_select props', () => {
beforeEach(() => {
createComponent();
@@ -114,15 +102,16 @@ describe('OrganizationSelect', () => {
describe('on mount', () => {
it('fetches organizations when the listbox is opened', async () => {
createComponent();
- await waitForPromises();
-
openListbox();
await waitForPromises();
- expect(findListbox().props('items')).toEqual([
- { text: nodes[0].name, value: 1 },
- { text: nodes[1].name, value: 2 },
- { text: nodes[2].name, value: 3 },
- ]);
+
+ const expectedItems = nodes.map((node) => ({
+ ...node,
+ text: node.name,
+ value: getIdFromGraphQLId(node.id),
+ }));
+
+ expect(findListbox().props('items')).toEqual(expectedItems);
});
describe('with an initial selection', () => {
@@ -136,7 +125,7 @@ describe('OrganizationSelect', () => {
it('show an error if fetching initially selected fails', async () => {
createComponent({
props: { initialSelection: organization.id },
- handlers: [[getOrganizationQuery, jest.fn().mockRejectedValueOnce(new Error())]],
+ handlers: [[getOrganizationQuery, jest.fn().mockRejectedValueOnce()]],
});
expect(findAlert().exists()).toBe(false);
@@ -183,7 +172,6 @@ describe('OrganizationSelect', () => {
await waitForPromises();
findListbox().vm.$emit('bottom-reached');
- await nextTick();
await waitForPromises();
});
@@ -198,10 +186,8 @@ describe('OrganizationSelect', () => {
it('shows an error when fetching organizations fails', async () => {
createComponent({
- handlers: [[getCurrentUserOrganizationsQuery, jest.fn().mockRejectedValueOnce(new Error())]],
+ handlers: [[getCurrentUserOrganizationsQuery, jest.fn().mockRejectedValueOnce()]],
});
- await waitForPromises();
-
openListbox();
expect(findAlert().exists()).toBe(false);
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index cb2d3fbcae4..e8156091f9d 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -462,7 +462,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
end
end
- shared_examples 'a handler that does not verify the custom email' do |error_identifier|
+ shared_examples 'a handler that does not verify the custom email' do
it 'does not verify the custom email address' do
# project has no owner, so only notify verification triggerer
expect(Notify).to receive(:service_desk_verification_result_email).once
@@ -477,20 +477,32 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
end
end
- shared_examples 'a handler that verifies Service Desk custom email verification emails' do
+ context 'when using incoming_email address' do
+ before do
+ stub_incoming_email_setting(enabled: true, address: 'support+%{key}@example.com')
+ end
+
it_behaves_like 'an early exiting handler'
context 'with valid service desk settings' do
let_it_be(:user) { create(:user) }
+ let_it_be(:credentials) { create(:service_desk_custom_email_credential, project: project) }
- let!(:settings) { create(:service_desk_setting, project: project, custom_email: 'custom-support-email@example.com') }
- let!(:verification) { create(:service_desk_custom_email_verification, project: project, token: 'ZROT4ZZXA-Y6', triggerer: user) }
+ let_it_be_with_reload(:settings) do
+ create(:service_desk_setting, project: project, custom_email: 'custom-support-email@example.com')
+ end
+
+ let_it_be_with_reload(:verification) do
+ create(:service_desk_custom_email_verification, project: project, token: 'ZROT4ZZXA-Y6', triggerer: user)
+ end
let(:message_delivery) { instance_double(ActionMailer::MessageDelivery) }
- before do
+ before_all do
project.add_maintainer(user)
+ end
+ before do
allow(message_delivery).to receive(:deliver_later)
allow(Notify).to receive(:service_desk_verification_result_email).and_return(message_delivery)
end
@@ -521,7 +533,9 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
verification.update!(token: 'XXXXXXXXXXXX')
end
- it_behaves_like 'a handler that does not verify the custom email', 'incorrect_token'
+ it_behaves_like 'a handler that does not verify the custom email' do
+ let(:error_identifier) { 'incorrect_token' }
+ end
end
context 'and verification email ingested too late' do
@@ -529,7 +543,9 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
verification.update!(triggered_at: ServiceDesk::CustomEmailVerification::TIMEFRAME.ago)
end
- it_behaves_like 'a handler that does not verify the custom email', 'mail_not_received_within_timeframe'
+ it_behaves_like 'a handler that does not verify the custom email' do
+ let(:error_identifier) { 'mail_not_received_within_timeframe' }
+ end
end
context 'and from header differs from custom email address' do
@@ -537,19 +553,13 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
settings.update!(custom_email: 'different-from@example.com')
end
- it_behaves_like 'a handler that does not verify the custom email', 'incorrect_from'
+ it_behaves_like 'a handler that does not verify the custom email' do
+ let(:error_identifier) { 'incorrect_from' }
+ end
end
end
end
- context 'when using incoming_email address' do
- before do
- stub_incoming_email_setting(enabled: true, address: 'support+%{key}@example.com')
- end
-
- it_behaves_like 'a handler that verifies Service Desk custom email verification emails'
- end
-
context 'when using service_desk_email address' do
let(:receiver) { Gitlab::Email::ServiceDeskReceiver.new(email_raw) }
@@ -557,7 +567,35 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
stub_service_desk_email_setting(enabled: true, address: 'support+%{key}@example.com')
end
- it_behaves_like 'a handler that verifies Service Desk custom email verification emails'
+ it_behaves_like 'an early exiting handler'
+
+ context 'with valid service desk settings' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:credentials) { create(:service_desk_custom_email_credential, project: project) }
+
+ let_it_be_with_reload(:settings) do
+ create(:service_desk_setting, project: project, custom_email: 'custom-support-email@example.com')
+ end
+
+ let_it_be_with_reload(:verification) do
+ create(:service_desk_custom_email_verification, project: project, token: 'ZROT4ZZXA-Y6', triggerer: user)
+ end
+
+ let(:message_delivery) { instance_double(ActionMailer::MessageDelivery) }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ before do
+ allow(message_delivery).to receive(:deliver_later)
+ allow(Notify).to receive(:service_desk_verification_result_email).and_return(message_delivery)
+ end
+
+ it_behaves_like 'a handler that does not verify the custom email' do
+ let(:error_identifier) { 'incorrect_forwarding_target' }
+ end
+ end
end
end
end
diff --git a/spec/mailers/emails/service_desk_spec.rb b/spec/mailers/emails/service_desk_spec.rb
index d876ac00e93..3ed531a16bc 100644
--- a/spec/mailers/emails/service_desk_spec.rb
+++ b/spec/mailers/emails/service_desk_spec.rb
@@ -625,5 +625,10 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let(:error_identifier) { 'read_timeout' }
let(:expected_text) { 'Read timeout' }
end
+
+ it_behaves_like 'a custom email verification process result email with error' do
+ let(:error_identifier) { 'incorrect_forwarding_target' }
+ let(:expected_text) { 'Incorrect forwarding target' }
+ end
end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 0f786489245..05e3bffbeaf 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -738,6 +738,24 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
end
end
+ describe '#repository_storages_with_default_weight' do
+ context 'with no extra storage set-up in the config file', fips_mode: false do
+ it 'keeps existing key restrictions' do
+ expect(setting.repository_storages_with_default_weight).to eq({ 'default' => 100 })
+ end
+ end
+
+ context 'with extra storage set-up in the config file', fips_mode: false do
+ before do
+ stub_storage_settings({ 'default' => {}, 'custom' => {} })
+ end
+
+ it 'keeps existing key restrictions' do
+ expect(setting.repository_storages_with_default_weight).to eq({ 'default' => 100, 'custom' => 0 })
+ end
+ end
+ end
+
describe 'setting validated as `addressable_url` configured with external URI' do
before do
# Use any property that has the `addressable_url` validation.
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index 8e3b97e55f3..0ed6f058768 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -1355,6 +1355,30 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
end
end
+ describe '#sync_npm_metadata_cache' do
+ let_it_be(:package) { create(:npm_package) }
+
+ subject { package.sync_npm_metadata_cache }
+
+ it 'enqueues a sync worker job' do
+ expect(::Packages::Npm::CreateMetadataCacheWorker)
+ .to receive(:perform_async).with(package.project_id, package.name)
+
+ subject
+ end
+
+ context 'with a non npm package' do
+ let_it_be(:package) { create(:maven_package) }
+
+ it 'does not enqueue a sync worker job' do
+ expect(::Packages::Npm::CreateMetadataCacheWorker)
+ .not_to receive(:perform_async)
+
+ subject
+ end
+ end
+ end
+
describe '#mark_package_files_for_destruction' do
let_it_be(:package) { create(:npm_package, :pending_destruction) }
diff --git a/spec/requests/acme_challenges_controller_spec.rb b/spec/requests/acme_challenges_controller_spec.rb
new file mode 100644
index 00000000000..f37aefed488
--- /dev/null
+++ b/spec/requests/acme_challenges_controller_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe AcmeChallengesController, type: :request, feature_category: :pages do
+ it_behaves_like 'Base action controller' do
+ subject(:request) { get acme_challenge_path }
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb b/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb
index d0980a2b43d..084958be1fb 100644
--- a/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb
@@ -38,6 +38,26 @@ RSpec.describe 'Destroying multiple packages', feature_category: :package_regist
end
it_behaves_like 'returning response status', :success
+
+ context 'when npm package' do
+ let_it_be_with_reload(:packages1) { create_list(:npm_package, 3, project: project1, name: 'test-package-1') }
+ let_it_be_with_reload(:packages2) { create_list(:npm_package, 2, project: project2, name: 'test-package-2') }
+
+ it 'enqueues the worker to sync a metadata cache' do
+ arguments = []
+
+ expect(Packages::Npm::CreateMetadataCacheWorker)
+ .to receive(:bulk_perform_async_with_contexts).and_wrap_original do |original_method, *args|
+ packages = args.first
+ arguments = packages.map(&args.second[:arguments_proc]).uniq
+ original_method.call(*args)
+ end
+
+ mutation_request
+
+ expect(arguments).to contain_exactly([project1.id, 'test-package-1'], [project2.id, 'test-package-2'])
+ end
+ end
end
shared_examples 'denying the mutation request' do
diff --git a/spec/requests/api/graphql/mutations/packages/destroy_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
index 86167e7116f..6e0e5bd8aae 100644
--- a/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
@@ -35,6 +35,17 @@ RSpec.describe 'Destroying a package', feature_category: :package_registry do
.to change { ::Packages::Package.pending_destruction.count }.by(1)
end
+ context 'when npm package' do
+ let_it_be_with_reload(:package) { create(:npm_package) }
+
+ it 'enqueues the worker to sync a metadata cache' do
+ expect(Packages::Npm::CreateMetadataCacheWorker)
+ .to receive(:perform_async).with(project.id, package.name)
+
+ mutation_request
+ end
+ end
+
it_behaves_like 'returning response status', :success
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 46fc61c80d8..c304ae514a6 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -8,6 +8,12 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
let_it_be(:admin) { create(:admin) }
describe "GET /application/settings" do
+ before do
+ # Testing config file config/gitlab.yml becomes SSOT for this API
+ # see https://gitlab.com/gitlab-org/gitlab/-/issues/426091#note_1675160909
+ stub_storage_settings({ 'default' => {}, 'custom' => {} })
+ end
+
it "returns application settings" do
get api("/application/settings", admin)
@@ -15,7 +21,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
expect(json_response).to be_an Hash
expect(json_response['default_projects_limit']).to eq(42)
expect(json_response['password_authentication_enabled_for_web']).to be_truthy
- expect(json_response['repository_storages_weighted']).to eq({ 'default' => 100 })
+ expect(json_response['repository_storages_weighted']).to eq({ 'default' => 100, 'custom' => 0 })
expect(json_response['password_authentication_enabled']).to be_truthy
expect(json_response['plantuml_enabled']).to be_falsey
expect(json_response['plantuml_url']).to be_nil
@@ -109,7 +115,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
}
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['repository_storages_weighted']).to eq({ 'custom' => 75 })
+ expect(json_response['repository_storages_weighted']).to eq({ 'default' => 0, 'custom' => 75 })
end
context "repository_storages_weighted value is outside a 0-100 range" do
@@ -131,7 +137,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
default_projects_limit: 3,
default_project_creation: 2,
password_authentication_enabled_for_web: false,
- repository_storages_weighted: { 'custom' => 100 },
+ repository_storages_weighted: { 'default' => 100, 'custom' => 0 },
plantuml_enabled: true,
plantuml_url: 'http://plantuml.example.com',
diagramsnet_enabled: false,
@@ -214,7 +220,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
expect(json_response['default_projects_limit']).to eq(3)
expect(json_response['default_project_creation']).to eq(::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
expect(json_response['password_authentication_enabled_for_web']).to be_falsey
- expect(json_response['repository_storages_weighted']).to eq({ 'custom' => 100 })
+ expect(json_response['repository_storages_weighted']).to eq({ 'default' => 100, 'custom' => 0 })
expect(json_response['plantuml_enabled']).to be_truthy
expect(json_response['plantuml_url']).to eq('http://plantuml.example.com')
expect(json_response['diagramsnet_enabled']).to be_falsey
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index b63ea71efe6..86c4e04ef71 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -182,6 +182,7 @@ RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile
expect(json_response.first).not_to have_key('note')
expect(json_response.first).not_to have_key('namespace_id')
expect(json_response.first).not_to have_key('created_by')
+ expect(json_response.first).not_to have_key('email_reset_offered_at')
end
end
@@ -194,6 +195,7 @@ RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile
expect(json_response.first).not_to have_key('note')
expect(json_response.first).not_to have_key('namespace_id')
expect(json_response.first).not_to have_key('created_by')
+ expect(json_response.first).not_to have_key('email_reset_offered_at')
end
end
@@ -203,6 +205,7 @@ RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile
expect(response).to have_gitlab_http_status(:success)
expect(json_response.first).to have_key('note')
+ expect(json_response.first).to have_key('email_reset_offered_at')
expect(json_response.first['note']).to eq '2018-11-05 | 2FA removed | user requested | www.gitlab.com'
end
diff --git a/spec/requests/application_controller_spec.rb b/spec/requests/application_controller_spec.rb
new file mode 100644
index 00000000000..52fdf6bc69e
--- /dev/null
+++ b/spec/requests/application_controller_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ApplicationController, type: :request, feature_category: :shared do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it_behaves_like 'Base action controller' do
+ subject(:request) { get root_path }
+ end
+end
diff --git a/spec/requests/chaos_controller_spec.rb b/spec/requests/chaos_controller_spec.rb
new file mode 100644
index 00000000000..d2ce618b041
--- /dev/null
+++ b/spec/requests/chaos_controller_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ChaosController, type: :request, feature_category: :tooling do
+ it_behaves_like 'Base action controller' do
+ before do
+ # Stub leak_mem so we don't actually leak memory for the base action controller tests.
+ allow(Gitlab::Chaos).to receive(:leak_mem).with(100, 30.seconds)
+ end
+
+ subject(:request) { get leakmem_chaos_path }
+ end
+end
diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb
deleted file mode 100644
index 3ce7e33d88a..00000000000
--- a/spec/requests/content_security_policy_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-# The AnonymousController doesn't support setting the CSP
-# This is why an arbitrary test request was chosen instead
-# of testing in application_controller_spec.
-RSpec.describe 'Content Security Policy', feature_category: :application_instrumentation do
- let(:snowplow_host) { 'snowplow.example.com' }
- let(:vite_origin) { "#{ViteRuby.instance.config.host}:#{ViteRuby.instance.config.port}" }
-
- shared_examples 'snowplow is not in the CSP' do
- it 'does not add the snowplow collector hostname to the CSP' do
- get explore_root_url
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers['Content-Security-Policy']).not_to include(snowplow_host)
- end
- end
-
- describe 'GET #explore' do
- context 'snowplow is enabled' do
- before do
- stub_application_setting(snowplow_enabled: true, snowplow_collector_hostname: snowplow_host)
- end
-
- it 'adds the snowplow collector hostname to the CSP' do
- get explore_root_url
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers['Content-Security-Policy']).to include(snowplow_host)
- end
- end
-
- context 'snowplow is enabled but host is not configured' do
- before do
- stub_application_setting(snowplow_enabled: true)
- end
-
- it_behaves_like 'snowplow is not in the CSP'
- end
-
- context 'snowplow is disabled' do
- before do
- stub_application_setting(snowplow_enabled: false, snowplow_collector_hostname: snowplow_host)
- end
-
- it_behaves_like 'snowplow is not in the CSP'
- end
-
- context 'when vite enabled during development',
- quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424334' do
- before do
- stub_rails_env('development')
- stub_feature_flags(vite: true)
-
- get explore_root_url
- end
-
- it 'adds vite csp' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers['Content-Security-Policy']).to include(vite_origin)
- end
- end
-
- context 'when vite disabled' do
- before do
- stub_feature_flags(vite: false)
-
- get explore_root_url
- end
-
- it "doesn't add vite csp" do
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers['Content-Security-Policy']).not_to include(vite_origin)
- end
- end
- end
-end
diff --git a/spec/requests/health_controller_spec.rb b/spec/requests/health_controller_spec.rb
index 639f6194af9..5fb2115aac3 100644
--- a/spec/requests/health_controller_spec.rb
+++ b/spec/requests/health_controller_spec.rb
@@ -73,7 +73,9 @@ RSpec.describe HealthController, feature_category: :database do
end
describe 'GET /-/readiness' do
- subject { get '/-/readiness', params: params, headers: headers }
+ subject(:request) { get readiness_path, params: params, headers: headers }
+
+ it_behaves_like 'Base action controller'
shared_context 'endpoint responding with readiness data' do
context 'when requesting instance-checks' do
@@ -219,7 +221,6 @@ RSpec.describe HealthController, feature_category: :database do
stub_remote_addr(whitelisted_ip)
end
- it_behaves_like 'endpoint not querying database'
it_behaves_like 'endpoint responding with readiness data'
context 'when requesting all checks' do
@@ -236,7 +237,6 @@ RSpec.describe HealthController, feature_category: :database do
stub_remote_addr(not_whitelisted_ip)
end
- it_behaves_like 'endpoint not querying database'
it_behaves_like 'endpoint not found'
end
@@ -273,7 +273,6 @@ RSpec.describe HealthController, feature_category: :database do
stub_remote_addr(whitelisted_ip)
end
- it_behaves_like 'endpoint not querying database'
it_behaves_like 'endpoint responding with liveness data'
end
@@ -282,7 +281,6 @@ RSpec.describe HealthController, feature_category: :database do
stub_remote_addr(not_whitelisted_ip)
end
- it_behaves_like 'endpoint not querying database'
it_behaves_like 'endpoint not found'
context 'accessed with valid token' do
diff --git a/spec/requests/metrics_controller_spec.rb b/spec/requests/metrics_controller_spec.rb
new file mode 100644
index 00000000000..ce96906e020
--- /dev/null
+++ b/spec/requests/metrics_controller_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MetricsController, type: :request, feature_category: :metrics do
+ it_behaves_like 'Base action controller' do
+ subject(:request) { get metrics_path }
+ end
+end
diff --git a/spec/requests/oauth/authorizations_controller_spec.rb b/spec/requests/oauth/authorizations_controller_spec.rb
index 257f238d9ef..7887bf52542 100644
--- a/spec/requests/oauth/authorizations_controller_spec.rb
+++ b/spec/requests/oauth/authorizations_controller_spec.rb
@@ -20,6 +20,10 @@ RSpec.describe Oauth::AuthorizationsController, feature_category: :system_access
end
describe 'GET #new' do
+ it_behaves_like 'Base action controller' do
+ subject(:request) { get oauth_authorization_path }
+ end
+
context 'when application redirect URI has a custom scheme' do
context 'when CSP is disabled' do
before do
diff --git a/spec/requests/registrations_controller_spec.rb b/spec/requests/registrations_controller_spec.rb
index 8b857046a4d..71f2f347f0d 100644
--- a/spec/requests/registrations_controller_spec.rb
+++ b/spec/requests/registrations_controller_spec.rb
@@ -6,7 +6,9 @@ RSpec.describe RegistrationsController, type: :request, feature_category: :syste
describe 'POST #create' do
let_it_be(:user_attrs) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) }
- subject(:create_user) { post user_registration_path, params: { user: user_attrs } }
+ subject(:request) { post user_registration_path, params: { user: user_attrs } }
+
+ it_behaves_like 'Base action controller'
context 'when email confirmation is required' do
before do
@@ -15,7 +17,7 @@ RSpec.describe RegistrationsController, type: :request, feature_category: :syste
end
it 'redirects to the `users_almost_there_path`', unless: Gitlab.ee? do
- create_user
+ request
expect(response).to redirect_to(users_almost_there_path(email: user_attrs[:email]))
end
diff --git a/spec/requests/sessions_spec.rb b/spec/requests/sessions_spec.rb
index 12939acdd91..337f358d394 100644
--- a/spec/requests/sessions_spec.rb
+++ b/spec/requests/sessions_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe 'Sessions', feature_category: :system_access do
let(:user) { create(:user) }
+ it_behaves_like 'Base action controller' do
+ subject(:request) { get new_user_session_path }
+ end
+
context 'for authentication', :allow_forgery_protection do
it 'logout does not require a csrf token' do
login_as(user)
diff --git a/spec/services/packages/mark_package_for_destruction_service_spec.rb b/spec/services/packages/mark_package_for_destruction_service_spec.rb
index d65e62b84a6..bd69f995c77 100644
--- a/spec/services/packages/mark_package_for_destruction_service_spec.rb
+++ b/spec/services/packages/mark_package_for_destruction_service_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe Packages::MarkPackageForDestructionService, feature_category: :pa
context 'when it is successful' do
it 'marks the package and package files as pending destruction' do
expect(package).to receive(:sync_maven_metadata).and_call_original
+ expect(package).to receive(:sync_npm_metadata_cache).and_call_original
expect(package).to receive(:mark_package_files_for_destruction).and_call_original
expect { service.execute }.to change { package.status }.from('default').to('pending_destruction')
end
@@ -45,6 +46,7 @@ RSpec.describe Packages::MarkPackageForDestructionService, feature_category: :pa
response = service.execute
expect(package).not_to receive(:sync_maven_metadata)
+ expect(package).not_to receive(:sync_npm_metadata_cache)
expect(response).to be_a(ServiceResponse)
expect(response).to be_error
expect(response.message).to eq("Failed to mark the package as pending destruction")
diff --git a/spec/services/packages/mark_packages_for_destruction_service_spec.rb b/spec/services/packages/mark_packages_for_destruction_service_spec.rb
index 22278f9927d..cd6426d39ad 100644
--- a/spec/services/packages/mark_packages_for_destruction_service_spec.rb
+++ b/spec/services/packages/mark_packages_for_destruction_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
- let_it_be_with_reload(:packages) { create_list(:npm_package, 3, project: project) }
+ let_it_be_with_reload(:packages) { create_list(:nuget_package, 3, project: project) }
let(:user) { project.owner }
@@ -15,6 +15,17 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, fea
describe '#execute' do
subject { service.execute }
+ shared_examples 'returning service response' do |status:, message:, reason: nil|
+ it 'returns service response' do
+ subject
+
+ expect(subject).to be_a(ServiceResponse)
+ expect(subject.status).to eq(status)
+ expect(subject.message).to eq(message)
+ expect(subject.reason).to eq(reason) if reason
+ end
+ end
+
context 'when the user is authorized' do
before do
project.add_maintainer(user)
@@ -23,16 +34,16 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, fea
context 'when it is successful' do
it 'marks the packages as pending destruction' do
expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)
+ expect(::Packages::Npm::CreateMetadataCacheService).not_to receive(:new)
expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
.and change { Packages::PackageFile.pending_destruction.count }.from(0).to(3)
packages.each { |pkg| expect(pkg.reload).to be_pending_destruction }
-
- expect(subject).to be_a(ServiceResponse)
- expect(subject).to be_success
- expect(subject.message).to eq('Packages were successfully marked as pending destruction')
end
+ it_behaves_like 'returning service response', status: :success,
+ message: 'Packages were successfully marked as pending destruction'
+
context 'with maven packages' do
let_it_be_with_reload(:packages) { create_list(:maven_package, 3, project: project) }
@@ -42,12 +53,11 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, fea
expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
.and change { Packages::PackageFile.pending_destruction.count }.from(0).to(9)
packages.each { |pkg| expect(pkg.reload).to be_pending_destruction }
-
- expect(subject).to be_a(ServiceResponse)
- expect(subject).to be_success
- expect(subject.message).to eq('Packages were successfully marked as pending destruction')
end
+ it_behaves_like 'returning service response', status: :success,
+ message: 'Packages were successfully marked as pending destruction'
+
context 'without version' do
before do
::Packages::Package.id_in(package_ids).update_all(version: nil)
@@ -59,12 +69,26 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, fea
expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
.and change { Packages::PackageFile.pending_destruction.count }.from(0).to(9)
packages.each { |pkg| expect(pkg.reload).to be_pending_destruction }
-
- expect(subject).to be_a(ServiceResponse)
- expect(subject).to be_success
- expect(subject.message).to eq('Packages were successfully marked as pending destruction')
end
+
+ it_behaves_like 'returning service response', status: :success,
+ message: 'Packages were successfully marked as pending destruction'
+ end
+ end
+
+ context 'with npm packages' do
+ let_it_be_with_reload(:packages) { create_list(:npm_package, 3, project: project, name: 'test-package') }
+
+ it 'marks the packages as pending destruction' do
+ expect(::Packages::Npm::CreateMetadataCacheService).to receive(:new).once.and_call_original
+
+ expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
+ .and change { Packages::PackageFile.pending_destruction.count }.from(0).to(3)
+ packages.each { |package| expect(package.reload).to be_pending_destruction }
end
+
+ it_behaves_like 'returning service response', status: :success,
+ message: 'Packages were successfully marked as pending destruction'
end
end
@@ -73,7 +97,7 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, fea
allow(service).to receive(:can_destroy_packages?).and_raise(StandardError, 'test')
end
- it 'returns an error ServiceResponse' do
+ it 'does not mark the packages as pending destruction' do
expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
@@ -83,30 +107,25 @@ RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, fea
expect { subject }.to not_change { ::Packages::Package.pending_destruction.count }
.and not_change { ::Packages::PackageFile.pending_destruction.count }
-
- expect(subject).to be_a(ServiceResponse)
- expect(subject).to be_error
- expect(subject.message).to eq("Failed to mark the packages as pending destruction")
- expect(subject.status).to eq(:error)
end
+
+ it_behaves_like 'returning service response', status: :error,
+ message: 'Failed to mark the packages as pending destruction'
end
end
context 'when the user is not authorized' do
let(:user) { nil }
- it 'returns an error ServiceResponse' do
+ it 'does not mark the packages as pending destruction' do
expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)
expect { subject }.to not_change { ::Packages::Package.pending_destruction.count }
.and not_change { ::Packages::PackageFile.pending_destruction.count }
-
- expect(subject).to be_a(ServiceResponse)
- expect(subject).to be_error
- expect(subject.message).to eq("You don't have the permission to perform this action")
- expect(subject.status).to eq(:error)
- expect(subject.reason).to eq(:unauthorized)
end
+
+ it_behaves_like 'returning service response', status: :error, reason: :unauthorized,
+ message: "You don't have the permission to perform this action"
end
end
end
diff --git a/spec/services/service_desk/custom_email_verifications/update_service_spec.rb b/spec/services/service_desk/custom_email_verifications/update_service_spec.rb
index 9a51f645b4d..103caf0e6c5 100644
--- a/spec/services/service_desk/custom_email_verifications/update_service_spec.rb
+++ b/spec/services/service_desk/custom_email_verifications/update_service_spec.rb
@@ -27,6 +27,9 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
before do
allow(message_delivery).to receive(:deliver_later)
allow(Notify).to receive(:service_desk_verification_result_email).and_return(message_delivery)
+
+ stub_incoming_email_setting(enabled: true, address: 'support+%{key}@example.com')
+ stub_service_desk_email_setting(enabled: true, address: 'contact+%{key}@example.com')
end
shared_examples 'a failing verification process' do |expected_error_identifier|
@@ -118,7 +121,34 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
verification.update!(token: 'ZROT4ZZXA-Y6') # token from email fixture
end
- let(:email_raw) { email_fixture('emails/service_desk_custom_email_address_verification.eml') }
+ let(:service_desk_address) { project.service_desk_incoming_address }
+ let(:verification_address) { 'custom-support-email+verify@example.com' }
+ let(:verification_token) { 'ZROT4ZZXA-Y6' }
+ let(:shared_email_raw) do
+ <<~EMAIL
+ From: Flight Support <custom-support-email@example.com>
+ Subject: Verify custom email address custom-support-email@example.com for Flight
+ Auto-Submitted: no
+
+
+ This email is auto-generated. It verifies the ownership of the entered Service Desk custom email address and
+ correct functionality of email forwarding.
+
+ Verification token: #{verification_token}
+ --
+
+ You're receiving this email because of your account on 127.0.0.1.
+ EMAIL
+ end
+
+ let(:email_raw) do
+ <<~EMAIL
+ Delivered-To: #{service_desk_address}
+ To: #{verification_address}
+ #{shared_email_raw}
+ EMAIL
+ end
+
let(:mail_object) { Mail::Message.new(email_raw) }
it 'verifies and sends result emails' do
@@ -160,6 +190,38 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it_behaves_like 'a failing verification process', 'mail_not_received_within_timeframe'
end
+ context 'and service desk address from service_desk_email was used as forwarding target' do
+ let(:service_desk_address) { project.service_desk_alias_address }
+
+ it_behaves_like 'a failing verification process', 'incorrect_forwarding_target'
+
+ context 'when multiple Delivered-To headers are present' do
+ let(:email_raw) do
+ <<~EMAIL
+ Delivered-To: other@example.com
+ Delivered-To: #{service_desk_address}
+ To: #{verification_address}
+ #{shared_email_raw}
+ EMAIL
+ end
+
+ it_behaves_like 'a failing verification process', 'incorrect_forwarding_target'
+ end
+
+ context 'when multiple To headers are present' do
+ # Microsoft Exchange forwards emails this way when forwarding
+ # to an external email address using a transport rule
+ let(:email_raw) do
+ <<~EMAIL
+ To: #{service_desk_address}, #{verification_address}
+ #{shared_email_raw}
+ EMAIL
+ end
+
+ it_behaves_like 'a failing verification process', 'incorrect_forwarding_target'
+ end
+ end
+
context 'when already verified' do
let(:expected_error_message) { error_already_finished }
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index d6fa1d60dad..fe84a80dae6 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -8148,7 +8148,6 @@
- './spec/requests/api/users_spec.rb'
- './spec/requests/api/wikis_spec.rb'
- './spec/requests/concerns/planning_hierarchy_spec.rb'
-- './spec/requests/content_security_policy_spec.rb'
- './spec/requests/dashboard_controller_spec.rb'
- './spec/requests/dashboard/projects_controller_spec.rb'
- './spec/requests/git_http_spec.rb'
diff --git a/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb b/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb
new file mode 100644
index 00000000000..2eab533ef7f
--- /dev/null
+++ b/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+# Requires `request` subject to be defined
+#
+# subject(:request) { get root_path }
+RSpec.shared_examples 'Base action controller' do
+ describe 'security headers' do
+ describe 'Cross-Security-Policy' do
+ context 'when configuring snowplow' do
+ let(:snowplow_host) { 'snowplow.example.com' }
+
+ shared_examples 'snowplow is not in the CSP' do
+ it 'does not add the snowplow collector hostname to the CSP' do
+ request
+
+ expect(response.headers['Content-Security-Policy']).not_to include(snowplow_host)
+ end
+ end
+
+ context 'when snowplow is enabled' do
+ before do
+ stub_application_setting(snowplow_enabled: true, snowplow_collector_hostname: snowplow_host)
+ end
+
+ it 'adds snowplow to the csp' do
+ request
+
+ expect(response.headers['Content-Security-Policy']).to include(snowplow_host)
+ end
+ end
+
+ context 'when snowplow is enabled but host is not configured' do
+ before do
+ stub_application_setting(snowplow_enabled: true, snowplow_collector_hostname: nil)
+ end
+
+ it_behaves_like 'snowplow is not in the CSP'
+ end
+
+ context 'when snowplow is disabled' do
+ before do
+ stub_application_setting(snowplow_enabled: false, snowplow_collector_hostname: snowplow_host)
+ end
+
+ it_behaves_like 'snowplow is not in the CSP'
+ end
+ end
+
+ context 'when configuring vite' do
+ let(:vite_origin) { "#{ViteRuby.instance.config.host}:#{ViteRuby.instance.config.port}" }
+
+ context 'when vite enabled during development',
+ skip: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424334' do
+ before do
+ stub_rails_env('development')
+ stub_feature_flags(vite: true)
+ end
+
+ it 'adds vite csp' do
+ request
+
+ expect(response.headers['Content-Security-Policy']).to include(vite_origin)
+ end
+ end
+
+ context 'when vite disabled' do
+ before do
+ stub_feature_flags(vite: false)
+ end
+
+ it "doesn't add vite csp" do
+ request
+
+ expect(response.headers['Content-Security-Policy']).not_to include(vite_origin)
+ end
+ end
+ end
+ end
+ end
+end