diff options
Diffstat (limited to 'lib/gitlab/project_authorizations.rb')
-rw-r--r-- | lib/gitlab/project_authorizations.rb | 140 |
1 files changed, 89 insertions, 51 deletions
diff --git a/lib/gitlab/project_authorizations.rb b/lib/gitlab/project_authorizations.rb index c770260a66e..0fcb8321dae 100644 --- a/lib/gitlab/project_authorizations.rb +++ b/lib/gitlab/project_authorizations.rb @@ -12,62 +12,56 @@ module Gitlab end def calculate - cte = if Feature.enabled?(:linear_project_authorization, user) - linear_cte - else - recursive_cte - end - - cte_alias = cte.table.alias(Group.table_name) - projects = Project.arel_table - links = ProjectGroupLink.arel_table - - relations = [ - # The project a user has direct access to. - user.projects_with_active_memberships.select_for_project_authorization, - - # The personal projects of the user. - user.personal_projects.select_project_owner_for_project_authorization, + if Feature.enabled?(:compare_project_authorization_linear_cte, user) + linear_relation = calculate_with_linear_query + recursive_relation = calculate_with_recursive_query + recursive_set = Set.new(recursive_relation.to_a.pluck(:project_id, :access_level)) + linear_set = Set.new(linear_relation.to_a.pluck(:project_id, :access_level)) + if linear_set == recursive_set + Gitlab::AppJsonLogger.info(event: 'linear_authorized_projects_check', + user_id: user.id, + matching_results: true) + return calculate_with_linear_query + else + Gitlab::AppJsonLogger.warn(event: 'linear_authorized_projects_check', + user_id: user.id, + matching_results: false) + end + end - # Projects that belong directly to any of the groups the user has - # access to. - Namespace - .unscoped - .select([alias_as_column(projects[:id], 'project_id'), - cte_alias[:access_level]]) - .from(cte_alias) - .joins(:projects), - - # Projects shared with any of the namespaces the user has access to. - Namespace - .unscoped - .select([ - links[:project_id], - least(cte_alias[:access_level], links[:group_access], 'access_level') - ]) - .from(cte_alias) - .joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id') - .joins('INNER JOIN projects ON projects.id = project_group_links.project_id') - .joins('INNER JOIN namespaces p_ns ON p_ns.id = projects.namespace_id') - .where('p_ns.share_with_group_lock IS FALSE') - ] + Gitlab::AppJsonLogger.info(event: 'linear_authorized_projects_check_with_flag', + feature_flag_status: Feature.enabled?(:linear_project_authorization, user)) if Feature.enabled?(:linear_project_authorization, user) - ProjectAuthorization - .unscoped - .with(cte.to_arel) - .select_from_union(relations) + calculate_with_linear_query else - ProjectAuthorization - .unscoped - .with - .recursive(cte.to_arel) - .select_from_union(relations) + calculate_with_recursive_query end end private + def calculate_with_linear_query + cte = linear_cte + cte_alias = cte.table.alias(Group.table_name) + + ProjectAuthorization + .unscoped + .with(cte.to_arel) + .select_from_union(relations(cte_alias: cte_alias)) + end + + def calculate_with_recursive_query + cte = recursive_cte + cte_alias = cte.table.alias(Group.table_name) + + ProjectAuthorization + .unscoped + .with + .recursive(cte.to_arel) + .select_from_union(relations(cte_alias: cte_alias)) + end + # Builds a recursive CTE that gets all the groups the current user has # access to, including any nested groups and any shared groups. def recursive_cte @@ -83,9 +77,11 @@ module Gitlab # Namespaces shared with any of the group cte << Group.select([namespaces[:id], - least(members[:access_level], - group_group_links[:group_access], - 'access_level')]) + least( + members[:access_level], + group_group_links[:group_access], + 'access_level' + )]) .joins(join_group_group_links) .joins(join_members_on_group_group_links) @@ -120,7 +116,9 @@ module Gitlab .merge(user.group_members) .merge(GroupMember.active_state) - union = Namespace.from_union([shared_groups, member_groups_with_ancestors]) + union = Namespace + .select("namespaces.id, access_level") + .from_union([shared_groups, member_groups_with_ancestors]) Gitlab::SQL::CTE.new(:linear_namespaces_cte, union) end @@ -185,5 +183,45 @@ module Gitlab def alias_as_column(value, alias_to) Arel::Nodes::As.new(value, Arel::Nodes::SqlLiteral.new(alias_to)) end + + def relations(cte_alias:) + [ + user.projects_with_active_memberships.select_for_project_authorization, + user.personal_projects.select_project_owner_for_project_authorization, + projects_belonging_directy_to_any_groups_user_has_access_to(cte_alias: cte_alias), + projects_shared_with_namespaces_user_has_access_to(cte_alias: cte_alias) + ] + end + + def projects_shared_with_namespaces_user_has_access_to(cte_alias:) + Namespace + .unscoped + .select([ + links[:project_id], + least(cte_alias[:access_level], links[:group_access], 'access_level') + ]) + .from(cte_alias) + .joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id') + .joins('INNER JOIN projects ON projects.id = project_group_links.project_id') + .joins('INNER JOIN namespaces p_ns ON p_ns.id = projects.namespace_id') + .where('p_ns.share_with_group_lock IS FALSE') + end + + def projects_belonging_directy_to_any_groups_user_has_access_to(cte_alias:) + Namespace + .unscoped + .select([alias_as_column(projects[:id], 'project_id'), + cte_alias[:access_level]]) + .from(cte_alias) + .joins(:projects) + end + + def projects + Project.arel_table + end + + def links + ProjectGroupLink.arel_table + end end end |