From 8e3523281051490ff696bfd85bea1195c046c87c Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 2 Sep 2020 15:10:54 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/rules.gitlab-ci.yml | 2 +- .rubocop_todo.yml | 42 ------ Gemfile.lock | 2 +- .../issuable_filtered_search_token_keys.js | 5 + .../clusters/clusters_controller.rb | 5 +- .../concerns/authenticates_with_two_factor.rb | 24 +++- .../enforces_two_factor_authentication.rb | 18 +-- .../omniauth_callbacks_controller.rb | 11 +- .../profiles/active_sessions_controller.rb | 1 + .../profiles/two_factor_auths_controller.rb | 4 +- app/controllers/sessions_controller.rb | 13 +- app/finders/ci/auth_job_finder.rb | 56 ++++++++ app/finders/user_recent_events_finder.rb | 12 +- app/graphql/mutations/boards/lists/base.rb | 2 +- app/graphql/mutations/boards/lists/create.rb | 9 +- app/graphql/mutations/snippets/base.rb | 2 +- app/models/active_session.rb | 13 ++ app/models/aws/role.rb | 1 + app/models/clusters/applications/runner.rb | 2 +- app/models/concerns/discussion_on_diff.rb | 2 - app/models/concerns/resolvable_discussion.rb | 1 - app/models/diff_discussion.rb | 1 - app/models/discussion.rb | 1 - app/models/member.rb | 2 + app/models/user.rb | 7 + app/services/applications/create_service.rb | 11 +- ...ntainer_registry_authentication_service.rb | 1 + app/services/branches/delete_service.rb | 2 +- app/services/ci/pipeline_trigger_service.rb | 7 +- .../clusters/aws/authorize_role_service.rb | 16 +-- app/services/members/destroy_service.rb | 33 ++++- .../projects/update_remote_mirror_service.rb | 4 + .../active_sessions/_active_session.html.haml | 2 +- .../projects/issues/service_desk.html.haml | 2 +- .../unreleased/217908-handle-git-errors.yml | 5 + ...t-query-parameter-name-in-the-service-.yml | 5 + .../eb-track-group-coverage-csv-download.yml | 5 + changelogs/unreleased/empty-lines-cop-fix.yml | 5 + changelogs/unreleased/empty-literal-cop.yml | 5 + changelogs/unreleased/it-behaves-cop.yml | 5 + changelogs/unreleased/non-deter-cop.yml | 5 + ...-205-dblessing-oauth-token-brute-force.yml | 5 + ...ate-gitlab-runner-helm-chart-to-0-20-1.yml | 5 + config/initializers/doorkeeper.rb | 2 +- config/routes/user.rb | 1 - ...17040735_change_aws_roles_role_arn_null.rb | 15 ++ ...311_add_o_auth_paths_to_protected_paths.rb | 62 ++++++++ db/schema_migrations/20200717040735 | 1 + db/schema_migrations/20200728182311 | 1 + db/structure.sql | 4 +- .../graphql/reference/gitlab_schema.graphql | 19 ++- doc/api/graphql/reference/gitlab_schema.json | 34 ++++- doc/development/sidekiq_style_guide.md | 73 ++++++---- doc/integration/elasticsearch.md | 16 +-- doc/user/profile/active_sessions.md | 5 + doc/user/profile/index.md | 8 +- lib/api/api_guard.rb | 21 ++- lib/api/badges.rb | 7 +- lib/api/conan_packages.rb | 10 +- lib/api/helpers/badges_helpers.rb | 8 +- lib/api/helpers/packages/conan/api_helpers.rb | 8 +- .../packages_manager_clients_helpers.rb | 2 +- .../pipeline/broadcast_message_pipeline.rb | 1 - lib/banzai/pipeline/gfm_pipeline.rb | 6 - lib/banzai/pipeline/single_line_pipeline.rb | 2 - lib/gitlab/auth.rb | 25 +++- lib/gitlab/auth/auth_finders.rb | 16 ++- lib/gitlab/auth/two_factor_auth_verifier.rb | 36 +++++ lib/gitlab/fogbugz_import/importer.rb | 2 +- lib/gitlab/git/diff_collection.rb | 2 +- lib/gitlab/git_access.rb | 9 +- lib/gitlab/gitaly_client.rb | 2 +- lib/gitlab/regex.rb | 5 - locale/gitlab.pot | 14 +- package.json | 2 +- qa/spec/spec_helper.rb | 6 +- .../admin/applications_controller_spec.rb | 16 ++- .../admin/clusters_controller_spec.rb | 51 ++++--- .../application_controller_spec.rb | 9 +- .../groups/clusters_controller_spec.rb | 33 +++-- .../oauth/applications_controller_spec.rb | 23 ++- .../omniauth_callbacks_controller_spec.rb | 16 +++ .../active_sessions_controller_spec.rb | 23 +++ .../two_factor_auths_controller_spec.rb | 17 ++- .../projects/clusters_controller_spec.rb | 33 +++-- spec/controllers/search_controller_spec.rb | 12 +- spec/controllers/sessions_controller_spec.rb | 32 +++-- .../admin/admin_manage_applications_spec.rb | 18 ++- spec/features/issues/service_desk_spec.rb | 8 ++ spec/features/markdown/copy_as_gfm_spec.rb | 56 -------- .../user_manages_applications_spec.rb | 13 ++ spec/features/users/login_spec.rb | 12 +- spec/finders/ci/auth_job_finder_spec.rb | 64 +++++++++ .../finders/user_recent_events_finder_spec.rb | 37 ++++- spec/graphql/gitlab_schema_spec.rb | 49 +++++++ .../mutations/boards/lists/create_spec.rb | 15 +- spec/helpers/merge_requests_helper_spec.rb | 2 +- .../packages_manager_clients_helpers_spec.rb | 12 +- spec/lib/gitlab/auth/auth_finders_spec.rb | 46 +++++- .../gitlab/auth/request_authenticator_spec.rb | 11 +- .../auth/two_factor_auth_verifier_spec.rb | 112 +++++++++++++++ spec/lib/gitlab/auth_spec.rb | 72 +++++++++- spec/lib/gitlab/git/commit_spec.rb | 8 +- spec/lib/gitlab/git_access_spec.rb | 132 ++++++++++++++++-- spec/lib/gitlab/regex_spec.rb | 9 -- spec/lib/gitlab/workhorse_spec.rb | 2 +- ...dd_o_auth_paths_to_protected_paths_spec.rb | 52 +++++++ spec/models/active_session_spec.rb | 53 +++++++ spec/models/aws/role_spec.rb | 6 + spec/models/member_spec.rb | 13 ++ spec/models/user_spec.rb | 50 +++++++ spec/requests/api/badges_spec.rb | 28 +++- spec/requests/api/conan_packages_spec.rb | 45 +++++- spec/requests/api/generic_packages_spec.rb | 2 +- spec/requests/api/go_proxy_spec.rb | 9 +- .../mutations/boards/lists/create_spec.rb | 54 +++++++ .../mutations/snippets/destroy_spec.rb | 25 ++++ spec/requests/api/helpers_spec.rb | 21 +++ spec/requests/api/jobs_spec.rb | 6 +- spec/requests/api/maven_packages_spec.rb | 33 ++++- spec/requests/api/npm_packages_spec.rb | 11 +- spec/requests/api/nuget_packages_spec.rb | 2 +- spec/requests/api/releases_spec.rb | 10 +- spec/requests/api/terraform/state_spec.rb | 11 +- .../applications/create_service_spec.rb | 19 ++- ...er_registry_authentication_service_spec.rb | 13 ++ spec/services/branches/delete_service_spec.rb | 15 ++ .../ci/pipeline_trigger_service_spec.rb | 18 ++- .../aws/authorize_role_service_spec.rb | 44 +++--- spec/services/members/destroy_service_spec.rb | 40 ++++++ spec/services/notification_service_spec.rb | 10 +- .../update_remote_mirror_service_spec.rb | 33 +++++ spec/spec_helper.rb | 8 +- spec/support/helpers/stub_object_storage.rb | 2 +- .../clusters_controller_shared_examples.rb | 29 ++++ yarn.lock | 8 +- 136 files changed, 1951 insertions(+), 448 deletions(-) create mode 100644 app/finders/ci/auth_job_finder.rb create mode 100644 changelogs/unreleased/217908-handle-git-errors.yml create mode 100644 changelogs/unreleased/235440-search-query-is-added-without-query-parameter-name-in-the-service-.yml create mode 100644 changelogs/unreleased/eb-track-group-coverage-csv-download.yml create mode 100644 changelogs/unreleased/empty-lines-cop-fix.yml create mode 100644 changelogs/unreleased/empty-literal-cop.yml create mode 100644 changelogs/unreleased/it-behaves-cop.yml create mode 100644 changelogs/unreleased/non-deter-cop.yml create mode 100644 changelogs/unreleased/security-205-dblessing-oauth-token-brute-force.yml create mode 100644 changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-20-1.yml create mode 100644 db/migrate/20200717040735_change_aws_roles_role_arn_null.rb create mode 100644 db/migrate/20200728182311_add_o_auth_paths_to_protected_paths.rb create mode 100644 db/schema_migrations/20200717040735 create mode 100644 db/schema_migrations/20200728182311 create mode 100644 lib/gitlab/auth/two_factor_auth_verifier.rb create mode 100644 spec/controllers/profiles/active_sessions_controller_spec.rb create mode 100644 spec/finders/ci/auth_job_finder_spec.rb create mode 100644 spec/lib/gitlab/auth/two_factor_auth_verifier_spec.rb create mode 100644 spec/migrations/20200728182311_add_o_auth_paths_to_protected_paths_spec.rb create mode 100644 spec/requests/api/graphql/mutations/boards/lists/create_spec.rb create mode 100644 spec/support/shared_examples/controllers/clusters_controller_shared_examples.rb diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 47a1e8341b7..aedcd4f71a0 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -761,7 +761,7 @@ changes: *code-qa-patterns when: manual allow_failure: true - - <<: *if-master-refs + - <<: *if-dot-com-gitlab-org-schedule allow_failure: true .review:rules:danger: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d01b3fb91da..6c46ad5dffc 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -18,20 +18,6 @@ Capybara/CurrentPathExpectation: Layout/ArgumentAlignment: Enabled: false -# Offense count: 72 -# Cop supports --auto-correct. -Layout/EmptyLinesAroundArguments: - Exclude: - - 'app/models/concerns/discussion_on_diff.rb' - - 'app/models/concerns/resolvable_discussion.rb' - - 'app/models/diff_discussion.rb' - - 'app/models/discussion.rb' - - 'ee/spec/models/geo/project_registry_spec.rb' - - 'lib/banzai/pipeline/broadcast_message_pipeline.rb' - - 'lib/banzai/pipeline/gfm_pipeline.rb' - - 'lib/banzai/pipeline/single_line_pipeline.rb' - - 'spec/features/markdown/copy_as_gfm_spec.rb' - # Offense count: 413 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, IndentationWidth. @@ -101,14 +87,6 @@ Layout/SpaceInsideParens: Lint/MissingCopEnableDirective: Enabled: false -# Offense count: 11 -# Cop supports --auto-correct. -Lint/NonDeterministicRequireOrder: - Exclude: - - 'ee/spec/spec_helper.rb' - - 'qa/spec/spec_helper.rb' - - 'spec/spec_helper.rb' - # Offense count: 27 # Cop supports --auto-correct. Lint/RedundantCopDisableDirective: @@ -229,15 +207,6 @@ RSpec/ExpectChange: RSpec/ExpectInHook: Enabled: false -# Offense count: 9 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: it_behaves_like, it_should_behave_like -RSpec/ItBehavesLike: - Exclude: - - 'spec/lib/gitlab/git/commit_spec.rb' - - 'spec/services/notification_service_spec.rb' - # Offense count: 68 # Cop supports --auto-correct. RSpec/LetBeforeExamples: @@ -600,17 +569,6 @@ Style/EmptyLambdaParameter: - 'app/models/ci/build.rb' - 'app/models/ci/runner.rb' -# Offense count: 7 -# Cop supports --auto-correct. -Style/EmptyLiteral: - Exclude: - - 'lib/gitlab/fogbugz_import/importer.rb' - - 'lib/gitlab/git/diff_collection.rb' - - 'lib/gitlab/gitaly_client.rb' - - 'spec/helpers/merge_requests_helper_spec.rb' - - 'spec/lib/gitlab/workhorse_spec.rb' - - 'spec/requests/api/jobs_spec.rb' - # Offense count: 170 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. diff --git a/Gemfile.lock b/Gemfile.lock index ae678d2321b..53ede64312b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1197,7 +1197,7 @@ GEM railties (>= 3.2.0) websocket-driver (0.7.1) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.4) + websocket-extensions (0.1.5) wikicloth (0.8.1) builder expression_parser diff --git a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js index 9bea7aa7b04..d2ac80fa190 100644 --- a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js +++ b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js @@ -85,6 +85,11 @@ export const conditions = flattenDeep( tokenKey: 'assignee', value: __('Any'), }, + { + url: 'author_username=support-bot', + tokenKey: 'author', + value: 'support-bot', + }, { url: 'milestone_title=None', tokenKey: 'milestone', diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index b6d5eb7e5c0..7006c23321c 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -38,8 +38,7 @@ class Clusters::ClustersController < Clusters::BaseController def new if params[:provider] == 'aws' - @aws_role = current_user.aws_role || Aws::Role.new - @aws_role.ensure_role_external_id! + @aws_role = Aws::Role.create_or_find_by!(user: current_user) @instance_types = load_instance_types.to_json elsif params[:provider] == 'gcp' @@ -274,7 +273,7 @@ class Clusters::ClustersController < Clusters::BaseController end def aws_role_params - params.require(:cluster).permit(:role_arn, :role_external_id) + params.require(:cluster).permit(:role_arn) end def generate_gcp_authorize_url diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 4b4bcc8d37e..2cc51c65c26 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -22,6 +22,8 @@ module AuthenticatesWithTwoFactor return handle_locked_user(user) unless user.can?(:log_in) session[:otp_user_id] = user.id + session[:user_updated_at] = user.updated_at + setup_u2f_authentication(user) render 'devise/sessions/two_factor' end @@ -39,6 +41,7 @@ module AuthenticatesWithTwoFactor def authenticate_with_two_factor user = self.resource = find_user return handle_locked_user(user) unless user.can?(:log_in) + return handle_changed_user(user) if user_changed?(user) if user_params[:otp_attempt].present? && session[:otp_user_id] authenticate_with_two_factor_via_otp(user) @@ -63,12 +66,14 @@ module AuthenticatesWithTwoFactor def clear_two_factor_attempt! session.delete(:otp_user_id) + session.delete(:user_updated_at) + session.delete(:challenge) end def authenticate_with_two_factor_via_otp(user) if valid_otp_attempt?(user) # Remove any lingering user data from login - session.delete(:otp_user_id) + clear_two_factor_attempt! remember_me(user) if user_params[:remember_me] == '1' user.save! @@ -85,8 +90,7 @@ module AuthenticatesWithTwoFactor def authenticate_with_two_factor_via_u2f(user) if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge]) # Remove any lingering user data from login - session.delete(:otp_user_id) - session.delete(:challenge) + clear_two_factor_attempt! remember_me(user) if user_params[:remember_me] == '1' sign_in(user, message: :two_factor_authenticated, event: :authentication) @@ -113,4 +117,18 @@ module AuthenticatesWithTwoFactor end end # rubocop: enable CodeReuse/ActiveRecord + + def handle_changed_user(user) + clear_two_factor_attempt! + + redirect_to new_user_session_path, alert: _('An error occurred. Please sign in again.') + end + + # If user has been updated since we validated the password, + # the password might have changed. + def user_changed?(user) + return false unless session[:user_updated_at] + + user.updated_at != session[:user_updated_at] + end end diff --git a/app/controllers/concerns/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb index f1dd46648f1..02082f81598 100644 --- a/app/controllers/concerns/enforces_two_factor_authentication.rb +++ b/app/controllers/concerns/enforces_two_factor_authentication.rb @@ -29,12 +29,11 @@ module EnforcesTwoFactorAuthentication end def two_factor_authentication_required? - Gitlab::CurrentSettings.require_two_factor_authentication? || - current_user.try(:require_two_factor_authentication_from_group?) + two_factor_verifier.two_factor_authentication_required? end def current_user_requires_two_factor? - current_user && !current_user.temp_oauth_email? && !current_user.two_factor_enabled? && !skip_two_factor? + two_factor_verifier.current_user_needs_to_setup_two_factor? && !skip_two_factor? end # rubocop: disable CodeReuse/ActiveRecord @@ -43,7 +42,7 @@ module EnforcesTwoFactorAuthentication if Gitlab::CurrentSettings.require_two_factor_authentication? global.call else - groups = current_user.expanded_groups_requiring_two_factor_authentication.reorder(name: :asc) + groups = current_user.source_groups_of_two_factor_authentication_requirement.reorder(name: :asc) group.call(groups) end end @@ -51,14 +50,11 @@ module EnforcesTwoFactorAuthentication # rubocop: enable CodeReuse/ActiveRecord def two_factor_grace_period - periods = [Gitlab::CurrentSettings.two_factor_grace_period] - periods << current_user.two_factor_grace_period if current_user.try(:require_two_factor_authentication_from_group?) - periods.min + two_factor_verifier.two_factor_grace_period end def two_factor_grace_period_expired? - date = current_user.otp_grace_period_started_at - date && (date + two_factor_grace_period.hours) < Time.current + two_factor_verifier.two_factor_grace_period_expired? end def two_factor_skippable? @@ -70,6 +66,10 @@ module EnforcesTwoFactorAuthentication def skip_two_factor? session[:skip_two_factor] && session[:skip_two_factor] > Time.current end + + def two_factor_verifier + @two_factor_verifier ||= Gitlab::Auth::TwoFactorAuthVerifier.new(current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables + end end EnforcesTwoFactorAuthentication.prepend_if_ee('EE::EnforcesTwoFactorAuthentication') diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 6a393405e4d..a558b01f0c6 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -50,12 +50,6 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController redirect_unverified_saml_initiation end - def omniauth_error - @provider = params[:provider] - @error = params[:error] - render 'errors/omniauth_error', layout: "oauth_error", status: :unprocessable_entity - end - def cas3 ticket = params['ticket'] if ticket @@ -205,9 +199,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def fail_login(user) log_failed_login(user.username, oauth['provider']) - error_message = user.errors.full_messages.to_sentence + @provider = Gitlab::Auth::OAuth::Provider.label_for(params[:action]) + @error = user.errors.full_messages.to_sentence - redirect_to omniauth_error_path(oauth['provider'], error: error_message) + render 'errors/omniauth_error', layout: "oauth_error", status: :unprocessable_entity end def fail_auth0_login diff --git a/app/controllers/profiles/active_sessions_controller.rb b/app/controllers/profiles/active_sessions_controller.rb index f409193aefc..d9ec3195fd1 100644 --- a/app/controllers/profiles/active_sessions_controller.rb +++ b/app/controllers/profiles/active_sessions_controller.rb @@ -7,6 +7,7 @@ class Profiles::ActiveSessionsController < Profiles::ApplicationController def destroy ActiveSession.destroy_with_public_id(current_user, params[:id]) + current_user.forget_me! respond_to do |format| format.html { redirect_to profile_active_sessions_url, status: :found } diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index a88c5ca4fa1..f600c34ca75 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -4,7 +4,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController skip_before_action :check_two_factor_requirement def show - unless current_user.otp_secret + unless current_user.two_factor_enabled? current_user.otp_secret = User.generate_otp_secret(32) end @@ -38,6 +38,8 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController def create if current_user.validate_and_consume_otp!(params[:pin_code]) + ActiveSession.destroy_all_but_current(current_user, session) + Users::UpdateService.new(current_user, user: current_user, otp_required_for_login: true).execute! do |user| @codes = user.generate_otp_backup_codes! end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index baf7a05f8ba..5da2bafbcb3 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -8,6 +8,7 @@ class SessionsController < Devise::SessionsController include Recaptcha::Verify include RendersLdapServers include KnownSignIn + include Gitlab::Utils::StrongMemoize skip_before_action :check_two_factor_requirement, only: [:destroy] skip_before_action :check_password_expiration, only: [:destroy] @@ -199,10 +200,14 @@ class SessionsController < Devise::SessionsController end def find_user - if session[:otp_user_id] - User.find(session[:otp_user_id]) - elsif user_params[:login] - User.by_login(user_params[:login]) + strong_memoize(:find_user) do + if session[:otp_user_id] && user_params[:login] + User.by_id_and_login(session[:otp_user_id], user_params[:login]).first + elsif session[:otp_user_id] + User.find(session[:otp_user_id]) + elsif user_params[:login] + User.by_login(user_params[:login]) + end end end diff --git a/app/finders/ci/auth_job_finder.rb b/app/finders/ci/auth_job_finder.rb new file mode 100644 index 00000000000..aee7dd16341 --- /dev/null +++ b/app/finders/ci/auth_job_finder.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true +module Ci + class AuthJobFinder + AuthError = Class.new(StandardError) + NotRunningJobError = Class.new(AuthError) + ErasedJobError = Class.new(AuthError) + DeletedProjectError = Class.new(AuthError) + + def initialize(token:) + @token = token + end + + def execute! + find_job_by_token.tap do |job| + next unless job + + validate_job!(job) + end + end + + def execute + execute! + rescue AuthError + end + + private + + attr_reader :token, :require_running, :raise_on_missing + + def find_job_by_token + ::Ci::Build.find_by_token(token) + end + + def validate_job!(job) + validate_running_job!(job) + validate_job_not_erased!(job) + validate_project_presence!(job) + + true + end + + def validate_running_job!(job) + raise NotRunningJobError, 'Job is not running' unless job.running? + end + + def validate_job_not_erased!(job) + raise ErasedJobError, 'Job has been erased!' if job.erased? + end + + def validate_project_presence!(job) + if job.project.nil? || job.project.pending_delete? + raise DeletedProjectError, 'Project has been deleted!' + end + end + end +end diff --git a/app/finders/user_recent_events_finder.rb b/app/finders/user_recent_events_finder.rb index 3f2e813d381..f376b26ab9c 100644 --- a/app/finders/user_recent_events_finder.rb +++ b/app/finders/user_recent_events_finder.rb @@ -6,6 +6,7 @@ # WARNING: does not consider project feature visibility! # - user: The user for which to load the events # - params: +# - limit: Number of items that to be returned. Defaults to 20 and limited to 100. # - offset: The page of events to return class UserRecentEventsFinder prepend FinderWithCrossProjectAccess @@ -16,7 +17,8 @@ class UserRecentEventsFinder attr_reader :current_user, :target_user, :params - LIMIT = 20 + DEFAULT_LIMIT = 20 + MAX_LIMIT = 100 def initialize(current_user, target_user, params = {}) @current_user = current_user @@ -31,7 +33,7 @@ class UserRecentEventsFinder recent_events(params[:offset] || 0) .joins(:project) .with_associations - .limit_recent(params[:limit].presence || LIMIT, params[:offset]) + .limit_recent(limit, params[:offset]) end # rubocop: enable CodeReuse/ActiveRecord @@ -59,4 +61,10 @@ class UserRecentEventsFinder def projects target_user.project_interactions.to_sql end + + def limit + return DEFAULT_LIMIT unless params[:limit].present? + + [params[:limit].to_i, MAX_LIMIT].min + end end diff --git a/app/graphql/mutations/boards/lists/base.rb b/app/graphql/mutations/boards/lists/base.rb index 34b271ba3b8..d244d6bf8dd 100644 --- a/app/graphql/mutations/boards/lists/base.rb +++ b/app/graphql/mutations/boards/lists/base.rb @@ -8,7 +8,7 @@ module Mutations argument :board_id, ::Types::GlobalIDType[::Board], required: true, - description: 'The Global ID of the issue board to mutate' + description: 'Global ID of the issue board to mutate' field :list, Types::BoardListType, diff --git a/app/graphql/mutations/boards/lists/create.rb b/app/graphql/mutations/boards/lists/create.rb index 4f545709ee9..3fe1052315f 100644 --- a/app/graphql/mutations/boards/lists/create.rb +++ b/app/graphql/mutations/boards/lists/create.rb @@ -12,7 +12,7 @@ module Mutations argument :label_id, ::Types::GlobalIDType[::Label], required: false, - description: 'ID of an existing label' + description: 'Global ID of an existing label' def ready?(**args) if args.slice(*mutually_exclusive_args).size != 1 @@ -39,6 +39,7 @@ module Mutations private + # Overridden in EE def authorize_list_type_resource!(board, params) return unless params[:label_id] @@ -57,13 +58,15 @@ module Mutations create_list_service.execute(board) end + # Overridden in EE def create_list_params(args) params = args.slice(*mutually_exclusive_args).with_indifferent_access - params[:label_id] = GitlabSchema.parse_gid(params[:label_id]).model_id if params[:label_id] + params[:label_id] &&= ::GitlabSchema.parse_gid(params[:label_id], expected_type: ::Label).model_id params end + # Overridden in EE def mutually_exclusive_args [:backlog, :label_id] end @@ -71,3 +74,5 @@ module Mutations end end end + +Mutations::Boards::Lists::Create.prepend_if_ee('::EE::Mutations::Boards::Lists::Create') diff --git a/app/graphql/mutations/snippets/base.rb b/app/graphql/mutations/snippets/base.rb index c8cc721b2e0..023f876d035 100644 --- a/app/graphql/mutations/snippets/base.rb +++ b/app/graphql/mutations/snippets/base.rb @@ -11,7 +11,7 @@ module Mutations private def find_object(id:) - GitlabSchema.object_from_id(id) + GitlabSchema.object_from_id(id, expected_type: ::Snippet) end def authorized_resource?(snippet) diff --git a/app/models/active_session.rb b/app/models/active_session.rb index be07c221f32..4908290e06b 100644 --- a/app/models/active_session.rb +++ b/app/models/active_session.rb @@ -105,6 +105,19 @@ class ActiveSession end end + def self.destroy_all_but_current(user, current_session) + session_ids = not_impersonated(user) + session_ids.reject! { |session| session.current?(current_session) } if current_session + + Gitlab::Redis::SharedState.with do |redis| + destroy_sessions(redis, user, session_ids.map(&:session_id)) if session_ids.any? + end + end + + def self.not_impersonated(user) + list(user).reject(&:is_impersonated) + end + def self.key_name(user_id, session_id = '*') "#{Gitlab::Redis::SharedState::USER_SESSIONS_NAMESPACE}:#{user_id}:#{session_id}" end diff --git a/app/models/aws/role.rb b/app/models/aws/role.rb index 54132be749d..7d34665082d 100644 --- a/app/models/aws/role.rb +++ b/app/models/aws/role.rb @@ -9,6 +9,7 @@ module Aws validates :role_external_id, uniqueness: true, length: { in: 1..64 } validates :role_arn, length: 1..2048, + allow_nil: true, format: { with: Gitlab::Regex.aws_arn_regex, message: Gitlab::Regex.aws_arn_regex_message diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index f33d54544ca..4983de83800 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Runner < ApplicationRecord - VERSION = '0.20.0' + VERSION = '0.20.1' self.table_name = 'clusters_applications_runners' diff --git a/app/models/concerns/discussion_on_diff.rb b/app/models/concerns/discussion_on_diff.rb index 8542c48f366..40891073738 100644 --- a/app/models/concerns/discussion_on_diff.rb +++ b/app/models/concerns/discussion_on_diff.rb @@ -13,14 +13,12 @@ module DiscussionOnDiff :diff_line, :active?, :created_at_diff?, - to: :first_note delegate :file_path, :blob, :highlighted_diff_lines, :diff_lines, - to: :diff_file, allow_nil: true end diff --git a/app/models/concerns/resolvable_discussion.rb b/app/models/concerns/resolvable_discussion.rb index 5174ae05d15..3e1e5faee54 100644 --- a/app/models/concerns/resolvable_discussion.rb +++ b/app/models/concerns/resolvable_discussion.rb @@ -31,7 +31,6 @@ module ResolvableDiscussion delegate :resolved_at, :resolved_by, :resolved_by_push?, - to: :last_resolved_note, allow_nil: true end diff --git a/app/models/diff_discussion.rb b/app/models/diff_discussion.rb index f9e2f00b9f3..6806008d676 100644 --- a/app/models/diff_discussion.rb +++ b/app/models/diff_discussion.rb @@ -16,7 +16,6 @@ class DiffDiscussion < Discussion :diff_note_positions, :on_text?, :on_image?, - to: :first_note def legacy_diff_discussion? diff --git a/app/models/discussion.rb b/app/models/discussion.rb index adcb2217d85..793cdb5dece 100644 --- a/app/models/discussion.rb +++ b/app/models/discussion.rb @@ -24,7 +24,6 @@ class Discussion :system_note_with_references_visible_for?, :resource_parent, :save, - to: :first_note def declarative_policy_delegate diff --git a/app/models/member.rb b/app/models/member.rb index a27076b49d7..1913df61614 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -76,6 +76,8 @@ class Member < ApplicationRecord scope :request, -> { where.not(requested_at: nil) } scope :non_request, -> { where(requested_at: nil) } + scope :not_accepted_invitations_by_user, -> (user) { invite.where(invite_accepted_at: nil, created_by: user) } + scope :has_access, -> { active.where('access_level > 0') } scope :guests, -> { active.where(access_level: GUEST) } diff --git a/app/models/user.rb b/app/models/user.rb index 355a174ba9a..7574f0865a0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -364,6 +364,7 @@ class User < ApplicationRecord scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) } scope :order_recent_last_activity, -> { reorder(Gitlab::Database.nulls_last_order('last_activity_on', 'DESC')) } scope :order_oldest_last_activity, -> { reorder(Gitlab::Database.nulls_first_order('last_activity_on', 'ASC')) } + scope :by_id_and_login, ->(id, login) { where(id: id).where('username = LOWER(:login) OR email = LOWER(:login)', login: login) } def preferred_language read_attribute('preferred_language') || @@ -887,6 +888,12 @@ class User < ApplicationRecord all_expanded_groups.where(require_two_factor_authentication: true) end + def source_groups_of_two_factor_authentication_requirement + Gitlab::ObjectHierarchy.new(expanded_groups_requiring_two_factor_authentication) + .all_objects + .where(id: groups) + end + # rubocop: disable CodeReuse/ServiceClass def refresh_authorized_projects Users::RefreshAuthorizedProjectsService.new(self).execute diff --git a/app/services/applications/create_service.rb b/app/services/applications/create_service.rb index 500db1e172a..92500fbc254 100644 --- a/app/services/applications/create_service.rb +++ b/app/services/applications/create_service.rb @@ -11,7 +11,16 @@ module Applications # EE would override and use `request` arg def execute(request) - Doorkeeper::Application.create(params) + @application = Doorkeeper::Application.new(params) + + unless params[:scopes].present? + @application.errors.add(:base, _("Scopes can't be blank")) + + return @application + end + + @application.save + @application end end end diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index 44a434f4402..831a25a637e 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -132,6 +132,7 @@ module Auth def can_access?(requested_project, requested_action) return false unless requested_project.container_registry_enabled? + return false if requested_project.repository_access_level == ::ProjectFeature::DISABLED case requested_action when 'pull' diff --git a/app/services/branches/delete_service.rb b/app/services/branches/delete_service.rb index 9bd5b343448..6efbdd161a1 100644 --- a/app/services/branches/delete_service.rb +++ b/app/services/branches/delete_service.rb @@ -26,7 +26,7 @@ module Branches message: 'Failed to remove branch', http_status: 400) end - rescue Gitlab::Git::PreReceiveError => ex + rescue Gitlab::Git::PreReceiveError, Gitlab::Git::CommandError => ex ServiceResponse.error(message: ex.message, http_status: 400) end diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb index 37b9b4c362c..d9f41b7040e 100644 --- a/app/services/ci/pipeline_trigger_service.rb +++ b/app/services/ci/pipeline_trigger_service.rb @@ -10,6 +10,9 @@ module Ci elsif job_from_token create_pipeline_from_job(job_from_token) end + + rescue Ci::AuthJobFinder::AuthError => e + error(e.message, 401) end private @@ -41,8 +44,6 @@ module Ci # this check is to not leak the presence of the project if user cannot read it return unless can?(job.user, :read_project, project) - return error("400 Job has to be running", 400) unless job.running? - pipeline = Ci::CreatePipelineService.new(project, job.user, ref: params[:ref]) .execute(:pipeline, ignore_skip_ci: true) do |pipeline| source = job.sourced_pipelines.build( @@ -64,7 +65,7 @@ module Ci def job_from_token strong_memoize(:job) do - Ci::Build.find_by_token(params[:token].to_s) + Ci::AuthJobFinder.new(token: params[:token].to_s).execute! end end diff --git a/app/services/clusters/aws/authorize_role_service.rb b/app/services/clusters/aws/authorize_role_service.rb index fb620f77b9f..2712a4b05bb 100644 --- a/app/services/clusters/aws/authorize_role_service.rb +++ b/app/services/clusters/aws/authorize_role_service.rb @@ -9,6 +9,7 @@ module Clusters ERRORS = [ ActiveRecord::RecordInvalid, + ActiveRecord::RecordNotFound, Clusters::Aws::FetchCredentialsService::MissingRoleError, ::Aws::Errors::MissingCredentialsError, ::Aws::STS::Errors::ServiceError @@ -20,7 +21,8 @@ module Clusters end def execute - @role = create_or_update_role! + ensure_role_exists! + update_role_arn! Response.new(:ok, credentials) rescue *ERRORS => e @@ -33,14 +35,12 @@ module Clusters attr_reader :role, :params - def create_or_update_role! - if role = user.aws_role - role.update!(params) + def ensure_role_exists! + @role = ::Aws::Role.find_by_user_id!(user.id) + end - role - else - user.create_aws_role!(params) - end + def update_role_arn! + role.update!(params) end def credentials diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb index fdd43260521..8cad065e6cc 100644 --- a/app/services/members/destroy_service.rb +++ b/app/services/members/destroy_service.rb @@ -18,6 +18,7 @@ module Members end delete_subresources(member) unless skip_subresources + delete_project_invitations_by(member) unless skip_subresources enqueue_delete_todos(member) enqueue_unassign_issuables(member) if unassign_issuables @@ -39,24 +40,48 @@ module Members delete_project_members(member) delete_subgroup_members(member) + delete_invited_members(member) end def delete_project_members(member) groups = member.group.self_and_descendants - ProjectMember.in_namespaces(groups).with_user(member.user).each do |project_member| - self.class.new(current_user).execute(project_member, skip_authorization: @skip_auth) - end + destroy_project_members(ProjectMember.in_namespaces(groups).with_user(member.user)) end def delete_subgroup_members(member) groups = member.group.descendants - GroupMember.of_groups(groups).with_user(member.user).each do |group_member| + destroy_group_members(GroupMember.of_groups(groups).with_user(member.user)) + end + + def delete_invited_members(member) + groups = member.group.self_and_descendants + + destroy_group_members(GroupMember.of_groups(groups).not_accepted_invitations_by_user(member.user)) + + destroy_project_members(ProjectMember.in_namespaces(groups).not_accepted_invitations_by_user(member.user)) + end + + def destroy_project_members(members) + members.each do |project_member| + self.class.new(current_user).execute(project_member, skip_authorization: @skip_auth) + end + end + + def destroy_group_members(members) + members.each do |group_member| self.class.new(current_user).execute(group_member, skip_authorization: @skip_auth, skip_subresources: true) end end + def delete_project_invitations_by(member) + return unless member.is_a?(ProjectMember) && member.user && member.project + + members_to_delete = member.project.members.not_accepted_invitations_by_user(member.user) + destroy_project_members(members_to_delete) + end + def can_destroy_member?(member) can?(current_user, destroy_member_permission(member), member) end diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb index fe2610f89fb..7961f689259 100644 --- a/app/services/projects/update_remote_mirror_service.rb +++ b/app/services/projects/update_remote_mirror_service.rb @@ -7,6 +7,10 @@ module Projects def execute(remote_mirror, tries) return success unless remote_mirror.enabled? + if Gitlab::UrlBlocker.blocked_url?(CGI.unescape(Gitlab::UrlSanitizer.sanitize(remote_mirror.url))) + return error("The remote mirror URL is invalid.") + end + update_mirror(remote_mirror) success diff --git a/app/views/profiles/active_sessions/_active_session.html.haml b/app/views/profiles/active_sessions/_active_session.html.haml index 9ae75fe6b8e..c4b3fa80d75 100644 --- a/app/views/profiles/active_sessions/_active_session.html.haml +++ b/app/views/profiles/active_sessions/_active_session.html.haml @@ -27,6 +27,6 @@ - unless is_current_session .float-right - = link_to profile_active_session_path(active_session.public_id), data: { confirm: _('Are you sure? The device will be signed out of GitLab.') }, method: :delete, class: "btn btn-danger gl-ml-3" do + = link_to profile_active_session_path(active_session.public_id), data: { confirm: _('Are you sure? The device will be signed out of GitLab and all remember me tokens revoked.') }, method: :delete, class: "btn btn-danger gl-ml-3" do %span.sr-only= _('Revoke') = _('Revoke') diff --git a/app/views/projects/issues/service_desk.html.haml b/app/views/projects/issues/service_desk.html.haml index bd260bdf143..65580a94cd0 100644 --- a/app/views/projects/issues/service_desk.html.haml +++ b/app/views/projects/issues/service_desk.html.haml @@ -7,7 +7,7 @@ - support_bot_attrs = { service_desk_enabled: @project.service_desk_enabled?, **UserSerializer.new.represent(User.support_bot) }.to_json -- data_endpoint = "#{expose_path(api_v4_projects_issues_path(id: @project.id))}?author_id=#{User.support_bot.id}" +- data_endpoint = "#{expose_path(api_v4_projects_issues_path(id: @project.id))}?author_username=#{User.support_bot.username}" %div{ class: "js-service-desk-issues service-desk-issues", data: { support_bot: support_bot_attrs, service_desk_meta: service_desk_meta(@project) } } .top-area diff --git a/changelogs/unreleased/217908-handle-git-errors.yml b/changelogs/unreleased/217908-handle-git-errors.yml new file mode 100644 index 00000000000..bb6c4918428 --- /dev/null +++ b/changelogs/unreleased/217908-handle-git-errors.yml @@ -0,0 +1,5 @@ +--- +title: Fix unfinished merge by Merge Train process +merge_request: 41106 +author: +type: fixed diff --git a/changelogs/unreleased/235440-search-query-is-added-without-query-parameter-name-in-the-service-.yml b/changelogs/unreleased/235440-search-query-is-added-without-query-parameter-name-in-the-service-.yml new file mode 100644 index 00000000000..09b4181ee32 --- /dev/null +++ b/changelogs/unreleased/235440-search-query-is-added-without-query-parameter-name-in-the-service-.yml @@ -0,0 +1,5 @@ +--- +title: Fix the filtered search bar to work in the service desk issue list +merge_request: 40797 +author: +type: fixed diff --git a/changelogs/unreleased/eb-track-group-coverage-csv-download.yml b/changelogs/unreleased/eb-track-group-coverage-csv-download.yml new file mode 100644 index 00000000000..603d01bad2c --- /dev/null +++ b/changelogs/unreleased/eb-track-group-coverage-csv-download.yml @@ -0,0 +1,5 @@ +--- +title: Track downloads of group code coverage CSV in snowplow +merge_request: 40754 +author: +type: added diff --git a/changelogs/unreleased/empty-lines-cop-fix.yml b/changelogs/unreleased/empty-lines-cop-fix.yml new file mode 100644 index 00000000000..f5ed1955266 --- /dev/null +++ b/changelogs/unreleased/empty-lines-cop-fix.yml @@ -0,0 +1,5 @@ +--- +title: Fix Layout/EmptyLinesAroundArguments cop +merge_request: 41086 +author: Rajendra Kadam +type: fixed diff --git a/changelogs/unreleased/empty-literal-cop.yml b/changelogs/unreleased/empty-literal-cop.yml new file mode 100644 index 00000000000..1d5b4857193 --- /dev/null +++ b/changelogs/unreleased/empty-literal-cop.yml @@ -0,0 +1,5 @@ +--- +title: Fix Style/EmptyLiteral cop +merge_request: 41110 +author: Rajendra Kadam +type: fixed diff --git a/changelogs/unreleased/it-behaves-cop.yml b/changelogs/unreleased/it-behaves-cop.yml new file mode 100644 index 00000000000..95bb412c55a --- /dev/null +++ b/changelogs/unreleased/it-behaves-cop.yml @@ -0,0 +1,5 @@ +--- +title: Fix RSpec/ItBehavesLike cop +merge_request: 41111 +author: Rajendra Kadam +type: fixed diff --git a/changelogs/unreleased/non-deter-cop.yml b/changelogs/unreleased/non-deter-cop.yml new file mode 100644 index 00000000000..18cd89ccceb --- /dev/null +++ b/changelogs/unreleased/non-deter-cop.yml @@ -0,0 +1,5 @@ +--- +title: Fix Lint/NonDeterministicRequireOrder cop +merge_request: 41098 +author: Rajendra Kadam +type: fixed diff --git a/changelogs/unreleased/security-205-dblessing-oauth-token-brute-force.yml b/changelogs/unreleased/security-205-dblessing-oauth-token-brute-force.yml new file mode 100644 index 00000000000..e53ef7ba09a --- /dev/null +++ b/changelogs/unreleased/security-205-dblessing-oauth-token-brute-force.yml @@ -0,0 +1,5 @@ +--- +title: Protect OAuth endpoints from brute force/password stuffing +merge_request: +author: +type: security diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-20-1.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-20-1.yml new file mode 100644 index 00000000000..67cddaa4539 --- /dev/null +++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-20-1.yml @@ -0,0 +1,5 @@ +--- +title: Update GitLab Runner Helm Chart to 0.20.1 +merge_request: +author: +type: security diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 76e29fb6c02..ad0b0c2008f 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -17,7 +17,7 @@ Doorkeeper.configure do end resource_owner_from_credentials do |routes| - user = Gitlab::Auth.find_with_user_password(params[:username], params[:password]) + user = Gitlab::Auth.find_with_user_password(params[:username], params[:password], increment_failed_attempts: true) user unless user.try(:two_factor_enabled?) end diff --git a/config/routes/user.rb b/config/routes/user.rb index 3bf13908d39..c7a5a56d9ed 100644 --- a/config/routes/user.rb +++ b/config/routes/user.rb @@ -25,7 +25,6 @@ devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, confirmations: :confirmations } devise_scope :user do - get '/users/auth/:provider/omniauth_error' => 'omniauth_callbacks#omniauth_error', as: :omniauth_error get '/users/almost_there' => 'confirmations#almost_there' end diff --git a/db/migrate/20200717040735_change_aws_roles_role_arn_null.rb b/db/migrate/20200717040735_change_aws_roles_role_arn_null.rb new file mode 100644 index 00000000000..707cfe96a7c --- /dev/null +++ b/db/migrate/20200717040735_change_aws_roles_role_arn_null.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ChangeAwsRolesRoleArnNull < ActiveRecord::Migration[6.0] + DOWNTIME = false + EXAMPLE_ARN = 'arn:aws:iam::000000000000:role/example-role' + + def up + change_column_null :aws_roles, :role_arn, true + end + + def down + # Records may now exist with nulls, so we must fill them with a dummy value + change_column_null :aws_roles, :role_arn, false, EXAMPLE_ARN + end +end diff --git a/db/migrate/20200728182311_add_o_auth_paths_to_protected_paths.rb b/db/migrate/20200728182311_add_o_auth_paths_to_protected_paths.rb new file mode 100644 index 00000000000..7a5af0135fa --- /dev/null +++ b/db/migrate/20200728182311_add_o_auth_paths_to_protected_paths.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +class AddOAuthPathsToProtectedPaths < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + ADD_PROTECTED_PATHS = [ + '/oauth/authorize', + '/oauth/token' + ].freeze + + EXISTING_DEFAULT_PROTECTED_PATHS = [ + '/users/password', + '/users/sign_in', + '/api/v3/session.json', + '/api/v3/session', + '/api/v4/session.json', + '/api/v4/session', + '/users', + '/users/confirmation', + '/unsubscribes/', + '/import/github/personal_access_token', + '/admin/session' + ].freeze + + NEW_DEFAULT_PROTECTED_PATHS = (EXISTING_DEFAULT_PROTECTED_PATHS + ADD_PROTECTED_PATHS).freeze + + class ApplicationSetting < ActiveRecord::Base + self.table_name = 'application_settings' + end + + def up + change_column_default :application_settings, :protected_paths, NEW_DEFAULT_PROTECTED_PATHS + + ApplicationSetting.reset_column_information + + ApplicationSetting.where.not(protected_paths: nil).each do |application_setting| + missing_paths = ADD_PROTECTED_PATHS - application_setting.protected_paths + + next if missing_paths.empty? + + updated_protected_paths = application_setting.protected_paths + missing_paths + application_setting.update!(protected_paths: updated_protected_paths) + end + end + + def down + change_column_default :application_settings, :protected_paths, EXISTING_DEFAULT_PROTECTED_PATHS + + ApplicationSetting.reset_column_information + + ApplicationSetting.where.not(protected_paths: nil).each do |application_setting| + paths_to_remove = application_setting.protected_paths - EXISTING_DEFAULT_PROTECTED_PATHS + + next if paths_to_remove.empty? + + updated_protected_paths = application_setting.protected_paths - paths_to_remove + application_setting.update!(protected_paths: updated_protected_paths) + end + end +end diff --git a/db/schema_migrations/20200717040735 b/db/schema_migrations/20200717040735 new file mode 100644 index 00000000000..6bfa1dd7261 --- /dev/null +++ b/db/schema_migrations/20200717040735 @@ -0,0 +1 @@ +6b8fa09c9700c494eeb5151f43064f1656eaaea804742629b7bd66483e2b04cb \ No newline at end of file diff --git a/db/schema_migrations/20200728182311 b/db/schema_migrations/20200728182311 new file mode 100644 index 00000000000..6bb5a869513 --- /dev/null +++ b/db/schema_migrations/20200728182311 @@ -0,0 +1 @@ +2aab4599404312ddcc5bc9af11b0a21dfd6aa8aa10d4b4b5086a93ce1ffe77b6 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 61a9dadba08..97d74287694 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -9190,7 +9190,7 @@ CREATE TABLE public.application_settings ( throttle_protected_paths_enabled boolean DEFAULT false NOT NULL, throttle_protected_paths_requests_per_period integer DEFAULT 10 NOT NULL, throttle_protected_paths_period_in_seconds integer DEFAULT 60 NOT NULL, - protected_paths character varying(255)[] DEFAULT '{/users/password,/users/sign_in,/api/v3/session.json,/api/v3/session,/api/v4/session.json,/api/v4/session,/users,/users/confirmation,/unsubscribes/,/import/github/personal_access_token,/admin/session}'::character varying[], + protected_paths character varying(255)[] DEFAULT '{/users/password,/users/sign_in,/api/v3/session.json,/api/v3/session,/api/v4/session.json,/api/v4/session,/users,/users/confirmation,/unsubscribes/,/import/github/personal_access_token,/admin/session,/oauth/authorize,/oauth/token}'::character varying[], throttle_incident_management_notification_enabled boolean DEFAULT false NOT NULL, throttle_incident_management_notification_period_in_seconds integer DEFAULT 3600, throttle_incident_management_notification_per_period integer DEFAULT 3600, @@ -9557,7 +9557,7 @@ CREATE TABLE public.aws_roles ( user_id integer NOT NULL, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, - role_arn character varying(2048) NOT NULL, + role_arn character varying(2048), role_external_id character varying(64) NOT NULL ); diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index f66a897c1c2..6d73c0d594a 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -1309,13 +1309,18 @@ type BoardListConnection { Autogenerated input type of BoardListCreate """ input BoardListCreateInput { + """ + Global ID of an existing user + """ + assigneeId: UserID + """ Create the backlog list """ backlog: Boolean """ - The Global ID of the issue board to mutate + Global ID of the issue board to mutate """ boardId: BoardID! @@ -1325,9 +1330,14 @@ input BoardListCreateInput { clientMutationId: String """ - ID of an existing label + Global ID of an existing label """ labelId: LabelID + + """ + Global ID of an existing milestone + """ + milestoneId: MilestoneID } """ @@ -17210,6 +17220,11 @@ type UserEdge { node: User } +""" +Identifier of User +""" +scalar UserID + type UserPermissions { """ Indicates the user can perform `create_snippet` on this resource diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index ecf3cb3e38c..7a58ee5d54b 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -3505,7 +3505,7 @@ "inputFields": [ { "name": "boardId", - "description": "The Global ID of the issue board to mutate", + "description": "Global ID of the issue board to mutate", "type": { "kind": "NON_NULL", "name": null, @@ -3529,7 +3529,7 @@ }, { "name": "labelId", - "description": "ID of an existing label", + "description": "Global ID of an existing label", "type": { "kind": "SCALAR", "name": "LabelID", @@ -3537,6 +3537,26 @@ }, "defaultValue": null }, + { + "name": "milestoneId", + "description": "Global ID of an existing milestone", + "type": { + "kind": "SCALAR", + "name": "MilestoneID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "assigneeId", + "description": "Global ID of an existing user", + "type": { + "kind": "SCALAR", + "name": "UserID", + "ofType": null + }, + "defaultValue": null + }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", @@ -50478,6 +50498,16 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "UserID", + "description": "Identifier of User", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "UserPermissions", diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md index c5dfc5731e6..fdea27f43ca 100644 --- a/doc/development/sidekiq_style_guide.md +++ b/doc/development/sidekiq_style_guide.md @@ -615,42 +615,51 @@ Jobs need to be backward and forward compatible between consecutive versions of the application. Adding or removing an argument may cause problems during deployment before all Rails and Sidekiq nodes have the updated code. -#### Remove an argument +#### Deprecate and remove an argument -**Do not remove arguments from the `perform` function.**. Instead, use the -following approach: +**Before you remove arguments from the `perform_async` and `perform` methods.**, deprecate them. The +following example deprecates and then removes `arg2` from the `perform_async` method: 1. Provide a default value (usually `nil`) and use a comment to mark the - argument as deprecated -1. Stop using the argument in `perform_async`. -1. Ignore the value in the worker class, but do not remove it until the next - major release. + argument as deprecated in the coming minor release. (Release M) -In the following example, if you want to remove `arg2`, first set a `nil` default value, -and then update locations where `ExampleWorker.perform_async` is called. + ```ruby + class ExampleWorker + # Keep arg2 parameter for backwards compatibility. + def perform(object_id, arg1, arg2 = nil) + # ... + end + end + ``` -```ruby -class ExampleWorker - def perform(object_id, arg1, arg2 = nil) - # ... - end -end -``` +1. One minor release later, stop using the argument in `perform_async`. (Release M+1) + + ```ruby + ExampleWorker.perform_async(object_id, arg1) + ``` + +1. At the next major release, remove the value from the worker class. (Next major release) + + ```ruby + class ExampleWorker + def perform(object_id, arg1) + # ... + end + end + ``` #### Add an argument There are two options for safely adding new arguments to Sidekiq workers: -1. Set up a [multi-step deployment](#multi-step-deployment) in which the new argument is first added to the worker +1. Set up a [multi-step deployment](#multi-step-deployment) in which the new argument is first added to the worker. 1. Use a [parameter hash](#parameter-hash) for additional arguments. This is perhaps the most flexible option. ##### Multi-step deployment -This approach requires multiple merge requests and for the first merge request -to be merged and deployed before additional changes are merged. +This approach requires multiple releases. -1. In an initial merge request, add the argument to the worker with a default - value: +1. Add the argument to the worker with a default value (Release M). ```ruby class ExampleWorker @@ -660,16 +669,28 @@ to be merged and deployed before additional changes are merged. end ``` -1. Merge and deploy the worker with the new argument. -1. In a further merge request, update `ExampleWorker.perform_async` calls to - use the new argument. +1. Add the new argument to all the invocations of the worker (Release M+1). + + ```ruby + ExampleWorker.perform_async(object_id, new_arg) + ``` + +1. Remove the default value (Release M+2). + + ```ruby + class ExampleWorker + def perform(object_id, new_arg) + # ... + end + end + ``` ##### Parameter hash -This approach will not require multiple deployments if an existing worker already +This approach will not require multiple releases if an existing worker already utilizes a parameter hash. -1. Use a parameter hash in the worker to allow for future flexibility: +1. Use a parameter hash in the worker to allow future flexibility. ```ruby class ExampleWorker diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md index daf7a8f6703..4d0ed035ad5 100644 --- a/doc/integration/elasticsearch.md +++ b/doc/integration/elasticsearch.md @@ -165,7 +165,7 @@ instances](#indexing-large-instances) below. In order to enable Elasticsearch, you need to have admin access in GitLab. -1. Navigate to **Admin Area** (wrench icon), then **Settings > Integrations** +1. Navigate to **Admin Area** (wrench icon), then **Settings > General** and expand the **Elasticsearch** section. 1. Configure the [Elasticsearch settings](#elasticsearch-configuration) for your Elasticsearch cluster. Do not enable **Elasticsearch indexing** or @@ -183,7 +183,7 @@ In order to enable Elasticsearch, you need to have admin access in GitLab. ``` 1. Now enable `Elasticsearch indexing` in **Admin Area > Settings > - Integrations > Elasticsearch** and click **Save changes**. + General > Elasticsearch** and click **Save changes**. 1. Click **Index all projects**. 1. Click **Check progress** in the confirmation message to see the status of the background jobs. @@ -198,7 +198,7 @@ In order to enable Elasticsearch, you need to have admin access in GitLab. ``` 1. After the indexing has completed, enable **Search with Elasticsearch** in - **Admin Area > Settings > Integrations > Elasticsearch** and click **Save + **Admin Area > Settings > General > Elasticsearch** and click **Save changes**. ### Elasticsearch configuration @@ -251,7 +251,7 @@ from the Elasticsearch index as expected. To disable the Elasticsearch integration: -1. Navigate to the **Admin Area** (wrench icon), then **Settings > Integrations**. +1. Navigate to the **Admin Area** (wrench icon), then **Settings > General**. 1. Expand the **Elasticsearch** section and uncheck **Elasticsearch indexing** and **Search with Elasticsearch enabled**. 1. Click **Save changes** for the changes to take effect. @@ -439,7 +439,7 @@ used by the GitLab Elasticsearch integration. ### Pause the indexing -In the **Admin Area > Integration > Elasticsearch** section, select the +In the **Admin Area > Settings > General > Elasticsearch** section, select the **Pause Elasticsearch Indexing** setting, and then save your change. With this, all updates that should happen on your Elasticsearch index will be @@ -455,7 +455,7 @@ This process involves several shell commands and curl invocations, so a good initial setup will help for later: ```shell -# You can find this value under Admin Area > Integration > Elasticsearch > URL +# You can find this value under Admin Area > Settings > General > Elasticsearch > URL export CLUSTER_URL="http://localhost:9200" export PRIMARY_INDEX="gitlab-production" export SECONDARY_INDEX="gitlab-production-$(date +%s)" @@ -556,14 +556,14 @@ To trigger the re-index from `primary` index: 1. Unpause the indexing - Under **Admin Area > Integration > Elasticsearch**, uncheck the **Pause Elasticsearch Indexing** setting and save. + Under **Admin Area > Settings > General > Elasticsearch**, uncheck the **Pause Elasticsearch Indexing** setting and save. ### Trigger the reindex via the Elasticsearch administration > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34069) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2. > - A scheduled index deletion and the ability to cancel it was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38914) in GitLab Starter 13.3. -Under **Admin Area > Integration > Elasticsearch zero-downtime reindexing**, click on **Trigger cluster reindexing**. +Under **Admin Area > Settings > General > Elasticsearch > Elasticsearch zero-downtime reindexing**, click on **Trigger cluster reindexing**. NOTE: **Note:** Reindexing can be a lengthy process depending on the size of your Elasticsearch cluster. diff --git a/doc/user/profile/active_sessions.md b/doc/user/profile/active_sessions.md index 4dbb11b581d..a5b15a7880c 100644 --- a/doc/user/profile/active_sessions.md +++ b/doc/user/profile/active_sessions.md @@ -29,6 +29,11 @@ exceeds 100, the oldest ones are deleted. 1. Use the previous steps to navigate to **Active Sessions**. 1. Click on **Revoke** besides a session. The current session cannot be revoked, as this would sign you out of GitLab. +NOTE: **Note:** +When any session is revoked all **Remember me** tokens for all +devices will be revoked. See ['Why do I keep getting signed out?'](index.md#why-do-i-keep-getting-signed-out) +for more information about the **Remember me** feature. +