diff options
Diffstat (limited to 'app/finders')
-rw-r--r-- | app/finders/alert_management/http_integrations_finder.rb | 54 | ||||
-rw-r--r-- | app/finders/ci/commit_statuses_finder.rb | 40 | ||||
-rw-r--r-- | app/finders/ci/jobs_finder.rb | 16 | ||||
-rw-r--r-- | app/finders/concerns/finder_with_cross_project_access.rb | 2 | ||||
-rw-r--r-- | app/finders/environment_names_finder.rb | 18 | ||||
-rw-r--r-- | app/finders/feature_flags_user_lists_finder.rb | 34 | ||||
-rw-r--r-- | app/finders/group_projects_finder.rb | 1 | ||||
-rw-r--r-- | app/finders/issuable_finder.rb | 13 | ||||
-rw-r--r-- | app/finders/issues_finder.rb | 2 | ||||
-rw-r--r-- | app/finders/merge_requests_finder.rb | 30 | ||||
-rw-r--r-- | app/finders/packages/group_packages_finder.rb | 9 | ||||
-rw-r--r-- | app/finders/packages/npm/package_finder.rb | 2 | ||||
-rw-r--r-- | app/finders/personal_access_tokens_finder.rb | 7 | ||||
-rw-r--r-- | app/finders/security/jobs_finder.rb | 71 | ||||
-rw-r--r-- | app/finders/security/license_compliance_jobs_finder.rb | 18 | ||||
-rw-r--r-- | app/finders/security/security_jobs_finder.rb | 19 | ||||
-rw-r--r-- | app/finders/user_groups_counter.rb | 30 |
17 files changed, 324 insertions, 42 deletions
diff --git a/app/finders/alert_management/http_integrations_finder.rb b/app/finders/alert_management/http_integrations_finder.rb new file mode 100644 index 00000000000..9f511be0ace --- /dev/null +++ b/app/finders/alert_management/http_integrations_finder.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module AlertManagement + class HttpIntegrationsFinder + def initialize(project, params) + @project = project + @params = params + end + + def execute + @collection = project.alert_management_http_integrations + + filter_by_availability + filter_by_endpoint_identifier + filter_by_active + + collection + end + + private + + attr_reader :project, :params, :collection + + def filter_by_availability + return if multiple_alert_http_integrations? + + first_id = project.alert_management_http_integrations + .ordered_by_id + .select(:id) + .at_most(1) + + @collection = collection.id_in(first_id) + end + + def filter_by_endpoint_identifier + return unless params[:endpoint_identifier] + + @collection = collection.for_endpoint_identifier(params[:endpoint_identifier]) + end + + def filter_by_active + return unless params[:active] + + @collection = collection.active + end + + # Overridden in EE + def multiple_alert_http_integrations? + false + end + end +end + +::AlertManagement::HttpIntegrationsFinder.prepend_if_ee('EE::AlertManagement::HttpIntegrationsFinder') diff --git a/app/finders/ci/commit_statuses_finder.rb b/app/finders/ci/commit_statuses_finder.rb new file mode 100644 index 00000000000..3c465eb88f3 --- /dev/null +++ b/app/finders/ci/commit_statuses_finder.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Ci + class CommitStatusesFinder + include ::Gitlab::Utils::StrongMemoize + + def initialize(project, repository, current_user, refs) + @project = project + @repository = repository + @current_user = current_user + @refs = refs + end + + def execute + return [] unless Ability.allowed?(@current_user, :read_pipeline, @project) + + commit_statuses + end + + private + + def latest_commits + strong_memoize(:latest_commits) do + refs.map do |ref| + [ref.name, @repository.commit(ref.dereferenced_target).sha] + end.to_h + end + end + + def commit_statuses + latest_pipelines = project.ci_pipelines.latest_pipeline_per_commit(latest_commits.values) + + latest_commits.transform_values do |commit_sha| + latest_pipelines[commit_sha]&.detailed_status(current_user) + end.compact + end + + attr_reader :project, :repository, :current_user, :refs + end +end diff --git a/app/finders/ci/jobs_finder.rb b/app/finders/ci/jobs_finder.rb index 40c610f8209..78791d737da 100644 --- a/app/finders/ci/jobs_finder.rb +++ b/app/finders/ci/jobs_finder.rb @@ -25,11 +25,7 @@ module Ci attr_reader :current_user, :pipeline, :project, :params, :type def init_collection - if Feature.enabled?(:ci_jobs_finder_refactor, default_enabled: true) - pipeline_jobs || project_jobs || all_jobs - else - project ? project_builds : all_jobs - end + pipeline_jobs || project_jobs || all_jobs end def all_jobs @@ -38,12 +34,6 @@ module Ci type.all end - def project_builds - raise Gitlab::Access::AccessDeniedError unless can?(current_user, :read_build, project) - - project.builds.relevant - end - def project_jobs return unless project raise Gitlab::Access::AccessDeniedError unless can?(current_user, :read_build, project) @@ -59,9 +49,7 @@ module Ci end def filter_by_scope(builds) - if Feature.enabled?(:ci_jobs_finder_refactor, default_enabled: true) - return filter_by_statuses!(params[:scope], builds) if params[:scope].is_a?(Array) - end + return filter_by_statuses!(params[:scope], builds) if params[:scope].is_a?(Array) case params[:scope] when 'pending' diff --git a/app/finders/concerns/finder_with_cross_project_access.rb b/app/finders/concerns/finder_with_cross_project_access.rb index a55fb58a1bc..e63b868e470 100644 --- a/app/finders/concerns/finder_with_cross_project_access.rb +++ b/app/finders/concerns/finder_with_cross_project_access.rb @@ -32,7 +32,7 @@ module FinderWithCrossProjectAccess end override :execute - def execute(*args) + def execute(*args, **kwargs) check = Gitlab::CrossProjectAccess.find_check(self) original = -> { super } diff --git a/app/finders/environment_names_finder.rb b/app/finders/environment_names_finder.rb index a92998921c7..e9063ef4c90 100644 --- a/app/finders/environment_names_finder.rb +++ b/app/finders/environment_names_finder.rb @@ -13,7 +13,7 @@ class EnvironmentNamesFinder attr_reader :project_or_group, :current_user - def initialize(project_or_group, current_user) + def initialize(project_or_group, current_user = nil) @project_or_group = project_or_group @current_user = current_user end @@ -31,14 +31,24 @@ class EnvironmentNamesFinder end def namespace_environments - projects = - project_or_group.all_projects.public_or_visible_to_user(current_user) + # We assume reporter access is needed for the :read_environment permission + # here. This expection is also present in + # IssuableFinder::Params#min_access_level, which is used for filtering out + # merge requests that don't have the right permissions. + # + # We use this approach so we don't need to load every project into memory + # just to verify if we can see their environments. Doing so would not be + # efficient, and possibly mess up pagination if certain projects are not + # meant to be visible. + projects = project_or_group + .all_projects + .public_or_visible_to_user(current_user, Gitlab::Access::REPORTER) Environment.for_project(projects) end def project_environments - if current_user.can?(:read_environment, project_or_group) + if Ability.allowed?(current_user, :read_environment, project_or_group) project_or_group.environments else Environment.none diff --git a/app/finders/feature_flags_user_lists_finder.rb b/app/finders/feature_flags_user_lists_finder.rb new file mode 100644 index 00000000000..ebe60acd711 --- /dev/null +++ b/app/finders/feature_flags_user_lists_finder.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class FeatureFlagsUserListsFinder + attr_reader :project, :current_user, :params + + def initialize(project, current_user, params = {}) + @project = project + @current_user = current_user + @params = params + end + + def execute + unless Ability.allowed?(current_user, :read_feature_flag, project) + return Operations::FeatureFlagsUserList.none + end + + items = feature_flags_user_lists + by_search(items) + end + + private + + def feature_flags_user_lists + project.operations_feature_flags_user_lists + end + + def by_search(items) + if params[:search].present? + items.for_name_like(params[:search]) + else + items + end + end +end diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb index 5f24b15156c..8362e782ad1 100644 --- a/app/finders/group_projects_finder.rb +++ b/app/finders/group_projects_finder.rb @@ -12,6 +12,7 @@ # only_owned: boolean # only_shared: boolean # limit: integer +# include_subgroups: boolean # params: # sort: string # visibility_level: int diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 9c4aecedd93..d431c3e3699 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -153,10 +153,8 @@ class IssuableFinder end def row_count - fast_fail = Feature.enabled?(:soft_fail_count_by_state, params.group || params.project) - Gitlab::IssuablesCountForState - .new(self, nil, fast_fail: fast_fail) + .new(self, nil, fast_fail: true) .for_state_or_opened(params[:state]) end @@ -341,6 +339,15 @@ class IssuableFinder cte << items items = klass.with(cte.to_arel).from(klass.table_name) + elsif Feature.enabled?(:pg_hint_plan_for_issuables, params.project) + items = items.optimizer_hints(<<~HINTS) + BitmapScan( + issues idx_issues_on_project_id_and_created_at_and_id_and_state_id + idx_issues_on_project_id_and_due_date_and_id_and_state_id + idx_issues_on_project_id_and_updated_at_and_id_and_state_id + index_issues_on_project_id_and_iid + ) + HINTS end items.full_search(search, matched_columns: params[:in], use_minimum_char_limit: !use_cte_for_search?) diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb index 32be5bee0db..5c9010ee3e0 100644 --- a/app/finders/issues_finder.rb +++ b/app/finders/issues_finder.rb @@ -97,6 +97,8 @@ class IssuesFinder < IssuableFinder items.due_between(Date.today.beginning_of_month, Date.today.end_of_month) elsif params.filter_by_due_next_month_and_previous_two_weeks? items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month) + else + items.none end end diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb index c998de75ab2..1f847b09752 100644 --- a/app/finders/merge_requests_finder.rb +++ b/app/finders/merge_requests_finder.rb @@ -66,6 +66,11 @@ class MergeRequestsFinder < IssuableFinder by_source_project_id(items) end + def filter_negated_items(items) + items = super(items) + by_negated_target_branch(items) + end + private def by_commit(items) @@ -98,6 +103,14 @@ class MergeRequestsFinder < IssuableFinder end # rubocop: enable CodeReuse/ActiveRecord + # rubocop: disable CodeReuse/ActiveRecord + def by_negated_target_branch(items) + return items unless not_params[:target_branch] + + items.where.not(target_branch: not_params[:target_branch]) + end + # rubocop: enable CodeReuse/ActiveRecord + def source_project_id @source_project_id ||= params[:source_project_id].presence end @@ -142,19 +155,6 @@ class MergeRequestsFinder < IssuableFinder .or(table[:title].matches('(Draft)%')) end - # rubocop: disable CodeReuse/ActiveRecord - def by_deployment(items) - return items unless deployment_id - - items.includes(:deployment_merge_requests) - .where(deployment_merge_requests: { deployment_id: deployment_id }) - end - # rubocop: enable CodeReuse/ActiveRecord - - def deployment_id - @deployment_id ||= params[:deployment_id].presence - end - # Filter by merge requests that had been approved by specific users # rubocop: disable CodeReuse/Finder def by_approvals(items) @@ -165,10 +165,6 @@ class MergeRequestsFinder < IssuableFinder # rubocop: enable CodeReuse/Finder def by_deployments(items) - # Until this feature flag is enabled permanently, we retain the old - # filtering behaviour/code. - return by_deployment(items) unless Feature.enabled?(:deployment_filters) - env = params[:environment] before = params[:deployed_before] after = params[:deployed_after] diff --git a/app/finders/packages/group_packages_finder.rb b/app/finders/packages/group_packages_finder.rb index 8b948bb056d..a51057571f1 100644 --- a/app/finders/packages/group_packages_finder.rb +++ b/app/finders/packages/group_packages_finder.rb @@ -25,7 +25,7 @@ module Packages .including_build_info .including_project_route .including_tags - .for_projects(group_projects_visible_to_current_user) + .for_projects(group_projects_visible_to_current_user.select(:id)) .processed .has_version .sort_by_attribute("#{params[:order_by]}_#{params[:sort]}") @@ -36,11 +36,14 @@ module Packages end def group_projects_visible_to_current_user + # according to project_policy.rb + # access to packages is ruled by: + # - project is public or the current user has access to it with at least the reporter level + # - the repository feature is available to the current_user ::Project .in_namespace(groups) .public_or_visible_to_user(current_user, Gitlab::Access::REPORTER) - .with_project_feature - .select { |project| Ability.allowed?(current_user, :read_package, project) } + .with_feature_available_for_user(:repository, current_user) end def package_type diff --git a/app/finders/packages/npm/package_finder.rb b/app/finders/packages/npm/package_finder.rb index 8599fd07e7f..2854226e178 100644 --- a/app/finders/packages/npm/package_finder.rb +++ b/app/finders/packages/npm/package_finder.rb @@ -12,6 +12,8 @@ module Packages end def execute + return Packages::Package.none unless project + packages end diff --git a/app/finders/personal_access_tokens_finder.rb b/app/finders/personal_access_tokens_finder.rb index 93f8c520b63..4a6eed8f5ee 100644 --- a/app/finders/personal_access_tokens_finder.rb +++ b/app/finders/personal_access_tokens_finder.rb @@ -14,6 +14,7 @@ class PersonalAccessTokensFinder tokens = PersonalAccessToken.all tokens = by_current_user(tokens) tokens = by_user(tokens) + tokens = by_users(tokens) tokens = by_impersonation(tokens) tokens = by_state(tokens) @@ -37,6 +38,12 @@ class PersonalAccessTokensFinder tokens.for_user(@params[:user]) end + def by_users(tokens) + return tokens unless @params[:users] + + tokens.for_users(@params[:users]) + end + def sort(tokens) available_sort_orders = PersonalAccessToken.simple_sorts.keys diff --git a/app/finders/security/jobs_finder.rb b/app/finders/security/jobs_finder.rb new file mode 100644 index 00000000000..e2efb2e18c9 --- /dev/null +++ b/app/finders/security/jobs_finder.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# Security::JobsFinder +# +# Abstract class encapsulating common logic for finding jobs (builds) that are related to the Secure products +# SAST, DAST, Dependency Scanning, Container Scanning and License Management, Coverage Fuzzing +# +# Arguments: +# params: +# pipeline: required, only jobs for the specified pipeline will be found +# job_types: required, array of job types that should be returned, defaults to all job types + +module Security + class JobsFinder + attr_reader :pipeline + + def self.allowed_job_types + # Example return: [:sast, :dast, :dependency_scanning, :container_scanning, :license_management, :coverage_fuzzing] + raise NotImplementedError, 'allowed_job_types must be overwritten to return an array of job types' + end + + def initialize(pipeline:, job_types: []) + if self.class == Security::JobsFinder + raise NotImplementedError, 'This is an abstract class, please instantiate its descendants' + end + + if job_types.empty? + @job_types = self.class.allowed_job_types + elsif valid_job_types?(job_types) + @job_types = job_types + else + raise ArgumentError, "job_types must be from the following: #{self.class.allowed_job_types}" + end + + @pipeline = pipeline + end + + def execute + return [] if @job_types.empty? + + if Feature.enabled?(:ci_build_metadata_config) + find_jobs + else + find_jobs_legacy + end + end + + private + + def find_jobs + @pipeline.builds.with_secure_reports_from_config_options(@job_types) + end + + def find_jobs_legacy + # the query doesn't guarantee accuracy, so we verify it here + legacy_jobs_query.select do |job| + @job_types.find { |job_type| job.options.dig(:artifacts, :reports, job_type) } + end + end + + def legacy_jobs_query + @job_types.map do |job_type| + @pipeline.builds.with_secure_reports_from_options(job_type) + end.reduce(&:or) + end + + def valid_job_types?(job_types) + (job_types - self.class.allowed_job_types).empty? + end + end +end diff --git a/app/finders/security/license_compliance_jobs_finder.rb b/app/finders/security/license_compliance_jobs_finder.rb new file mode 100644 index 00000000000..100f94b2cc7 --- /dev/null +++ b/app/finders/security/license_compliance_jobs_finder.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Security::LicenseScanningJobsFinder +# +# Used to find jobs (builds) that are related to the License Management. +# +# Arguments: +# params: +# pipeline: required, only jobs for the specified pipeline will be found +# job_types: required, array of job types that should be returned, defaults to all job types + +module Security + class LicenseComplianceJobsFinder < JobsFinder + def self.allowed_job_types + [:license_management, :license_scanning] + end + end +end diff --git a/app/finders/security/security_jobs_finder.rb b/app/finders/security/security_jobs_finder.rb new file mode 100644 index 00000000000..2352e19c7da --- /dev/null +++ b/app/finders/security/security_jobs_finder.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Security::SecurityJobsFinder +# +# Used to find jobs (builds) that are related to the Secure products: +# SAST, DAST, Dependency Scanning and Container Scanning +# +# Arguments: +# params: +# pipeline: required, only jobs for the specified pipeline will be found +# job_types: required, array of job types that should be returned, defaults to all job types + +module Security + class SecurityJobsFinder < JobsFinder + def self.allowed_job_types + [:sast, :dast, :dependency_scanning, :container_scanning, :secret_detection, :coverage_fuzzing, :api_fuzzing] + end + end +end diff --git a/app/finders/user_groups_counter.rb b/app/finders/user_groups_counter.rb new file mode 100644 index 00000000000..7dbc8502be2 --- /dev/null +++ b/app/finders/user_groups_counter.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class UserGroupsCounter + def initialize(user_ids) + @user_ids = user_ids + end + + def execute + Namespace.unscoped do + Namespace.from_union([ + groups, + project_groups + ]).group(:user_id).count # rubocop: disable CodeReuse/ActiveRecord + end + end + + private + + attr_reader :user_ids + + def groups + Group.for_authorized_group_members(user_ids) + .select('namespaces.*, members.user_id as user_id') + end + + def project_groups + Group.for_authorized_project_members(user_ids) + .select('namespaces.*, project_authorizations.user_id as user_id') + end +end |