diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/ability.rb | 67 | ||||
-rw-r--r-- | app/models/analytics/cycle_analytics/project_level.rb | 1 | ||||
-rw-r--r-- | app/models/ci/pipeline.rb | 2 | ||||
-rw-r--r-- | app/models/clusters/platforms/kubernetes.rb | 6 | ||||
-rw-r--r-- | app/models/container_expiration_policy.rb | 10 | ||||
-rw-r--r-- | app/models/integration.rb | 4 | ||||
-rw-r--r-- | app/models/issue.rb | 1 | ||||
-rw-r--r-- | app/models/merge_request.rb | 3 | ||||
-rw-r--r-- | app/models/packages/package.rb | 2 | ||||
-rw-r--r-- | app/models/project.rb | 27 | ||||
-rw-r--r-- | app/models/remote_mirror.rb | 3 | ||||
-rw-r--r-- | app/models/user.rb | 15 |
12 files changed, 116 insertions, 25 deletions
diff --git a/app/models/ability.rb b/app/models/ability.rb index c18bd21d754..6a63a8d46ba 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -54,7 +54,7 @@ class Ability end end - def allowed?(user, action, subject = :global, opts = {}) + def allowed?(user, ability, subject = :global, opts = {}) if subject.is_a?(Hash) opts = subject subject = :global @@ -64,21 +64,76 @@ class Ability case opts[:scope] when :user - DeclarativePolicy.user_scope { policy.can?(action) } + DeclarativePolicy.user_scope { policy.allowed?(ability) } when :subject - DeclarativePolicy.subject_scope { policy.can?(action) } + DeclarativePolicy.subject_scope { policy.allowed?(ability) } else - policy.can?(action) + policy.allowed?(ability) end + ensure + # TODO: replace with runner invalidation: + # See: https://gitlab.com/gitlab-org/declarative-policy/-/merge_requests/24 + # See: https://gitlab.com/gitlab-org/declarative-policy/-/merge_requests/25 + forget_runner_result(policy.runner(ability)) if policy && ability_forgetting? end def policy_for(user, subject = :global) - cache = Gitlab::SafeRequestStore.active? ? Gitlab::SafeRequestStore : {} - DeclarativePolicy.policy_for(user, subject, cache: cache) + DeclarativePolicy.policy_for(user, subject, cache: ::Gitlab::SafeRequestStore.storage) + end + + # This method is something of a band-aid over the problem. The problem is + # that some conditions may not be re-entrant, if facts change. + # (`BasePolicy#admin?` is a known offender, due to the effects of + # `admin_mode`) + # + # To deal with this we need to clear two elements of state: the offending + # conditions (selected by 'pattern') and the cached ability checks (cached + # on the `policy#runner(ability)`). + # + # Clearing the conditions (see `forget_all_but`) is fairly robust, provided + # the pattern is not _under_-selective. Clearing the runners is harder, + # since there is not good way to know which abilities any given condition + # may affect. The approach taken here (see `forget_runner_result`) is to + # discard all runner results generated during a `forgetting` block. This may + # be _under_-selective if a runner prior to this block cached a state value + # that might now be invalid. + # + # TODO: add some kind of reverse-dependency mapping in DeclarativePolicy + # See: https://gitlab.com/gitlab-org/declarative-policy/-/issues/14 + def forgetting(pattern, &block) + was_forgetting = ability_forgetting? + ::Gitlab::SafeRequestStore[:ability_forgetting] = true + keys_before = ::Gitlab::SafeRequestStore.storage.keys + + yield + ensure + ::Gitlab::SafeRequestStore[:ability_forgetting] = was_forgetting + forget_all_but(keys_before, matching: pattern) end private + def ability_forgetting? + ::Gitlab::SafeRequestStore[:ability_forgetting] + end + + def forget_all_but(keys_before, matching:) + keys_after = ::Gitlab::SafeRequestStore.storage.keys + + added_keys = keys_after - keys_before + added_keys.each do |key| + if key.is_a?(String) && key.start_with?('/dp') && key =~ matching + ::Gitlab::SafeRequestStore.delete(key) + end + end + end + + def forget_runner_result(runner) + # TODO: add support in DP for this + # See: https://gitlab.com/gitlab-org/declarative-policy/-/issues/15 + runner.instance_variable_set(:@state, nil) + end + def apply_filters_if_needed(elements, user, filters) filters.each do |ability, filter| elements = filter.call(elements) unless allowed?(user, ability) diff --git a/app/models/analytics/cycle_analytics/project_level.rb b/app/models/analytics/cycle_analytics/project_level.rb index 7a73bc75ed6..d43793f60c9 100644 --- a/app/models/analytics/cycle_analytics/project_level.rb +++ b/app/models/analytics/cycle_analytics/project_level.rb @@ -47,3 +47,4 @@ module Analytics end end end +Analytics::CycleAnalytics::ProjectLevel.prepend_mod_with('Analytics::CycleAnalytics::ProjectLevel') diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index ae06bea5a02..159d9d10878 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -1257,7 +1257,7 @@ module Ci end def build_matchers - self.builds.build_matchers(project) + self.builds.latest.build_matchers(project) end private diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index da5f4cc1862..7f5f87e3e36 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -98,11 +98,7 @@ module Clusters pods = read_pods(environment.deployment_namespace) deployments = read_deployments(environment.deployment_namespace) - ingresses = if ::Feature.enabled?(:canary_ingress_weight_control, environment.project, default_enabled: true) - read_ingresses(environment.deployment_namespace) - else - [] - end + ingresses = read_ingresses(environment.deployment_namespace) # extract only the data required for display to avoid unnecessary caching { diff --git a/app/models/container_expiration_policy.rb b/app/models/container_expiration_policy.rb index 0441a5f0f5b..9bacd9a0edf 100644 --- a/app/models/container_expiration_policy.rb +++ b/app/models/container_expiration_policy.rb @@ -38,6 +38,16 @@ class ContainerExpirationPolicy < ApplicationRecord ) end + def self.without_container_repositories + where.not( + 'EXISTS(?)', + ContainerRepository.select(1) + .where( + 'container_repositories.project_id = container_expiration_policies.project_id' + ) + ) + end + def self.keep_n_options { 1 => _('%{tags} tag per image name') % { tags: 1 }, diff --git a/app/models/integration.rb b/app/models/integration.rb index 238ecbbf209..2fbcdc7f1cb 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -44,6 +44,10 @@ class Integration < ApplicationRecord bamboo bugzilla buildkite campfire confluence custom_issue_tracker datadog discord drone_ci + emails_on_push ewm emails_on_push external_wiki + flowdock + hangouts_chat + irker ].to_set.freeze def self.renamed?(name) diff --git a/app/models/issue.rb b/app/models/issue.rb index b0a126c4442..48f388ea48d 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -23,6 +23,7 @@ class Issue < ApplicationRecord include IssueAvailableFeatures include Todoable include FromUnion + include EachBatch extend ::Gitlab::Utils::Override diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 15f112690d5..68fb957759d 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -263,8 +263,9 @@ class MergeRequest < ApplicationRecord scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } scope :of_projects, ->(ids) { where(target_project_id: ids) } scope :from_project, ->(project) { where(source_project_id: project.id) } + scope :from_fork, -> { where('source_project_id <> target_project_id') } scope :from_and_to_forks, ->(project) do - where('source_project_id <> target_project_id AND (source_project_id = ? OR target_project_id = ?)', project.id, project.id) + from_fork.where('source_project_id = ? OR target_project_id = ?', project.id, project.id) end scope :merged, -> { with_state(:merged) } scope :closed_and_merged, -> { with_states(:closed, :merged) } diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb index 7b0bb72940e..b040c98ef09 100644 --- a/app/models/packages/package.rb +++ b/app/models/packages/package.rb @@ -158,7 +158,7 @@ class Packages::Package < ApplicationRecord joins(:project).reorder(keyset_order) end - after_commit :update_composer_cache, on: :destroy, if: -> { composer? } + after_commit :update_composer_cache, on: :destroy, if: -> { composer? && Feature.disabled?(:disable_composer_callback) } def self.only_maven_packages_with_path(path, use_cte: false) if use_cte diff --git a/app/models/project.rb b/app/models/project.rb index 735dc185575..1f8e8b81015 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -166,12 +166,12 @@ class Project < ApplicationRecord has_one :datadog_integration, class_name: 'Integrations::Datadog' has_one :discord_integration, class_name: 'Integrations::Discord' has_one :drone_ci_integration, class_name: 'Integrations::DroneCi' - has_one :emails_on_push_service, class_name: 'Integrations::EmailsOnPush' - has_one :ewm_service, class_name: 'Integrations::Ewm' - has_one :external_wiki_service, class_name: 'Integrations::ExternalWiki' - has_one :flowdock_service, class_name: 'Integrations::Flowdock' - has_one :hangouts_chat_service, class_name: 'Integrations::HangoutsChat' - has_one :irker_service, class_name: 'Integrations::Irker' + has_one :emails_on_push_integration, class_name: 'Integrations::EmailsOnPush' + has_one :ewm_integration, class_name: 'Integrations::Ewm' + has_one :external_wiki_integration, class_name: 'Integrations::ExternalWiki' + has_one :flowdock_integration, class_name: 'Integrations::Flowdock' + has_one :hangouts_chat_integration, class_name: 'Integrations::HangoutsChat' + has_one :irker_integration, class_name: 'Integrations::Irker' has_one :jenkins_service, class_name: 'Integrations::Jenkins' has_one :jira_service, class_name: 'Integrations::Jira' has_one :mattermost_service, class_name: 'Integrations::Mattermost' @@ -825,6 +825,21 @@ class Project < ApplicationRecord from_union([with_issues_enabled, with_merge_requests_enabled]).select(:id) end + + def find_by_url(url) + uri = URI(url) + + return unless uri.host == Gitlab.config.gitlab.host + + match = Rails.application.routes.recognize_path(url) + + return if match[:unmatched_route].present? + return if match[:namespace_id].blank? || match[:id].blank? + + find_by_full_path(match.values_at(:namespace_id, :id).join("/")) + rescue ActionController::RoutingError, URI::InvalidURIError + nil + end end def initialize(attributes = nil) diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb index c3ca90ca0ad..a700f104150 100644 --- a/app/models/remote_mirror.rb +++ b/app/models/remote_mirror.rb @@ -100,10 +100,11 @@ class RemoteMirror < ApplicationRecord update_status == 'started' end - def update_repository + def update_repository(inmemory_remote:) Gitlab::Git::RemoteMirror.new( project.repository.raw, remote_name, + inmemory_remote ? remote_url : nil, **options_for_update ).update end diff --git a/app/models/user.rb b/app/models/user.rb index 8ee0421e45f..5fbd6271589 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -84,10 +84,11 @@ class User < ApplicationRecord update_tracked_fields(request) - lease = Gitlab::ExclusiveLease.new("user_update_tracked_fields:#{id}", timeout: 1.hour.to_i) - return unless lease.try_obtain - - Users::UpdateService.new(self, user: self).execute(validate: false) + Gitlab::ExclusiveLease.throttle(id) do + ::Ability.forgetting(/admin/) do + Users::UpdateService.new(self, user: self).execute(validate: false) + end + end end # rubocop: enable CodeReuse/ServiceClass @@ -1868,6 +1869,12 @@ class User < ApplicationRecord !!(password_expires_at && password_expires_at < Time.current) end + def password_expired_if_applicable? + return false unless allow_password_authentication? + + password_expired? + end + def can_be_deactivated? active? && no_recent_activity? && !internal? end |