Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-03-10 15:11:00 +00:00
parent 5103041796
commit ad2d90fb24
82 changed files with 1294 additions and 454 deletions

View File

@ -1,14 +1,59 @@
.preflight-job-base:
stage: preflight
extends:
- .default-retry
needs: []
.qa-preflight-job:
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}
extends:
- .preflight-job-base
- .qa-cache
variables:
USE_BUNDLE_INSTALL: "false"
SETUP_DB: "false"
before_script:
- !reference [.default-before_script, before_script]
- cd qa && bundle install
rails-production-environment:
extends:
- .preflight-job-base
- .default-before_script
- .production
- .ruby-cache
- .setup:rules:rails-production-environment
- .use-pg12
stage: preflight
variables:
BUNDLE_WITHOUT: "development:test"
BUNDLE_WITH: "production"
needs: []
script:
- bundle exec rails runner --environment=production 'puts Rails.env'
no-ee-check:
extends:
- .preflight-job-base
- .setup:rules:no-ee-check
script:
- scripts/no-dir-check ee
no-jh-check:
extends:
- .preflight-job-base
- .setup:rules:no-jh-check
script:
- scripts/no-dir-check jh
qa:selectors:
extends:
- .qa-preflight-job
- .qa:rules:ee-and-foss
script:
- bundle exec bin/qa Test::Sanity::Selectors
qa:selectors-as-if-foss:
extends:
- qa:selectors
- .qa:rules:as-if-foss
- .as-if-foss

View File

@ -25,13 +25,6 @@ qa:internal-as-if-foss:
- .qa:rules:internal-as-if-foss
- .as-if-foss
qa:selectors:
extends:
- .qa-job-base
- .qa:rules:ee-and-foss
script:
- bundle exec bin/qa Test::Sanity::Selectors
qa:master-auto-quarantine-dequarantine:
extends:
- .qa-job-base
@ -50,12 +43,6 @@ qa:nightly-auto-quarantine-dequarantine:
- bundle exec confiner -r .confiner/nightly.yml
allow_failure: true
qa:selectors-as-if-foss:
extends:
- qa:selectors
- .qa:rules:as-if-foss
- .as-if-foss
qa:update-qa-cache:
extends:
- .qa-job-base

View File

@ -51,22 +51,6 @@ gitlab_git_test:
script:
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
no-ee-check:
extends:
- .predictive-job
- .setup:rules:no-ee-check
stage: test
script:
- scripts/no-dir-check ee
no-jh-check:
extends:
- .predictive-job
- .setup:rules:no-jh-check
stage: test
script:
- scripts/no-dir-check jh
verify-ruby-3.0:
extends:
- .absolutely-predictive-job

View File

@ -459,12 +459,20 @@ export default {
@sort="handleSort"
>
<template #nav-actions>
<gl-button :href="rssPath" icon="rss">
{{ $options.i18n.rssLabel }}
</gl-button>
<gl-button :href="calendarPath" icon="calendar">
{{ $options.i18n.calendarLabel }}
</gl-button>
<gl-button
v-gl-tooltip
:href="rssPath"
icon="rss"
:title="$options.i18n.rssLabel"
class="has-tooltip btn-icon"
/>
<gl-button
v-gl-tooltip
:href="calendarPath"
icon="calendar"
:title="$options.i18n.calendarLabel"
class="has-tooltip btn-icon"
/>
</template>
<template #timeframe="{ issuable = {} }">

View File

@ -207,6 +207,10 @@ export default {
emailConfirmationSettingsOffHelpText: s__(
'ApplicationSettings|New users can sign up without confirming their email address.',
),
emailConfirmationSettingsSoftLabel: s__('ApplicationSettings|Soft'),
emailConfirmationSettingsSoftHelpText: s__(
'ApplicationSettings|Send a confirmation email during sign up. New users can log in immediately, but must confirm their email within three days.',
),
emailConfirmationSettingsHardLabel: s__('ApplicationSettings|Hard'),
emailConfirmationSettingsHardHelpText: s__(
'ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in.',
@ -286,16 +290,23 @@ export default {
v-model="form.emailConfirmationSetting"
name="application_setting[email_confirmation_setting]"
>
<gl-form-radio value="hard">
{{ $options.i18n.emailConfirmationSettingsHardLabel }}
<template #help> {{ $options.i18n.emailConfirmationSettingsHardHelpText }} </template>
</gl-form-radio>
<gl-form-radio value="off">
{{ $options.i18n.emailConfirmationSettingsOffLabel }}
<template #help> {{ $options.i18n.emailConfirmationSettingsOffHelpText }} </template>
</gl-form-radio>
<gl-form-radio value="soft">
{{ $options.i18n.emailConfirmationSettingsSoftLabel }}
<template #help> {{ $options.i18n.emailConfirmationSettingsSoftHelpText }} </template>
</gl-form-radio>
<gl-form-radio value="hard">
{{ $options.i18n.emailConfirmationSettingsHardLabel }}
<template #help> {{ $options.i18n.emailConfirmationSettingsHardHelpText }} </template>
</gl-form-radio>
</gl-form-radio-group>
</gl-form-group>

View File

@ -1,6 +1,6 @@
import { __ } from '~/locale';
// TODO: Remove in favor of https://gitlab.com/gitlab-org/gitlab/issues/35144
// https://docs.sentry.io/platforms/javascript/configuration/filtering/#decluttering-sentry
export const IGNORE_ERRORS = [
// Random plugins/extensions
'top.GLOBALS',

View File

@ -1,7 +1,7 @@
import * as Sentry5 from 'sentrybrowser5';
import $ from 'jquery';
import { __ } from '~/locale';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './legacy_constants';
const SentryConfig = {
IGNORE_ERRORS,

View File

@ -1,5 +1,4 @@
import * as Sentry from 'sentrybrowser7';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
const SentryConfig = {
init(options = {}) {
@ -17,9 +16,6 @@ const SentryConfig = {
release,
allowUrls,
environment,
ignoreErrors: IGNORE_ERRORS,
denyUrls: DENY_URLS,
sampleRate: SAMPLE_RATE,
});
Sentry.setTags(tags);

View File

@ -10,7 +10,7 @@ module ConfirmEmailWarning
protected
def show_confirm_warning?
html_request? && request.get? && Feature.enabled?(:soft_email_confirmation)
html_request? && request.get? && Gitlab::CurrentSettings.email_confirmation_setting_soft?
end
def set_confirm_warning

View File

@ -20,7 +20,7 @@ class ConfirmationsController < Devise::ConfirmationsController
protected
def after_resending_confirmation_instructions_path_for(resource)
return users_almost_there_path unless Feature.enabled?(:soft_email_confirmation)
return users_almost_there_path unless Gitlab::CurrentSettings.email_confirmation_setting_soft?
stored_location_for(resource) || dashboard_projects_path
end

View File

@ -50,7 +50,7 @@ module Registrations
def requires_confirmation?(user)
return false if user.confirmed?
return false if Feature.enabled?(:soft_email_confirmation)
return false unless Gitlab::CurrentSettings.email_confirmation_setting_hard?
true
end

View File

@ -129,9 +129,9 @@ class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
return new_user_session_path(anchor: 'login-pane') if resource.blocked_pending_approval?
return dashboard_projects_path if Feature.enabled?(:soft_email_confirmation)
return dashboard_projects_path if Gitlab::CurrentSettings.email_confirmation_setting_soft?
# when email confirmation is enabled, path to redirect is saved
# when email_confirmation_setting is set to `hard`, path to redirect is saved
# after user confirms and comes back, he will be redirected
store_location_for(:redirect, after_sign_up_path)

View File

@ -835,6 +835,33 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
false
end
# Overriding the enum check for `email_confirmation_setting` as the feature flag is being removed and is taking a
# release M, M.N+1 strategy as noted in:
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107302#note_1286005956
def email_confirmation_setting_off?
if Feature.enabled?(:soft_email_confirmation)
false
else
super
end
end
def email_confirmation_setting_soft?
if Feature.enabled?(:soft_email_confirmation)
true
else
super
end
end
def email_confirmation_setting_hard?
if Feature.enabled?(:soft_email_confirmation)
false
else
super
end
end
private
def parsed_grafana_url

View File

@ -264,6 +264,7 @@ class Project < ApplicationRecord
has_one :project_setting, inverse_of: :project, autosave: true
has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting'
has_one :service_desk_setting, class_name: 'ServiceDeskSetting'
has_one :service_desk_custom_email_verification, class_name: 'ServiceDesk::CustomEmailVerification'
# Merge requests for target project should be removed with it
has_many :merge_requests, foreign_key: 'target_project_id', inverse_of: :target_project, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
module ServiceDesk
def self.table_name_prefix
'service_desk_'
end
end

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
module ServiceDesk
class CustomEmailVerification < ApplicationRecord
enum state: {
running: 0,
verified: 1,
error: 2
}, _default: 'running'
enum error: {
incorrect_token: 0,
incorrect_from: 1,
mail_not_received_within_timeframe: 2,
invalid_credentials: 3,
smtp_host_issue: 4
}
TIMEFRAME = 30.minutes
attr_encrypted :token,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
key: Settings.attr_encrypted_db_key_base_32,
encode: false,
encode_iv: false
belongs_to :project
belongs_to :triggerer, class_name: 'User', optional: true
validates :project, presence: true
validates :state, presence: true
delegate :service_desk_setting, to: :project
class << self
def generate_token
SecureRandom.alphanumeric(12)
end
end
def accepted_until
return unless running?
return unless triggered_at.present?
TIMEFRAME.since(triggered_at)
end
def in_timeframe?
return false unless running?
!!accepted_until&.future?
end
end
end

View File

@ -3,6 +3,8 @@
class ServiceDeskSetting < ApplicationRecord
include Gitlab::Utils::StrongMemoize
CUSTOM_EMAIL_VERIFICATION_SUBADDRESS = '+verify'
attribute :custom_email_enabled, default: false
attr_encrypted :custom_email_smtp_password,
mode: :per_attribute_iv,
@ -12,6 +14,7 @@ class ServiceDeskSetting < ApplicationRecord
encode_iv: false
belongs_to :project
validates :project_id, presence: true
validate :valid_issue_template
validate :valid_project_key
@ -32,21 +35,25 @@ class ServiceDeskSetting < ApplicationRecord
validates :custom_email,
presence: true,
devise_email: true,
if: :custom_email_enabled?
if: :needs_custom_email_smtp_credentials?
validates :custom_email_smtp_address,
presence: true,
hostname: { allow_numeric_hostname: true, require_valid_tld: true },
if: :custom_email_enabled?
if: :needs_custom_email_smtp_credentials?
validates :custom_email_smtp_username,
presence: true,
if: :custom_email_enabled?
if: :needs_custom_email_smtp_credentials?
validates :custom_email_smtp_port,
presence: true,
numericality: { only_integer: true, greater_than: 0 },
if: :custom_email_enabled?
if: :needs_custom_email_smtp_credentials?
scope :with_project_key, ->(key) { where(project_key: key) }
def custom_email_verification
project&.service_desk_custom_email_verification
end
def custom_email_delivery_options
{
user_name: custom_email_smtp_username,
@ -57,6 +64,12 @@ class ServiceDeskSetting < ApplicationRecord
}
end
def custom_email_address_for_verification
return unless custom_email.present?
custom_email.sub("@", "#{CUSTOM_EMAIL_VERIFICATION_SUBADDRESS}@")
end
def issue_template_content
strong_memoize(:issue_template_content) do
next unless issue_template_key.present?
@ -102,6 +115,10 @@ class ServiceDeskSetting < ApplicationRecord
setting.project.full_path_slug == project_slug
end
end
def needs_custom_email_smtp_credentials?
custom_email_enabled? || custom_email_verification.present?
end
end
ServiceDeskSetting.prepend_mod

View File

@ -2129,7 +2129,15 @@ class User < ApplicationRecord
end
def confirmation_required_on_sign_in?
!confirmed? && !confirmation_period_valid?
return false if confirmed?
if ::Gitlab::CurrentSettings.email_confirmation_setting_off?
false
elsif ::Gitlab::CurrentSettings.email_confirmation_setting_soft?
!in_confirmation_period?
elsif ::Gitlab::CurrentSettings.email_confirmation_setting_hard?
true
end
end
def impersonated?
@ -2210,10 +2218,13 @@ class User < ApplicationRecord
# override from Devise::Confirmable
def confirmation_period_valid?
return false if Feature.disabled?(:soft_email_confirmation)
return super if ::Gitlab::CurrentSettings.email_confirmation_setting_soft?
super
# Following devise logic for method, we want to return `true`
# See: https://github.com/heartcombo/devise/blob/main/lib/devise/models/confirmable.rb#L191-L218
true
end
alias_method :in_confirmation_period?, :confirmation_period_valid?
# This is copied from Devise::Models::TwoFactorAuthenticatable#consume_otp!
#

View File

@ -33,7 +33,6 @@ module BulkImports
validate_symlink
extract_archive
remove_symlinks
tmpdir
end
@ -60,15 +59,5 @@ module BulkImports
def extract_archive
untar_xf(archive: filepath, dir: tmpdir)
end
def extracted_files
Dir.glob(File.join(tmpdir, '**', '*'))
end
def remove_symlinks
extracted_files.each do |path|
FileUtils.rm(path) if symlink?(path)
end
end
end
end

View File

@ -113,7 +113,13 @@ module Ci
end
def accessibility(params)
params[:accessibility] || 'public'
accessibility = params[:accessibility]
return :public if Feature.disabled?(:non_public_artifacts, type: :development)
return accessibility if accessibility.present?
job.artifacts_public? ? :public : :private
end
def parse_artifact(artifact)

View File

@ -38,6 +38,8 @@
= render_if_exists 'admin/application_settings/ldap_access_setting', form: f
= render_if_exists 'admin/application_settings/saml_group_locks_setting', form: f
.form-group{ data: { testid: 'project-export' } }
= f.label :project_export, s_('AdminSettings|Project export'), class: 'label-bold'
= f.gitlab_ui_checkbox_component :project_export_enabled, s_('AdminSettings|Enabled')

View File

@ -1,8 +1,8 @@
- show_calendar_button = local_assigns.fetch(:show_calendar_button, true)
= render Pajamas::ButtonComponent.new(href: safe_params.merge(rss_url_options), icon: 'rss', button_options: { class: 'has-tooltip', 'aria-label': _('Subscribe to RSS feed'), data: { container: 'body', testid: 'rss-feed-link' } }) do
= _('Subscribe to RSS feed')
= render Pajamas::ButtonComponent.new(href: safe_params.merge(rss_url_options), button_options: { class: 'has-tooltip btn-icon', title: _('Subscribe to RSS feed'), 'aria-label': _('Subscribe to RSS feed'), data: { container: 'body', testid: 'rss-feed-link' } }) do
= sprite_icon('rss')
- if show_calendar_button
= render Pajamas::ButtonComponent.new(href: safe_params.merge(calendar_url_options), icon: 'calendar', button_options: { class: 'has-tooltip', 'aria-label': _('Subscribe to calendar'), data: { container: 'body' } }) do
= _('Subscribe to calendar')
= render Pajamas::ButtonComponent.new(href: safe_params.merge(calendar_url_options), button_options: { class: 'has-tooltip btn-icon', title: _('Subscribe to calendar'), 'aria-label': _('Subscribe to calendar'), data: { container: 'body' } }) do
= sprite_icon('calendar')

View File

@ -0,0 +1,11 @@
---
table_name: service_desk_custom_email_verifications
classes:
- ServiceDesk::CustomEmailVerification
feature_categories:
- service_desk
description: Holds the verification state and additional information for custom email
addresses for Service Desk
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112938
milestone: '15.10'
gitlab_schema: gitlab_main

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class AddServiceDeskCustomEmailVerifications < Gitlab::Database::Migration[2.1]
enable_lock_retries!
def up
create_table(:service_desk_custom_email_verifications, id: false, primary_key: :project_id) do |t|
t.references :project, index: false, foreign_key: { on_delete: :cascade }, null: false
t.references :triggerer, index: true, foreign_key: { to_table: :users, on_delete: :nullify }
t.timestamps_with_timezone
t.datetime_with_timezone :triggered_at
t.integer :state, limit: 2, null: false, default: 0
t.integer :error, limit: 2
t.binary :encrypted_token
t.binary :encrypted_token_iv
end
execute "ALTER TABLE service_desk_custom_email_verifications ADD PRIMARY KEY (project_id);"
end
def down
drop_table :service_desk_custom_email_verifications
end
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddSamlGroupLockToApplicationSettings < Gitlab::Database::Migration[2.1]
def change
add_column :application_settings, :lock_memberships_to_saml, :boolean, default: false, null: false
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
class QueueDeleteOrphanedPackagesDependencies < Gitlab::Database::Migration[2.1]
restrict_gitlab_migration gitlab_schema: :gitlab_main
MIGRATION = 'DeleteOrphanedPackagesDependencies'
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 6000
SUB_BATCH_SIZE = 100
disable_ddl_transaction!
def up
queue_batched_background_migration(
MIGRATION,
:packages_dependencies,
:id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, :packages_dependencies, :id, [])
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class RecreateUserTypeMigrationIndexes < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
INCORRECT_BILLABLE_INDEX = 'index_users_for_active_billable_users_migration'
BILLABLE_INDEX = 'migrate_index_users_for_active_billable_users'
def up
# Temporary index to migrate human user_type. See https://gitlab.com/gitlab-org/gitlab/-/issues/386474
add_concurrent_index :users, :id, name: BILLABLE_INDEX,
where: "state = 'active' AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[0, 6, 4, 13]))) " \
"AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[0, 4, 5])))"
remove_concurrent_index_by_name :users, INCORRECT_BILLABLE_INDEX
end
def down
add_concurrent_index :users, :id, name: INCORRECT_BILLABLE_INDEX,
where: "state = 'active' AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[6, 4, 13]))) " \
"AND ((user_type IS NULL OR user_type = 0) OR (user_type = ANY (ARRAY[4, 5])))"
remove_concurrent_index_by_name :users, BILLABLE_INDEX
end
end

View File

@ -0,0 +1 @@
d6fdfc530a49b230aa041d4629a0484462abacb824f6bbf23d9740068e3ca781

View File

@ -0,0 +1 @@
191d7be803e9e3a2a5292bbcd562c34a67c07b73da2c429ac2f115b28d04f00c

View File

@ -0,0 +1 @@
5f2176abfc462e65c9ef2b9b28c9feb60cac868aa491d4d4207a8904deb60f18

View File

@ -0,0 +1 @@
d1accdc2bbe9aa5266df98a893176fba94148f9754d2c0b2de04e9d8d66d8eba

View File

@ -11748,6 +11748,7 @@ CREATE TABLE application_settings (
projects_api_rate_limit_unauthenticated integer DEFAULT 400 NOT NULL,
deny_all_requests_except_allowed boolean DEFAULT false NOT NULL,
product_analytics_data_collector_host text,
lock_memberships_to_saml boolean DEFAULT false NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
@ -22180,6 +22181,18 @@ CREATE TABLE serverless_domain_cluster (
certificate text
);
CREATE TABLE service_desk_custom_email_verifications (
project_id bigint NOT NULL,
triggerer_id bigint,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
triggered_at timestamp with time zone,
state smallint DEFAULT 0 NOT NULL,
error smallint,
encrypted_token bytea,
encrypted_token_iv bytea
);
CREATE TABLE service_desk_settings (
project_id bigint NOT NULL,
issue_template_key character varying(255),
@ -27610,6 +27623,9 @@ ALTER TABLE ONLY sprints
ALTER TABLE ONLY serverless_domain_cluster
ADD CONSTRAINT serverless_domain_cluster_pkey PRIMARY KEY (uuid);
ALTER TABLE ONLY service_desk_custom_email_verifications
ADD CONSTRAINT service_desk_custom_email_verifications_pkey PRIMARY KEY (project_id);
ALTER TABLE ONLY service_desk_settings
ADD CONSTRAINT service_desk_settings_pkey PRIMARY KEY (project_id);
@ -31836,6 +31852,8 @@ CREATE INDEX index_serverless_domain_cluster_on_creator_id ON serverless_domain_
CREATE INDEX index_serverless_domain_cluster_on_pages_domain_id ON serverless_domain_cluster USING btree (pages_domain_id);
CREATE INDEX index_service_desk_custom_email_verifications_on_triggerer_id ON service_desk_custom_email_verifications USING btree (triggerer_id);
CREATE INDEX index_service_desk_enabled_projects_on_id_creator_id_created_at ON projects USING btree (id, creator_id, created_at) WHERE (service_desk_enabled = true);
CREATE INDEX index_service_desk_settings_on_file_template_project_id ON service_desk_settings USING btree (file_template_project_id);
@ -32154,8 +32172,6 @@ CREATE UNIQUE INDEX index_user_synced_attributes_metadata_on_user_id ON user_syn
CREATE INDEX index_users_for_active_billable_users ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[6, 4, 13]))) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[4, 5]))));
CREATE INDEX index_users_for_active_billable_users_migration ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = ANY (ARRAY[6, 4, 13]))) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = ANY (ARRAY[4, 5]))));
CREATE INDEX index_users_on_accepted_term_id ON users USING btree (accepted_term_id);
CREATE INDEX index_users_on_admin ON users USING btree (admin);
@ -32484,6 +32500,8 @@ CREATE UNIQUE INDEX merge_request_user_mentions_on_mr_id_index ON merge_request_
CREATE INDEX merge_requests_state_id_temp_index ON merge_requests USING btree (id) WHERE (state_id = ANY (ARRAY[2, 3]));
CREATE INDEX migrate_index_users_for_active_billable_users ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = ANY (ARRAY[0, 6, 4, 13]))) AND ((user_type IS NULL) OR (user_type = 0) OR (user_type = ANY (ARRAY[0, 4, 5]))));
CREATE INDEX note_mentions_temp_index ON notes USING btree (id, noteable_type) WHERE (note ~~ '%@%'::text);
CREATE UNIQUE INDEX one_canonical_wiki_page_slug_per_metadata ON wiki_page_slugs USING btree (wiki_page_meta_id) WHERE (canonical = true);
@ -35109,6 +35127,9 @@ ALTER TABLE ONLY diff_note_positions
ALTER TABLE ONLY analytics_cycle_analytics_aggregations
ADD CONSTRAINT fk_rails_13c8374c7a FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY service_desk_custom_email_verifications
ADD CONSTRAINT fk_rails_14dcaf4c92 FOREIGN KEY (triggerer_id) REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE ONLY namespaces_storage_limit_exclusions
ADD CONSTRAINT fk_rails_14e8f7b0e0 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@ -36462,6 +36483,9 @@ ALTER TABLE ONLY dast_scanner_profiles_tags
ALTER TABLE ONLY vulnerability_feedback
ADD CONSTRAINT fk_rails_debd54e456 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY service_desk_custom_email_verifications
ADD CONSTRAINT fk_rails_debe4c4acc FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY packages_debian_project_distributions
ADD CONSTRAINT fk_rails_df44271a30 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE RESTRICT;

View File

@ -165,6 +165,7 @@ It does not cover all data types.
| LFS objects (using Git) | **{check-circle}** Yes |
| Pages | **{dotted-circle}** No <sup>2</sup> |
| Advanced search (using the web UI) | **{dotted-circle}** No |
| Container registry | **{dotted-circle}** No |
1. Git reads are served from the local secondary while pushes get proxied to the primary.
Selective sync or cases where repositories don't exist locally on the Geo secondary throw a "not found" error.

View File

@ -8,6 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Keep your GitLab instance up and running smoothly.
- [Upgrading GitLab](../../update/index.md).
- [Rake tasks](../../raketasks/index.md): Tasks for common administration and operational processes such as
[cleaning up unneeded items from GitLab instance](../../raketasks/cleanup.md), integrity checks,
and more.

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Pods
group: Tenant Scale
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -155,7 +155,7 @@ or a [CI/CD job token](../ci/jobs/ci_job_token.md) for authentication.
With a CI/CD job token, the [triggered pipeline is a multi-project pipeline](../ci/pipelines/downstream_pipelines.md#trigger-a-multi-project-pipeline-by-using-the-api).
The job that authenticates the request becomes associated with the upstream pipeline,
which is visible on the [pipeline graph](../ci/pipelines/downstream_pipelines.md#view-multi-project-pipelines-in-pipeline-graphs).
which is visible on the pipeline graph.
If you use a trigger token in a job, the job is not associated with the upstream pipeline.

View File

@ -315,18 +315,32 @@ trigger_pipeline:
> Hover behavior for pipeline cards [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/197140/) in GitLab 13.2.
In the [pipeline graph view](index.md#view-full-pipeline-graph), downstream pipelines display
as a list of cards on the right of the graph. Hover over the pipeline's card to view
which job triggered the downstream pipeline.
as a list of cards on the right of the graph. From this view, you can:
### Retry a downstream pipeline
- Select a trigger job to see the triggered downstream pipeline's jobs.
- Select **Expand jobs** **{chevron-lg-right}** on a pipeline card to expand the view
with the downstream pipeline's jobs. You can view one downstream pipeline at a time.
- Hover over a pipeline card to have the job that triggered the downstream pipeline highlighted.
### Retry failed and canceled jobs in a downstream pipeline
> - Retry from graph view [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354974) in GitLab 15.0 [with a flag](../../administration/feature_flags.md) named `downstream_retry_action`. Disabled by default.
> - Retry from graph view [generally available and feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/357406) in GitLab 15.1.
To retry a completed downstream pipeline, select **Retry** (**{retry}**):
To retry failed and canceled jobs, select **Retry** (**{retry}**):
- From the downstream pipeline's details page.
- On the pipeline's card in the [pipeline graph view](index.md#view-full-pipeline-graph).
- On the pipeline's card in the pipeline graph view.
### Recreate a downstream pipeline
> Retry trigger job from graph view [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367547) in GitLab 15.10 [with a flag](../../administration/feature_flags.md) named `ci_recreate_downstream_pipeline`. Disabled by default.
You can recreate a downstream pipeline by retrying its corresponding trigger job. The newly created downstream pipeline replaces the current downstream pipeline in the pipeline graph.
To recreate a downstream pipeline:
- Select **Run again** (**{retry}**) on the trigger job's card in the pipeline graph view.
### Cancel a downstream pipeline
@ -336,7 +350,7 @@ To retry a completed downstream pipeline, select **Retry** (**{retry}**):
To cancel a downstream pipeline that is still running, select **Cancel** (**{cancel}**):
- From the downstream pipeline's details page.
- On the pipeline's card in the [pipeline graph view](index.md#view-full-pipeline-graph).
- On the pipeline's card in the pipeline graph view.
### Mirror the status of a downstream pipeline in the trigger job
@ -371,13 +385,9 @@ trigger_job:
After you trigger a multi-project pipeline, the downstream pipeline displays
to the right of the [pipeline graph](index.md#visualize-pipelines).
![Multi-project pipeline graph](img/multi_project_pipeline_graph_v14_3.png)
In [pipeline mini graphs](index.md#pipeline-mini-graphs), the downstream pipeline
displays to the right of the mini graph.
![Multi-project pipeline mini graph](img/pipeline_mini_graph_v15_0.png)
## Fetch artifacts from an upstream pipeline
Use [`needs:project`](../yaml/index.md#needsproject) to fetch artifacts from an

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -423,8 +423,7 @@ You can group the jobs by:
- [Job dependencies](#view-job-dependencies-in-the-pipeline-graph), which arranges
jobs based on their [`needs`](../yaml/index.md#needs) dependencies.
[Multi-project pipeline graphs](downstream_pipelines.md#view-multi-project-pipelines-in-pipeline-graphs) help
you visualize the entire pipeline, including all cross-project inter-dependencies.
Multi-project pipeline graphs help you visualize the entire pipeline, including all cross-project inter-dependencies.
If a stage contains more than 100 jobs, only the first 100 jobs are listed in the
pipeline graph. The remaining jobs still run as usual. To see the jobs:

View File

@ -961,10 +961,8 @@ job:
#### `artifacts:public`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49775) in GitLab 13.8
> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
> - It's disabled on GitLab.com.
> - It's recommended for production use.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223273) in GitLab 13.8 [with a flag](../../user/feature_flags.md) named `non_public_artifacts`, disabled by default.
> - [Updated](https://gitlab.com/gitlab-org/gitlab/-/issues/322454) in GitLab 15.10. Artifacts created with `artifacts:public` before 15.10 are not guaranteed to remain private after this update.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available,

View File

@ -30,7 +30,9 @@ We were using Overcommit prior to Lefthook, so you may want to uninstall it firs
### Install Lefthook
1. Install the `lefthook` Ruby gem:
1. You can install lefthook in [different ways](https://github.com/evilmartians/lefthook/blob/master/docs/install.md#install-lefthook).
If you do not choose to install it globally (e.g. via Homebrew or package managers), and only want to use it for the GitLab project,
you can install the Ruby gem via:
```shell
bundle install
@ -39,12 +41,18 @@ We were using Overcommit prior to Lefthook, so you may want to uninstall it firs
1. Install Lefthook managed Git hooks:
```shell
# If installed globally
lefthook install
# Or if installed via ruby gem
bundle exec lefthook install
```
1. Test Lefthook is working by running the Lefthook `pre-push` Git hook:
```shell
# If installed globally
lefthook run pre-push
# Or if installed via ruby gem
bundle exec lefthook run pre-push
```
@ -57,6 +65,18 @@ Lefthook is configured with a combination of:
- Project configuration in [`lefthook.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lefthook.yml).
- Any [local configuration](https://github.com/evilmartians/lefthook/blob/master/README.md#local-config).
### Lefthook auto-fixing files
We have a custom lefthook target to run all the linters with auto-fix capabilities,
but just on the files which changed in your branch.
```shell
# If installed globally
lefthook run auto-fix
# Or if installed via ruby gem
bundle exec lefthook run auto-fix
```
### Disable Lefthook temporarily
To disable Lefthook temporarily, you can set the `LEFTHOOK` environment variable to `0`. For instance:

View File

@ -1,6 +1,6 @@
---
stage: Data Stores
group: Pods
group: Tenant Scale
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -60,6 +60,8 @@ This means that new dependencies should, at a minimum, meet the following criter
- There are no issues open that we know may impact the availability or performance of GitLab.
- The project is tested using some form of test automation. The test suite must be passing
using the Ruby version currently used by GitLab.
- CI builds for all supported platforms must succeed using the new dependency. For more information, see
how to [build a package for testing](build_test_package.md#building-a-package-for-testing).
- If the project uses a C extension, consider requesting an additional review from a C or MRI
domain expert. C extensions can greatly impact GitLab stability and performance.

View File

@ -662,6 +662,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
- Generally, you want to use at least a 2-node cluster configuration with one replica, which allows you to have resilience. If your storage usage is growing quickly, you may want to plan horizontal scaling (adding more nodes) beforehand.
- It's not recommended to use HDD storage with the search cluster, because it takes a hit on performance. It's better to use SSD storage (NVMe or SATA SSD drives for example).
- You should not use [coordinating-only nodes](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#coordinating-only-node) with large instances. Coordinating-only nodes are smaller than [data nodes](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#data-node), which can impact performance and advanced search migrations.
- You can use the [GitLab Performance Tool](https://gitlab.com/gitlab-org/quality/performance) to benchmark search performance with different search cluster sizes and configurations.
- `Heap size` should be set to no more than 50% of your physical RAM. Additionally, it shouldn't be set to more than the threshold for zero-based compressed oops. The exact threshold varies, but 26 GB is safe on most systems, but can also be as large as 30 GB on some systems. See [Heap size settings](https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#heap-size-settings) and [Setting JVM options](https://www.elastic.co/guide/en/elasticsearch/reference/current/jvm-options.html) for more details.
- Number of CPUs (CPU cores) per node usually corresponds to the `Number of Elasticsearch shards` setting described below.

View File

@ -196,11 +196,11 @@ accordingly, while also consulting the
NOTE:
When not explicitly specified, upgrade GitLab to the latest available patch
release rather than the first patch release, for example `13.8.8` instead of `13.8.0`.
This includes versions you must stop at on the upgrade path as there may
release of the `major`.`minor` release rather than the first patch release, for example `13.8.8` instead of `13.8.0`.
This includes `major`.`minor` versions you must stop at on the upgrade path as there may
be fixes for issues relating to the upgrade process.
Specifically around a [major version](#upgrading-to-a-new-major-version),
crucial database schema and migration patches are included in the latest patch releases.
crucial database schema and migration patches may be included in the latest patch releases.
## Upgrading between editions
@ -237,7 +237,7 @@ possible.
## Version-specific upgrading instructions
Each month, major, minor, or patch releases of GitLab are published along with a
Each month, major or minor as well as possibly patch releases of GitLab are published along with a
[release post](https://about.gitlab.com/releases/categories/releases/).
You should read the release posts for all versions you're passing over.
At the end of major and minor release posts, there are three sections to look for specifically:
@ -267,7 +267,6 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### 15.9.0
- There is a [database migration bug in GitLab 15.9.x](#user-profile-data-loss-bug-in-159x) that can cause data to be lost from the user profile fields. This bug affects all currently available 15.9.x releases. Until a bug fix is released, you should upgrade to 15.6.x, 15.7.x, or 15.8.x first.
- This version removes `SanitizeConfidentialTodos` background migration [added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87908/diffs) in 15.6, which removed any user inaccessible to-do items. Make sure that this migration is finished before upgrading to 15.9.
- As part of the [CI Partitioning effort](../architecture/blueprints/ci_data_decay/pipeline_partitioning.md), a [new Foreign Key](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107547) was added to `ci_builds_needs`. On GitLab instances with large CI tables, adding this constraint can take longer than usual. Make sure that this migration is finished before upgrading to 15.9.
- Praefect's metadata verifier's [invalid metadata deletion behavior](../administration/gitaly/praefect.md#enable-deletions) is now enabled by default.

View File

@ -51,17 +51,26 @@ signing up using OmniAuth or LDAP, set `block_auto_created_users` to `true` in t
[OmniAuth configuration](../../../integration/omniauth.md#configure-common-settings) or
[LDAP configuration](../../../administration/auth/ldap/index.md#basic-configuration-settings).
## Require email confirmation
## Confirm user email
> - Soft email confirmation [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47003) in GitLab 12.2 [with a flag](../../../operations/feature_flags.md) named `soft_email_confirmation`.
> - Soft email confirmation [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107302/diffs) from a feature flag to an application setting in GitLab 15.9.
You can send confirmation emails during sign up and require that users confirm
their email address before they are allowed to sign in.
To enforce confirmation of the email address used for new sign ups:
For example, to enforce confirmation of the email address used for new sign ups:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
1. Under **Email confirmation settings**, select **Hard**.
The following settings are available:
- **Hard** - Send a confirmation email during sign up. New users must confirm their email address before they can log in.
- **Soft** - Send a confirmation email during sign up. New users can log in immediately, but must confirm their email in three days. Unconfirmed accounts are deleted.
- **Off** - New users can sign up without confirming their email address.
## User cap
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4315) in GitLab 13.7.
@ -95,22 +104,6 @@ New user sign ups are subject to the user cap restriction.
New users sign ups are not subject to the user cap restriction. Users in pending approval state are
automatically approved in a background job.
## Soft email confirmation
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47003) in GitLab 12.2.
> - It's [deployed behind a feature flag](../../../user/feature_flags.md), disabled by default.
> - It's enabled on GitLab.com.
> - It's recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-soft-email-confirmation).
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
The soft email confirmation improves the sign-up experience for new users by allowing
them to sign in without an immediate confirmation when an email confirmation is required.
GitLab shows the user a reminder to confirm their email address, and the user can't
create or update pipelines until their email address is confirmed.
## Minimum password length limit
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20661) in GitLab 12.6
@ -171,25 +164,6 @@ semicolon, comma, or a new line.
![Domain Denylist](img/domain_denylist_v14_1.png)
### Enable or disable soft email confirmation
Soft email confirmation is under development but ready for production use.
It is deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to disable it.
To enable it:
```ruby
Feature.enable(:soft_email_confirmation)
```
To disable it:
```ruby
Feature.disable(:soft_email_confirmation)
```
## Set up LDAP user filter
You can limit GitLab access to a subset of the LDAP users on your LDAP server.

View File

@ -106,6 +106,30 @@ Users granted:
SAML group membership is evaluated each time a user signs in.
### Global SAML group memberships lock **(PREMIUM SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386390) in GitLab 15.10.
GitLab administrators can use the global SAML group memberships lock to prevent group members from inviting new members to subgroups that have their membership synchronized with SAML Group Links.
Global group memberships lock only applies to subgroups of a top-level group where SAML Group Links synchronization is configured. No user can modify the
membership of a top-level group configured for SAML Group Links synchronization.
When global group memberships lock is enabled:
- Only an administrator can manage memberships of any group including access levels.
- Users cannot:
- Share a project with other groups.
- Invite members to a project created in a group.
To enable global group memberships lock:
1. [Configure SAML](../../../integration/saml.md) for your self-managed GitLab instance.
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Ensure the **Lock memberships to SAML synchronization** checkbox is selected.
### Automatic member removal
After a group sync, users who are not members of a mapped SAML group are removed from the group.

View File

@ -266,19 +266,28 @@ The GitLab npm repository supports the following commands for the npm CLI (`npm`
### `404 Not Found` errors are happening on `npm install` or `yarn`
Using `CI_JOB_TOKEN` to install npm packages with dependencies in another project gives you 404 Not Found errors. A fix for this problem is proposed in [issue 352962](https://gitlab.com/gitlab-org/gitlab/-/issues/352962).
Using `CI_JOB_TOKEN` to install npm packages with dependencies in another project gives you 404 Not Found errors. You need to authenticate with a token that has access to the package and all its dependencies.
As a workaround, you can:
If the package and its dependencies are in separate projects but in the same group, you can use a
[group deploy token](../../project/deploy_tokens/index.md#create-a-deploy-token):
1. Create a [personal access token](../../profile/personal_access_tokens.md).
1. Authenticate at both the instance level and project level for each package:
```ini
//gitlab.example.com/api/v4/packages/npm/:_authToken=<group-token>
@group-scope:registry=https://gitlab.example.com/api/v4/packages/npm/
```
```ini
@foo:registry=https://gitlab.example.com/api/v4/packages/npm/
//gitlab.example.com/api/v4/packages/npm/:_authToken=${MY_TOKEN}
//gitlab.example.com/api/v4/projects/<your_project_id_a>/packages/npm/:_authToken=${MY_TOKEN}
//gitlab.example.com/api/v4/projects/<your_project_id_b>/packages/npm/:_authToken=${MY_TOKEN}
```
If the package and its dependencies are spread across multiple groups, you can use a [personal access token](../../profile/personal_access_tokens.md)
from a user that has access to all the groups or individual projects:
```ini
//gitlab.example.com/api/v4/packages/npm/:_authToken=<personal-access-token>
@group-1:registry=https://gitlab.example.com/api/v4/packages/npm/
@group-2:registry=https://gitlab.example.com/api/v4/packages/npm/
```
WARNING:
Personal access tokens must be treated carefully. Read our [token security considerations](../../../security/token_overview.md#security-considerations)
for guidance on managing personal access tokens (for example, setting a short expiry and using minimal scopes).
### `npm publish` targets default npm registry (`registry.npmjs.org`)

View File

@ -55,6 +55,8 @@ Advanced search uses [Elasticsearch syntax](https://www.elastic.co/guide/en/elas
### Refining user search
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388409) in GitLab 15.10.
In user search, a [fuzzy query](https://www.elastic.co/guide/en/elasticsearch/reference/7.2/query-dsl-fuzzy-query.html) is used by default. You can refine your search with [Elasticsearch syntax](#syntax).
### Code search

View File

@ -96,6 +96,7 @@ pre-push:
"merge_conflicts":
skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md#skip
runner: bash
pre-commit:
parallel: true
commands:
@ -103,3 +104,27 @@ pre-commit:
tags: secrets
files: git diff --name-only --diff-filter=d --staged
run: 'if command -v gitleaks > /dev/null 2>&1; then gitleaks protect --no-banner --staged --redact --verbose; else echo "WARNING: gitleaks is not installed. Please install it. See https://github.com/zricethezav/gitleaks#installing."; fi'
auto-fix:
parallel: true
commands:
frontend:
tags: frontend style
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: '*.{js,vue}'
run: 'yarn run lint:eslint:fix {files} && yarn run prettier --write --list-different {files}'
jsonlint:
tags: style
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: '*.{json}'
run: scripts/lint-json --format --verbose {files}
prettier-graphql:
tags: frontend style
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: '*.{graphql}'
run: yarn run prettier --write --list-different {files}
rubocop:
tags: backend style
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
glob: '*.{rb,rake}'
run: REVEAL_RUBOCOP_TODO=0 bundle exec rubocop --parallel --autocorrect --force-exclusion {files}

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Deletes orphaned packages_dependencies records that have no packages_dependency_links
class DeleteOrphanedPackagesDependencies < BatchedMigrationJob
operation_name :delete_all
feature_category :package_registry
scope_to ->(relation) {
relation.where(
<<~SQL.squish
NOT EXISTS (
SELECT 1
FROM packages_dependency_links
WHERE packages_dependency_links.dependency_id = packages_dependencies.id
)
SQL
)
}
def perform
each_sub_batch(&:delete_all)
end
end
end
end

View File

@ -90,6 +90,7 @@ module Gitlab
def untar_with_options(archive:, dir:, options:)
execute_cmd(%W(tar -#{options} #{archive} -C #{dir}))
execute_cmd(%W(chmod -R #{UNTAR_MASK} #{dir}))
remove_symlinks(dir)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
@ -120,6 +121,19 @@ module Gitlab
FileUtils.copy_entry(source, destination)
true
end
def remove_symlinks(dir)
ignore_file_names = %w[. ..]
# Using File::FNM_DOTMATCH to also delete symlinks starting with "."
Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH)
.reject { |f| ignore_file_names.include?(File.basename(f)) }
.each do |filepath|
FileUtils.rm(filepath) if File.lstat(filepath).symlink?
end
true
end
end
end
end

View File

@ -8,7 +8,6 @@ module Gitlab
ImporterError = Class.new(StandardError)
MAX_RETRIES = 8
IGNORED_FILENAMES = %w(. ..).freeze
def self.import(*args, **kwargs)
new(*args, **kwargs).import
@ -24,7 +23,7 @@ module Gitlab
mkdir_p(@shared.export_path)
mkdir_p(@shared.archive_path)
remove_symlinks
remove_symlinks(@shared.export_path)
copy_archive
wait_for_archived_file do
@ -36,7 +35,7 @@ module Gitlab
false
ensure
remove_import_file
remove_symlinks
remove_symlinks(@shared.export_path)
end
private
@ -86,22 +85,10 @@ module Gitlab
end
end
def remove_symlinks
extracted_files.each do |path|
FileUtils.rm(path) if File.lstat(path).symlink?
end
true
end
def remove_import_file
FileUtils.rm_rf(@archive_file)
end
def extracted_files
Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| IGNORED_FILENAMES.include?(File.basename(f)) }
end
def validate_decompressed_archive_size
raise ImporterError, _('Decompressed archive size validation failed.') unless size_validator.valid?
end

View File

@ -5099,12 +5099,18 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr ""
msgid "ApplicationSettings|Send a confirmation email during sign up. New users can log in immediately, but must confirm their email within three days."
msgstr ""
msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
msgstr ""
msgid "ApplicationSettings|Sign-up enabled"
msgstr ""
msgid "ApplicationSettings|Soft"
msgstr ""
msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
msgstr ""
@ -8716,12 +8722,6 @@ msgstr ""
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to confirm your order! Please try again."
msgstr ""
msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
msgstr ""
msgid "Checkout|Failed to load countries. Please try again."
msgstr ""
@ -19488,6 +19488,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
msgid "Global SAML group membership lock"
msgstr ""
msgid "Global Search is disabled for this scope"
msgstr ""
@ -21557,6 +21560,9 @@ msgstr ""
msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
msgstr ""
msgid "If checked, new group memberships and permissions can only be added via SAML Group Links synchronization"
msgstr ""
msgid "If disabled, a diverged local branch will not be automatically updated with commits from its remote counterpart, to prevent local data loss. If the default branch (%{default_branch}) has diverged and cannot be updated, mirroring will fail. Other diverged branches are silently ignored. %{link_start}Learn more.%{link_end}"
msgstr ""
@ -25902,6 +25908,9 @@ msgstr ""
msgid "Lock memberships to LDAP synchronization"
msgstr ""
msgid "Lock memberships to SAML Group Links synchronization"
msgstr ""
msgid "Lock merge request"
msgstr ""
@ -37891,6 +37900,9 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
msgid "SAML group membership settings"
msgstr ""
msgid "SAML single sign-on"
msgstr ""
@ -38930,6 +38942,9 @@ msgstr ""
msgid "SecurityOrchestration|No rules defined - policy will not run."
msgstr ""
msgid "SecurityOrchestration|No tags available"
msgstr ""
msgid "SecurityOrchestration|Non-existing tags have been detected in the policy yaml. As a result, rule mode has been disabled. To enable rule mode, remove those non-existing tags from the policy yaml."
msgstr ""
@ -39023,7 +39038,7 @@ msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr ""
msgid "SecurityOrchestration|Scan will automatically choose a runner to run on because there are no tags exist on runners"
msgid "SecurityOrchestration|Scan will automatically choose a runner to run on because there are no tags exist on runners. You can %{linkStart}create a new tag in settings%{linkEnd}."
msgstr ""
msgid "SecurityOrchestration|Security Approvals"

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe ConfirmEmailWarning do
before do
stub_feature_flags(soft_email_confirmation: true)
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
controller(ApplicationController) do

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe ConfirmationsController do
RSpec.describe ConfirmationsController, feature_category: :system_access do
include DeviseHelpers
before do
@ -148,51 +148,69 @@ RSpec.describe ConfirmationsController do
end
end
context 'when reCAPTCHA is disabled' do
context "when `email_confirmation_setting` is set to `soft`" do
before do
stub_application_setting(recaptcha_enabled: false)
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
it 'successfully sends password reset when reCAPTCHA is not solved' do
perform_request
context 'when reCAPTCHA is disabled' do
before do
stub_application_setting(recaptcha_enabled: false)
end
expect(response).to redirect_to(dashboard_projects_path)
it 'successfully sends password reset when reCAPTCHA is not solved' do
perform_request
expect(response).to redirect_to(dashboard_projects_path)
end
end
context 'when reCAPTCHA is enabled' do
before do
stub_application_setting(recaptcha_enabled: true)
end
context 'when the reCAPTCHA is not solved' do
before do
Recaptcha.configuration.skip_verify_env.delete('test')
end
it 'displays an error' do
perform_request
expect(response).to render_template(:new)
expect(flash[:alert]).to include _('There was an error with the reCAPTCHA.')
end
it 'sets gon variables' do
Gon.clear
perform_request
expect(response).to render_template(:new)
expect(Gon.all_variables).not_to be_empty
end
end
it 'successfully sends password reset when reCAPTCHA is solved' do
Recaptcha.configuration.skip_verify_env << 'test'
perform_request
expect(response).to redirect_to(dashboard_projects_path)
end
end
end
context 'when reCAPTCHA is enabled' do
context "when `email_confirmation_setting` is not set to `soft`" do
before do
stub_application_setting(recaptcha_enabled: true)
stub_feature_flags(soft_email_confirmation: false)
end
context 'when the reCAPTCHA is not solved' do
before do
Recaptcha.configuration.skip_verify_env.delete('test')
end
it 'displays an error' do
perform_request
expect(response).to render_template(:new)
expect(flash[:alert]).to include _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
end
it 'sets gon variables' do
Gon.clear
perform_request
expect(response).to render_template(:new)
expect(Gon.all_variables).not_to be_empty
end
end
it 'successfully sends password reset when reCAPTCHA is solved' do
Recaptcha.configuration.skip_verify_env << 'test'
it 'redirects to the users_almost_there path' do
perform_request
expect(response).to redirect_to(dashboard_projects_path)
expect(response).to redirect_to(users_almost_there_path)
end
end
end

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe OmniauthCallbacksController, type: :controller do
RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: :system_access do
include LoginHelpers
describe 'omniauth' do
@ -202,20 +202,30 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
end
end
context 'when user with 2FA is unconfirmed' do
context 'when a user has 2FA enabled' do
render_views
let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider) }
before do
user.update_column(:confirmed_at, nil)
context 'when a user is unconfirmed' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
user.update!(confirmed_at: nil)
end
it 'redirects to login page' do
post provider
expect(response).to redirect_to(new_user_session_path)
expect(flash[:alert]).to match(/You have to confirm your email address before continuing./)
end
end
it 'redirects to login page' do
post provider
expect(response).to redirect_to(new_user_session_path)
expect(flash[:alert]).to match(/You have to confirm your email address before continuing./)
context 'when a user is confirmed' do
it 'returns 200 response' do
expect(response).to have_gitlab_http_status(:ok)
end
end
end

View File

@ -57,6 +57,32 @@ RSpec.describe Registrations::WelcomeController, feature_category: :system_acces
expect(subject).not_to redirect_to(profile_two_factor_auth_path)
end
end
context 'when welcome step is completed' do
before do
user.update!(setup_for_company: true)
end
context 'when user is confirmed' do
before do
sign_in(user)
end
it { is_expected.to redirect_to dashboard_projects_path }
end
context 'when user is not confirmed' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
sign_in(user)
user.update!(confirmed_at: nil)
end
it { is_expected.to redirect_to user_session_path }
end
end
end
describe '#update' do

View File

@ -75,7 +75,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
context 'email confirmation' do
context 'when `email_confirmation_setting` is set to `hard`' do
context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
@ -122,7 +122,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
context 'email confirmation' do
context 'when `email_confirmation_setting` is set to `hard`' do
context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
stub_feature_flags(identity_verification: false)
@ -157,7 +157,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
stub_feature_flags(identity_verification: false)
end
context 'when `email_confirmation_setting` is set to `off`' do
context 'when email confirmation setting is set to `off`' do
it 'signs the user in' do
stub_application_setting_enum('email_confirmation_setting', 'off')
@ -166,103 +166,97 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
context 'when `email_confirmation_setting` is set to `hard`' do
context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
end
context 'when soft email confirmation is not enabled' do
before do
stub_feature_flags(soft_email_confirmation: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
end
it 'does not authenticate the user and sends a confirmation email' do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_nil
end
it 'does not authenticate the user and sends a confirmation email' do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_nil
end
it 'tracks an almost there redirect' do
post_create
it 'tracks an almost there redirect' do
post_create
expect_snowplow_event(
category: described_class.name,
action: 'render',
user: User.find_by(email: base_user_params[:email])
)
end
expect_snowplow_event(
category: described_class.name,
action: 'render',
user: User.find_by(email: base_user_params[:email])
)
end
context 'when registration is triggered from an accepted invite' do
context 'when it is part from the initial invite email', :snowplow do
let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) }
context 'when registration is triggered from an accepted invite' do
context 'when it is part from the initial invite email', :snowplow do
let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) }
let(:originating_member_id) { member.id }
let(:session_params) do
{
invite_email: user_params.dig(:user, :email),
originating_member_id: originating_member_id
}
end
let(:originating_member_id) { member.id }
let(:session_params) do
{
invite_email: user_params.dig(:user, :email),
originating_member_id: originating_member_id
}
end
context 'when member exists from the session key value' do
it 'tracks the invite acceptance' do
subject
context 'when member exists from the session key value' do
it 'tracks the invite acceptance' do
subject
expect_snowplow_event(
category: 'RegistrationsController',
action: 'accepted',
label: 'invite_email',
property: member.id.to_s,
user: member.reload.user
)
expect_snowplow_event(
category: 'RegistrationsController',
action: 'accepted',
label: 'invite_email',
property: member.id.to_s,
user: member.reload.user
)
expect_snowplow_event(
category: 'RegistrationsController',
action: 'create_user',
label: 'invited',
user: member.reload.user
)
end
end
context 'when member does not exist from the session key value' do
let(:originating_member_id) { nil }
it 'does not track invite acceptance' do
subject
expect_no_snowplow_event(
category: 'RegistrationsController',
action: 'accepted',
label: 'invite_email'
)
expect_snowplow_event(
category: 'RegistrationsController',
action: 'create_user',
label: 'signup',
user: member.reload.user
)
end
expect_snowplow_event(
category: 'RegistrationsController',
action: 'create_user',
label: 'invited',
user: member.reload.user
)
end
end
context 'when invite email matches email used on registration' do
let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
context 'when member does not exist from the session key value' do
let(:originating_member_id) { nil }
it 'signs the user in without sending a confirmation email', :aggregate_failures do
expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_confirmed
it 'does not track invite acceptance' do
subject
expect_no_snowplow_event(
category: 'RegistrationsController',
action: 'accepted',
label: 'invite_email'
)
expect_snowplow_event(
category: 'RegistrationsController',
action: 'create_user',
label: 'signup',
user: member.reload.user
)
end
end
end
context 'when invite email does not match the email used on registration' do
let(:session_params) { { invite_email: 'bogus@email.com' } }
context 'when invite email matches email used on registration' do
let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_nil
end
it 'signs the user in without sending a confirmation email', :aggregate_failures do
expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_confirmed
end
end
context 'when invite email does not match the email used on registration' do
let(:session_params) { { invite_email: 'bogus@email.com' } }
it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_nil
end
end
end
@ -286,45 +280,45 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
expect(controller.current_user).to be_nil
end
end
end
context 'when soft email confirmation is enabled' do
before do
stub_feature_flags(soft_email_confirmation: true)
allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
context 'when email confirmation setting is set to `soft`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
end
it 'authenticates the user and sends a confirmation email' do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_present
expect(response).to redirect_to(users_sign_up_welcome_path)
end
it 'does not track an almost there redirect' do
post_create
expect_no_snowplow_event(
category: described_class.name,
action: 'render',
user: User.find_by(email: base_user_params[:email])
)
end
context 'when invite email matches email used on registration' do
let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
it 'signs the user in without sending a confirmation email', :aggregate_failures do
expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_confirmed
end
end
it 'authenticates the user and sends a confirmation email' do
context 'when invite email does not match the email used on registration' do
let(:session_params) { { invite_email: 'bogus@email.com' } }
it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_present
expect(response).to redirect_to(users_sign_up_welcome_path)
end
it 'does not track an almost there redirect' do
post_create
expect_no_snowplow_event(
category: described_class.name,
action: 'render',
user: User.find_by(email: base_user_params[:email])
)
end
context 'when invite email matches email used on registration' do
let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
it 'signs the user in without sending a confirmation email', :aggregate_failures do
expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_confirmed
end
end
context 'when invite email does not match the email used on registration' do
let(:session_params) { { invite_email: 'bogus@email.com' } }
it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).not_to be_confirmed
end
expect(controller.current_user).not_to be_confirmed
end
end
end

View File

@ -694,7 +694,7 @@ FactoryBot.define do
end
end
trait :non_public_artifacts do
trait :with_private_artifacts_config do
options do
{
artifacts: { public: false }
@ -702,6 +702,14 @@ FactoryBot.define do
end
end
trait :with_public_artifacts_config do
options do
{
artifacts: { public: true }
}
end
end
trait :non_playable do
status { 'created' }
self.when { 'manual' }

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
FactoryBot.define do
factory :service_desk_custom_email_verification, class: '::ServiceDesk::CustomEmailVerification' do
project
state { "running" }
end
end

View File

@ -244,9 +244,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
context 'the user sign-up using a different email address' do
let(:invite_email) { build_stubbed(:user).email }
context 'when soft email confirmation is not enabled' do
context 'when email confirmation is not set to `soft`' do
before do
stub_feature_flags(soft_email_confirmation: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
stub_feature_flags(identity_verification: false)
end
@ -261,9 +260,9 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
context 'when soft email confirmation is enabled' do
context 'when email confirmation setting is set to `soft`' do
before do
stub_feature_flags(soft_email_confirmation: true)
stub_application_setting_enum('email_confirmation_setting', 'soft')
allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
end

View File

@ -109,6 +109,10 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'within the grace period' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
it 'allows to login' do
expect(authentication_metrics).to increment(:user_authenticated_counter)
@ -137,11 +141,9 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when resending the confirmation email' do
let_it_be(:user) { create(:user) }
it 'redirects to the "almost there" page' do
stub_feature_flags(soft_email_confirmation: false)
user = create(:user)
visit new_user_confirmation_path
fill_in 'user_email', with: user.email
click_button 'Resend'
@ -971,8 +973,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
stub_feature_flags(soft_email_confirmation: true)
stub_application_setting_enum('email_confirmation_setting', 'soft')
stub_feature_flags(identity_verification: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
end

View File

@ -200,9 +200,8 @@ RSpec.describe 'Signup', feature_category: :user_profile do
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
context 'when soft email confirmation is not enabled' do
context 'when email confirmation setting is not `soft`' do
before do
stub_feature_flags(soft_email_confirmation: false)
stub_feature_flags(identity_verification: false)
end
@ -221,9 +220,9 @@ RSpec.describe 'Signup', feature_category: :user_profile do
end
end
context 'when soft email confirmation is enabled' do
context 'when email confirmation setting is `soft`' do
before do
stub_feature_flags(soft_email_confirmation: true)
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
it 'creates the user account and sends a confirmation email' do

View File

@ -1,5 +1,4 @@
import * as Sentry from 'sentrybrowser7';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from '~/sentry/constants';
import SentryConfig from '~/sentry/sentry_config';
@ -62,11 +61,8 @@ describe('SentryConfig', () => {
expect(Sentry.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
sampleRate: SAMPLE_RATE,
allowUrls: options.allowUrls,
environment: options.environment,
ignoreErrors: IGNORE_ERRORS,
denyUrls: DENY_URLS,
});
});
@ -82,11 +78,8 @@ describe('SentryConfig', () => {
expect(Sentry.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
sampleRate: SAMPLE_RATE,
allowUrls: options.allowUrls,
environment: 'development',
ignoreErrors: IGNORE_ERRORS,
denyUrls: DENY_URLS,
});
});
});

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DeleteOrphanedPackagesDependencies, schema: 20230303105806,
feature_category: :package_registry do
let!(:migration_attrs) do
{
start_id: 1,
end_id: 1000,
batch_table: :packages_dependencies,
batch_column: :id,
sub_batch_size: 500,
pause_ms: 0,
connection: ApplicationRecord.connection
}
end
let!(:migration) { described_class.new(**migration_attrs) }
let(:packages_dependencies) { table(:packages_dependencies) }
let!(:namespace) { table(:namespaces).create!(name: 'project', path: 'project', type: 'Project') }
let!(:project) do
table(:projects).create!(name: 'project', path: 'project', project_namespace_id: namespace.id,
namespace_id: namespace.id)
end
let!(:package) do
table(:packages_packages).create!(name: 'test', version: '1.2.3', package_type: 2, project_id: project.id)
end
let!(:orphan_dependency_1) { packages_dependencies.create!(name: 'dependency 1', version_pattern: '~0.0.1') }
let!(:orphan_dependency_2) { packages_dependencies.create!(name: 'dependency 2', version_pattern: '~0.0.2') }
let!(:orphan_dependency_3) { packages_dependencies.create!(name: 'dependency 3', version_pattern: '~0.0.3') }
let!(:linked_dependency) do
packages_dependencies.create!(name: 'dependency 4', version_pattern: '~0.0.4').tap do |dependency|
table(:packages_dependency_links).create!(package_id: package.id, dependency_id: dependency.id,
dependency_type: 'dependencies')
end
end
subject(:perform_migration) { migration.perform }
it 'executes 3 queries' do
queries = ActiveRecord::QueryRecorder.new do
perform_migration
end
expect(queries.count).to eq(3)
end
it 'deletes only orphaned dependencies' do
expect { perform_migration }.to change { packages_dependencies.count }.by(-3)
expect(packages_dependencies.all).to eq([linked_dependency])
end
end

View File

@ -722,6 +722,7 @@ project:
- upstream_project_subscriptions
- downstream_project_subscriptions
- service_desk_setting
- service_desk_custom_email_verification
- security_setting
- import_failures
- container_expiration_policy
@ -963,6 +964,8 @@ bulk_import_export:
- group
service_desk_setting:
- file_template_project
service_desk_custom_email_verification:
- triggerer
approvals:
- user
- merge_request

View File

@ -2,13 +2,14 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::CommandLineUtil do
RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importers do
include ExportFileHelper
let(:path) { "#{Dir.tmpdir}/symlink_test" }
let(:archive) { 'spec/fixtures/symlink_export.tar.gz' }
let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
let(:tmpdir) { Dir.mktmpdir }
let(:archive_dir) { Dir.mktmpdir }
subject do
Class.new do
@ -25,20 +26,38 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
before do
FileUtils.mkdir_p(path)
subject.untar_zxf(archive: archive, dir: path)
end
after do
FileUtils.rm_rf(path)
FileUtils.rm_rf(archive_dir)
FileUtils.remove_entry(tmpdir)
end
it 'has the right mask for project.json' do
expect(file_permissions("#{path}/project.json")).to eq(0755) # originally 777
end
shared_examples 'deletes symlinks' do |compression, decompression|
it 'deletes the symlinks', :aggregate_failures do
Dir.mkdir("#{tmpdir}/.git")
Dir.mkdir("#{tmpdir}/folder")
FileUtils.touch("#{tmpdir}/file.txt")
FileUtils.touch("#{tmpdir}/folder/file.txt")
FileUtils.touch("#{tmpdir}/.gitignore")
FileUtils.touch("#{tmpdir}/.git/config")
File.symlink('file.txt', "#{tmpdir}/.symlink")
File.symlink('file.txt', "#{tmpdir}/.git/.symlink")
File.symlink('file.txt', "#{tmpdir}/folder/.symlink")
archive = File.join(archive_dir, 'archive')
subject.public_send(compression, archive: archive, dir: tmpdir)
it 'has the right mask for uploads' do
expect(file_permissions("#{path}/uploads")).to eq(0755) # originally 555
subject.public_send(decompression, archive: archive, dir: archive_dir)
expect(File.exist?("#{archive_dir}/file.txt")).to eq(true)
expect(File.exist?("#{archive_dir}/folder/file.txt")).to eq(true)
expect(File.exist?("#{archive_dir}/.gitignore")).to eq(true)
expect(File.exist?("#{archive_dir}/.git/config")).to eq(true)
expect(File.exist?("#{archive_dir}/.symlink")).to eq(false)
expect(File.exist?("#{archive_dir}/.git/.symlink")).to eq(false)
expect(File.exist?("#{archive_dir}/folder/.symlink")).to eq(false)
end
end
describe '#download_or_copy_upload' do
@ -228,12 +247,6 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
end
describe '#tar_cf' do
let(:archive_dir) { Dir.mktmpdir }
after do
FileUtils.remove_entry(archive_dir)
end
it 'archives a folder without compression' do
archive_file = File.join(archive_dir, 'archive.tar')
@ -256,13 +269,25 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
end
end
describe '#untar_xf' do
let(:archive_dir) { Dir.mktmpdir }
describe '#untar_zxf' do
it_behaves_like 'deletes symlinks', :tar_czf, :untar_zxf
after do
FileUtils.remove_entry(archive_dir)
it 'has the right mask for project.json' do
subject.untar_zxf(archive: archive, dir: path)
expect(file_permissions("#{path}/project.json")).to eq(0755) # originally 777
end
it 'has the right mask for uploads' do
subject.untar_zxf(archive: archive, dir: path)
expect(file_permissions("#{path}/uploads")).to eq(0755) # originally 555
end
end
describe '#untar_xf' do
it_behaves_like 'deletes symlinks', :tar_cf, :untar_xf
it 'extracts archive without decompression' do
filename = 'archive.tar.gz'
archive_file = File.join(archive_dir, 'archive.tar')

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe QueueDeleteOrphanedPackagesDependencies, feature_category: :package_registry do
let!(:batched_migration) { described_class::MIGRATION }
it 'schedules a new batched migration' do
reversible_migration do |migration|
migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration
}
migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration(
table_name: :packages_dependencies,
column_name: :id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE
)
}
end
end
end

View File

@ -1525,4 +1525,50 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
expect(setting.personal_access_tokens_disabled?).to eq(false)
end
end
describe 'email_confirmation_setting prefixes' do
before do
described_class.create_from_defaults
end
context 'when feature flag `soft_email_confirmation` is not enabled' do
before do
stub_feature_flags(soft_email_confirmation: false)
end
where(:email_confirmation_setting, :off, :soft, :hard) do
'off' | true | false | false
'soft' | false | true | false
'hard' | false | false | true
end
with_them do
it 'returns the correct value when prefixed' do
stub_application_setting_enum('email_confirmation_setting', email_confirmation_setting)
expect(described_class.last.email_confirmation_setting_off?).to be off
expect(described_class.last.email_confirmation_setting_soft?).to be soft
expect(described_class.last.email_confirmation_setting_hard?).to be hard
end
end
it 'calls super' do
expect(described_class.last.email_confirmation_setting_off?).to be true
expect(described_class.last.email_confirmation_setting_soft?).to be false
expect(described_class.last.email_confirmation_setting_hard?).to be false
end
end
context 'when feature flag `soft_email_confirmation` is enabled' do
before do
stub_feature_flags(soft_email_confirmation: true)
end
it 'returns correct value when enum is prefixed' do
expect(described_class.last.email_confirmation_setting_off?).to be false
expect(described_class.last.email_confirmation_setting_soft?).to be true
expect(described_class.last.email_confirmation_setting_hard?).to be false
end
end
end
end

View File

@ -1040,7 +1040,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
context 'non public artifacts' do
let(:build) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
it { is_expected.to be_falsey }
end

View File

@ -89,6 +89,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
it { is_expected.to have_one(:alerting_setting).class_name('Alerting::ProjectAlertingSetting') }
it { is_expected.to have_one(:mock_ci_integration) }
it { is_expected.to have_one(:mock_monitoring_integration) }
it { is_expected.to have_one(:service_desk_custom_email_verification).class_name('ServiceDesk::CustomEmailVerification') }
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:ci_pipelines) }
it { is_expected.to have_many(:ci_refs) }

View File

@ -0,0 +1,109 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ServiceDesk::CustomEmailVerification, feature_category: :service_desk do
let(:user) { build_stubbed(:user) }
let(:project) { build_stubbed(:project) }
let(:verification) { build_stubbed(:service_desk_custom_email_verification, project: project) }
let(:token) { 'XXXXXXXXXXXX' }
describe '.generate_token' do
it 'matches expected output' do
expect(described_class.generate_token).to match(/\A\p{Alnum}{12}\z/)
end
end
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:state) }
end
describe '#accepted_until' do
context 'when no custom email is set up' do
it 'returns nil' do
expect(subject.accepted_until).to be_nil
end
end
context 'when custom email is set up' do
subject { verification.accepted_until }
it { is_expected.to be_nil }
context 'when verification process started' do
let(:triggered_at) { 2.minutes.ago }
before do
verification.assign_attributes(
state: "running",
triggered_at: triggered_at,
triggerer: user,
token: token
)
end
it { is_expected.to eq(described_class::TIMEFRAME.since(triggered_at)) }
end
end
end
describe '#in_timeframe?' do
context 'when no custom email is set up' do
it 'returns false' do
expect(subject).not_to be_in_timeframe
end
end
context 'when custom email is set up' do
it { is_expected.not_to be_in_timeframe }
context 'when verification process started' do
let(:triggered_at) { 1.second.ago }
before do
subject.assign_attributes(
state: "running",
triggered_at: triggered_at,
triggerer: user,
token: token
)
end
it { is_expected.to be_in_timeframe }
context 'and timeframe was missed' do
let(:triggered_at) { (described_class::TIMEFRAME + 1).ago }
before do
subject.triggered_at = triggered_at
end
it { is_expected.not_to be_in_timeframe }
end
end
end
end
describe 'encrypted #token' do
subject { build_stubbed(:service_desk_custom_email_verification, token: token) }
it 'saves and retrieves the encrypted token and iv correctly' do
expect(subject.encrypted_token).not_to be_nil
expect(subject.encrypted_token_iv).not_to be_nil
expect(subject.token).to eq(token)
end
end
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:triggerer) }
it 'can access service desk setting from project' do
setting = build_stubbed(:service_desk_setting, project: project)
expect(verification.service_desk_setting).to eq(setting)
end
end
end

View File

@ -3,6 +3,9 @@
require 'spec_helper'
RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
let(:verification) { build(:service_desk_custom_email_verification) }
let(:project) { build(:project) }
describe 'validations' do
subject(:service_desk_setting) { create(:service_desk_setting) }
@ -23,6 +26,8 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
context 'when custom_email_enabled is true' do
before do
# Test without ServiceDesk::CustomEmailVerification for simplicity
# See dedicated simplified tests below
subject.custom_email_enabled = true
end
@ -55,7 +60,18 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
it { is_expected.not_to allow_value('/example').for(:custom_email_smtp_address) }
end
describe '.valid_issue_template' do
context 'when custom email verification is present/was triggered' do
before do
subject.project.service_desk_custom_email_verification = verification
end
it { is_expected.to validate_presence_of(:custom_email) }
it { is_expected.to validate_presence_of(:custom_email_smtp_username) }
it { is_expected.to validate_presence_of(:custom_email_smtp_port) }
it { is_expected.to validate_presence_of(:custom_email_smtp_address) }
end
describe '#valid_issue_template' do
let_it_be(:project) { create(:project, :custom_repo, files: { '.gitlab/issue_templates/service_desk.md' => 'template' }) }
it 'is not valid if template does not exist' do
@ -73,7 +89,20 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
end
end
describe '.valid_project_key' do
describe '#custom_email_address_for_verification' do
it 'returns nil' do
expect(subject.custom_email_address_for_verification).to be_nil
end
context 'when custom_email exists' do
it 'returns correct verification address' do
subject.custom_email = 'support@example.com'
expect(subject.custom_email_address_for_verification).to eq('support+verify@example.com')
end
end
end
describe '#valid_project_key' do
# Creates two projects with same full path slug
# group1/test/one and group1/test-one will both have 'group-test-one' slug
let_it_be(:group) { create(:group) }
@ -109,15 +138,15 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
end
end
describe 'encrypted password' do
describe 'encrypted #custom_email_smtp_password' do
let_it_be(:settings) do
create(
:service_desk_setting,
custom_email_enabled: true,
custom_email: 'supersupport@example.com',
custom_email: 'support@example.com',
custom_email_smtp_address: 'smtp.example.com',
custom_email_smtp_port: 587,
custom_email_smtp_username: 'supersupport@example.com',
custom_email_smtp_username: 'support@example.com',
custom_email_smtp_password: 'supersecret'
)
end
@ -131,6 +160,24 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do
end
describe 'associations' do
let(:custom_email_settings) do
build_stubbed(
:service_desk_setting,
custom_email: 'support@example.com',
custom_email_smtp_address: 'smtp.example.com',
custom_email_smtp_port: 587,
custom_email_smtp_username: 'support@example.com',
custom_email_smtp_password: 'supersecret'
)
end
it { is_expected.to belong_to(:project) }
it 'can access custom email verification from project' do
project.service_desk_custom_email_verification = verification
custom_email_settings.project = project
expect(custom_email_settings.custom_email_verification).to eq(verification)
end
end
end

View File

@ -7102,43 +7102,105 @@ RSpec.describe User, feature_category: :user_profile do
context 'when user is confirmed' do
let(:user) { create(:user) }
it 'is falsey' do
expect(user.confirmed?).to be_truthy
expect(subject).to be_falsey
it 'is false' do
expect(user.confirmed?).to be(true)
expect(subject).to be(false)
end
end
context 'when user is not confirmed' do
let_it_be(:user) { build_stubbed(:user, :unconfirmed, confirmation_sent_at: Time.current) }
it 'is truthy when soft_email_confirmation feature is disabled' do
stub_feature_flags(soft_email_confirmation: false)
expect(subject).to be_truthy
context 'when email confirmation setting is set to `off`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'off')
end
it { is_expected.to be(false) }
end
context 'when soft_email_confirmation feature is enabled' do
context 'when email confirmation setting is set to `soft`' do
before do
stub_feature_flags(soft_email_confirmation: true)
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
it 'is falsey when confirmation period is valid' do
expect(subject).to be_falsey
context 'when confirmation period is valid' do
it { is_expected.to be(false) }
end
it 'is truthy when confirmation period is expired' do
travel_to(User.allow_unconfirmed_access_for.from_now + 1.day) do
expect(subject).to be_truthy
context 'when confirmation period is expired' do
before do
travel_to(User.allow_unconfirmed_access_for.from_now + 1.day)
end
it { is_expected.to be(true) }
end
context 'when user has no confirmation email sent' do
let(:user) { build(:user, :unconfirmed, confirmation_sent_at: nil) }
it 'is truthy' do
expect(subject).to be_truthy
end
it { is_expected.to be(true) }
end
end
context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
it { is_expected.to be(true) }
end
end
end
describe '#confirmation_period_valid?' do
subject { user.send(:confirmation_period_valid?) }
let_it_be(:user) { create(:user) }
context 'when email confirmation setting is set to `off`' do
before do
stub_feature_flags(soft_email_confirmation: false)
end
it { is_expected.to be(true) }
end
context 'when email confirmation setting is set to `soft`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
context 'when within confirmation window' do
before do
user.update!(confirmation_sent_at: Date.today)
end
it { is_expected.to be(true) }
end
context 'when outside confirmation window' do
before do
user.update!(confirmation_sent_at: Date.today - described_class.confirm_within - 7.days)
end
it { is_expected.to be(false) }
end
end
context 'when email confirmation setting is set to `hard`' do
before do
stub_feature_flags(soft_email_confirmation: false)
stub_application_setting_enum('email_confirmation_setting', 'hard')
end
it { is_expected.to be(true) }
end
describe '#in_confirmation_period?' do
it 'is expected to be an alias' do
expect(user.method(:in_confirmation_period?).original_name).to eq(:confirmation_period_valid?)
end
end
end

View File

@ -292,6 +292,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
context 'inactive user' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
current_user.update!(confirmed_at: nil, confirmation_sent_at: 5.days.ago)
end
@ -412,6 +413,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
describe 'inactive user' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
current_user.update!(confirmed_at: nil)
end
@ -516,6 +518,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
describe 'inactive user' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
current_user.update!(confirmed_at: nil)
end

View File

@ -190,7 +190,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
end
context 'when project is public with artifacts that are non public' do
let(:job) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
it 'rejects access to artifacts' do
project.update_column(:visibility_level,
@ -439,7 +439,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
context 'when public project guest and artifacts are non public' do
let(:api_user) { guest }
let(:job) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
before do
project.update_column(:visibility_level,
@ -644,7 +644,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
end
context 'when project is public with non public artifacts' do
let(:job) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline, user: api_user) }
let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline, user: api_user) }
let(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC }
let(:public_builds) { true }

View File

@ -124,6 +124,8 @@ RSpec.describe 'OAuth tokens', feature_category: :system_access do
context 'when user account is not confirmed' do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
user.update!(confirmed_at: nil)
request_oauth_token(user, client_basic_auth_header(client))

View File

@ -285,7 +285,7 @@ RSpec.describe BuildDetailsEntity do
end
context 'when the build has non public archive type artifacts' do
let(:build) { create(:ci_build, :artifacts, :non_public_artifacts, pipeline: pipeline) }
let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) }
it 'does not expose non public artifacts' do
expect(subject.keys).not_to include(:artifact)

View File

@ -33,6 +33,66 @@ RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifac
describe '#execute' do
subject { service.execute(artifacts_file, params, metadata_file: metadata_file) }
def expect_accessibility_be(accessibility)
if accessibility == :public
expect(job.job_artifacts).to all be_public_accessibility
else
expect(job.job_artifacts).to all be_private_accessibility
end
end
shared_examples 'job does not have public artifacts in the CI config' do |expected_artifacts_count, accessibility|
it "sets accessibility by default to #{accessibility}" do
expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
expect_accessibility_be(accessibility)
end
end
shared_examples 'job artifact set as private in the CI config' do |expected_artifacts_count, accessibility|
let!(:job) { create(:ci_build, :with_private_artifacts_config, project: project) }
it "sets accessibility to #{accessibility}" do
expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
expect_accessibility_be(accessibility)
end
end
shared_examples 'job artifact set as public in the CI config' do |expected_artifacts_count, accessibility|
let!(:job) { create(:ci_build, :with_public_artifacts_config, project: project) }
it "sets accessibility to #{accessibility}" do
expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
expect_accessibility_be(accessibility)
end
end
shared_examples 'when accessibility level passed as private' do |expected_artifacts_count, accessibility|
before do
params.merge!('accessibility' => 'private')
end
it 'sets accessibility to private level' do
expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
expect_accessibility_be(accessibility)
end
end
shared_examples 'when accessibility passed as public' do |expected_artifacts_count|
before do
params.merge!('accessibility' => 'public')
end
it 'sets accessibility level to public' do
expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count)
expect(job.job_artifacts).to all be_public_accessibility
end
end
context 'when artifacts file is uploaded' do
it 'logs the created artifact' do
expect(Gitlab::Ci::Artifacts::Logger)
@ -61,37 +121,19 @@ RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifac
expect(new_artifact.locked).to eq(job.pipeline.locked)
end
it 'sets accessibility level by default to public' do
expect { subject }.to change { Ci::JobArtifact.count }.by(1)
new_artifact = job.job_artifacts.last
expect(new_artifact).to be_public_accessibility
end
context 'when accessibility level passed as private' do
context 'when non_public_artifacts feature flag is disabled' do
before do
params.merge!('accessibility' => 'private')
stub_feature_flags(non_public_artifacts: false)
end
it 'sets accessibility level to private' do
expect { subject }.to change { Ci::JobArtifact.count }.by(1)
new_artifact = job.job_artifacts.last
expect(new_artifact).to be_private_accessibility
end
end
context 'when accessibility passed as public' do
before do
params.merge!('accessibility' => 'public')
context 'when accessibility level not passed to the service' do
it_behaves_like 'job does not have public artifacts in the CI config', 1, :public
it_behaves_like 'job artifact set as private in the CI config', 1, :public
it_behaves_like 'job artifact set as public in the CI config', 1, :public
end
it 'sets accessibility to public level' do
expect { subject }.to change { Ci::JobArtifact.count }.by(1)
new_artifact = job.job_artifacts.last
expect(new_artifact).to be_public_accessibility
end
it_behaves_like 'when accessibility level passed as private', 1, :public
it_behaves_like 'when accessibility passed as public', 1
end
context 'when accessibility passed as invalid value' do
@ -104,6 +146,16 @@ RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifac
end
end
context 'when accessibility level not passed to the service' do
it_behaves_like 'job does not have public artifacts in the CI config', 1, :public
it_behaves_like 'job artifact set as private in the CI config', 1, :private
it_behaves_like 'job artifact set as public in the CI config', 1, :public
end
it_behaves_like 'when accessibility level passed as private', 1, :private
it_behaves_like 'when accessibility passed as public', 1
context 'when metadata file is also uploaded' do
let(:metadata_file) do
file_to_upload('spec/fixtures/ci_build_artifacts_metadata.gz', sha256: artifacts_sha256)
@ -125,13 +177,16 @@ RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifac
expect(new_artifact.locked).to eq(job.pipeline.locked)
end
it 'sets accessibility by default to public' do
expect { subject }.to change { Ci::JobArtifact.count }.by(2)
new_artifact = job.job_artifacts.last
expect(new_artifact).to be_public_accessibility
context 'when accessibility level not passed to the service' do
it_behaves_like 'job does not have public artifacts in the CI config', 2, :public
it_behaves_like 'job artifact set as private in the CI config', 2, :private
it_behaves_like 'job artifact set as public in the CI config', 2, :public
end
it_behaves_like 'when accessibility level passed as private', 2, :privatge
it_behaves_like 'when accessibility passed as public', 2
it 'logs the created artifact and metadata' do
expect(Gitlab::Ci::Artifacts::Logger)
.to receive(:log_created)
@ -140,32 +195,6 @@ RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifac
subject
end
context 'when accessibility level passed as private' do
before do
params.merge!('accessibility' => 'private')
end
it 'sets accessibility to private level' do
expect { subject }.to change { Ci::JobArtifact.count }.by(2)
new_artifact = job.job_artifacts.last
expect(new_artifact).to be_private_accessibility
end
end
context 'when accessibility passed as public' do
before do
params.merge!('accessibility' => 'public')
end
it 'sets accessibility level to public' do
expect { subject }.to change { Ci::JobArtifact.count }.by(2)
new_artifact = job.job_artifacts.last
expect(new_artifact).to be_public_accessibility
end
end
it 'sets expiration date according to application settings' do
expected_expire_at = 1.day.from_now

View File

@ -10,7 +10,7 @@ RSpec.shared_examples 'Secure OAuth Authorizations' do
end
context 'when user is unconfirmed' do
let(:user) { create(:user, confirmed_at: nil) }
let(:user) { create(:user, :unconfirmed) }
it 'displays an error' do
expect(page).to have_text I18n.t('doorkeeper.errors.messages.unconfirmed_email')