diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-01 12:17:48 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-01 12:17:48 +0000 |
commit | cbce607eef01db76e6923ce684aa31af248c004d (patch) | |
tree | 172e75a56c6ec5d2c6bc61eb545d712d971b489b /app | |
parent | d27481e8f3dd252b543f65cb56a98eeb00de855f (diff) | |
download | gitlab-ce-cbce607eef01db76e6923ce684aa31af248c004d.tar.gz |
Add latest changes from gitlab-org/security/gitlab@15-11-stable-ee
Diffstat (limited to 'app')
22 files changed, 113 insertions, 23 deletions
diff --git a/app/assets/javascripts/import_entities/components/group_dropdown.vue b/app/assets/javascripts/import_entities/components/group_dropdown.vue index 5b9e80f9d68..1c31c04a416 100644 --- a/app/assets/javascripts/import_entities/components/group_dropdown.vue +++ b/app/assets/javascripts/import_entities/components/group_dropdown.vue @@ -4,7 +4,7 @@ import { debounce } from 'lodash'; import { s__ } from '~/locale'; import { createAlert } from '~/alert'; -import searchNamespacesWhereUserCanCreateProjectsQuery from '~/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql'; +import searchNamespacesWhereUserCanImportProjectsQuery from '~/import_entities/import_projects/graphql/queries/search_namespaces_where_user_can_import_projects.query.graphql'; import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants'; import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; @@ -28,7 +28,7 @@ export default { }, apollo: { namespaces: { - query: searchNamespacesWhereUserCanCreateProjectsQuery, + query: searchNamespacesWhereUserCanImportProjectsQuery, variables() { return { search: this.searchTerm, diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue index 2e6e7cddf8f..246d27d3b94 100644 --- a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue +++ b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue @@ -24,7 +24,7 @@ import { getGroupPathAvailability } from '~/rest_api'; import axios from '~/lib/utils/axios_utils'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import { helpPagePath } from '~/helpers/help_page_helper'; -import searchNamespacesWhereUserCanCreateProjectsQuery from '~/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql'; +import searchNamespacesWhereUserCanImportProjectsQuery from '~/import_entities/import_projects/graphql/queries/search_namespaces_where_user_can_import_projects.query.graphql'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { STATUSES } from '../../constants'; @@ -118,7 +118,7 @@ export default { }, }, availableNamespaces: { - query: searchNamespacesWhereUserCanCreateProjectsQuery, + query: searchNamespacesWhereUserCanImportProjectsQuery, update(data) { return data.currentUser.groups.nodes; }, diff --git a/app/assets/javascripts/import_entities/import_projects/graphql/queries/search_namespaces_where_user_can_import_projects.query.graphql b/app/assets/javascripts/import_entities/import_projects/graphql/queries/search_namespaces_where_user_can_import_projects.query.graphql new file mode 100644 index 00000000000..8c41f7116b3 --- /dev/null +++ b/app/assets/javascripts/import_entities/import_projects/graphql/queries/search_namespaces_where_user_can_import_projects.query.graphql @@ -0,0 +1,18 @@ +query searchNamespacesWhereUserCanImportProjects($search: String) { + currentUser { + id + groups(permissionScope: IMPORT_PROJECTS, search: $search) { + nodes { + id + fullPath + name + visibility + webUrl + } + } + namespace { + id + fullPath + } + } +} diff --git a/app/assets/javascripts/projects/new/components/app.vue b/app/assets/javascripts/projects/new/components/app.vue index 0a160a357e5..2f58d4468be 100644 --- a/app/assets/javascripts/projects/new/components/app.vue +++ b/app/assets/javascripts/projects/new/components/app.vue @@ -9,6 +9,7 @@ import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue' import NewProjectPushTipPopover from './new_project_push_tip_popover.vue'; const CI_CD_PANEL = 'cicd_for_external_repo'; +const IMPORT_PROJECT_PANEL = 'import_project'; const PANELS = [ { key: 'blank', @@ -32,7 +33,7 @@ const PANELS = [ }, { key: 'import', - name: 'import_project', + name: IMPORT_PROJECT_PANEL, selector: '#import-project-pane', title: s__('ProjectsNew|Import project'), description: s__( @@ -92,6 +93,11 @@ export default { required: false, default: '', }, + canImportProjects: { + type: Boolean, + required: false, + default: true, + }, }, computed: { @@ -106,7 +112,21 @@ export default { return breadcrumbs; }, availablePanels() { - return this.isCiCdAvailable ? PANELS : PANELS.filter((p) => p.name !== CI_CD_PANEL); + if (this.isCiCdAvailable && this.canImportProjects) { + return PANELS; + } + + return PANELS.filter((panel) => { + if (!this.canImportProjects && panel.name === IMPORT_PROJECT_PANEL) { + return false; + } + + if (!this.isCiCdAvailable && panel.name === CI_CD_PANEL) { + return false; + } + + return true; + }); }, }, diff --git a/app/assets/javascripts/projects/new/index.js b/app/assets/javascripts/projects/new/index.js index 5ec50355a82..a5a833dc73b 100644 --- a/app/assets/javascripts/projects/new/index.js +++ b/app/assets/javascripts/projects/new/index.js @@ -19,6 +19,7 @@ export function initNewProjectCreation() { parentGroupName, projectsUrl, rootPath, + canImportProjects, } = el.dataset; const props = { @@ -29,6 +30,7 @@ export function initNewProjectCreation() { parentGroupName, projectsUrl, rootPath, + canImportProjects: parseBoolean(canImportProjects), }; const provide = { diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index 7ef07032913..bcb6aed9e38 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -18,7 +18,7 @@ class Import::BaseController < ApplicationController if params[:namespace_id]&.present? @namespace = Namespace.find_by_id(params[:namespace_id]) - render_404 unless current_user.can?(:create_projects, @namespace) + render_404 unless current_user.can?(:import_projects, @namespace) end end end diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb index 8a0f4a36781..c933b05e0c4 100644 --- a/app/controllers/import/bitbucket_controller.rb +++ b/app/controllers/import/bitbucket_controller.rb @@ -57,7 +57,7 @@ class Import::BitbucketController < Import::BaseController extra: { user_role: user_role(current_user, target_namespace), import_type: 'bitbucket' } ) - if current_user.can?(:create_projects, target_namespace) + if current_user.can?(:import_projects, target_namespace) # The token in a session can be expired, we need to get most recent one because # Bitbucket::Connection class refreshes it. session[:bitbucket_token] = bitbucket_client.connection.token @@ -70,7 +70,7 @@ class Import::BitbucketController < Import::BaseController render json: { errors: project_save_error(project) }, status: :unprocessable_entity end else - render json: { errors: _('This namespace has already been taken! Please choose another one.') }, status: :unprocessable_entity + render json: { errors: _('You are not allowed to import projects in this namespace.') }, status: :unprocessable_entity end end diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb index 047c273969c..2778b97419a 100644 --- a/app/controllers/import/gitea_controller.rb +++ b/app/controllers/import/gitea_controller.rb @@ -32,7 +32,7 @@ class Import::GiteaController < Import::GithubController if params[:namespace_id].present? @namespace = Namespace.find_by_id(params[:namespace_id]) - render_404 unless current_user.can?(:create_projects, @namespace) + render_404 unless current_user.can?(:import_projects, @namespace) end end end diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index bd0c0976729..719cd61e538 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -65,7 +65,7 @@ class Import::GithubController < Import::BaseController if params[:namespace_id].present? @namespace = Namespace.find_by_id(params[:namespace_id]) - render_404 unless current_user.can?(:create_projects, @namespace) + render_404 unless current_user.can?(:import_projects, @namespace) end end end diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index 9b8c480e529..d1b182a57d8 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -8,7 +8,7 @@ class Import::GitlabProjectsController < Import::BaseController def new @namespace = Namespace.find(project_params[:namespace_id]) - return render_404 unless current_user.can?(:create_projects, @namespace) + return render_404 unless current_user.can?(:import_projects, @namespace) @path = project_params[:path] end diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb index 461ba982969..03884717e54 100644 --- a/app/controllers/import/manifest_controller.rb +++ b/app/controllers/import/manifest_controller.rb @@ -20,8 +20,8 @@ class Import::ManifestController < Import::BaseController def upload group = Group.find(params[:group_id]) - unless can?(current_user, :create_projects, group) - @errors = ["You don't have enough permissions to create projects in the selected group"] + unless can?(current_user, :import_projects, group) + @errors = ["You don't have enough permissions to import projects in the selected group"] render :new && return end diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb index 41daeddcf7f..208fbc40556 100644 --- a/app/controllers/projects/imports_controller.rb +++ b/app/controllers/projects/imports_controller.rb @@ -56,7 +56,7 @@ class Projects::ImportsController < Projects::ApplicationController end def require_namespace_project_creation_permission - render_404 unless can?(current_user, :admin_project, @project) || can?(current_user, :create_projects, @project.namespace) + render_404 unless can?(current_user, :admin_project, @project) || can?(current_user, :import_projects, @project.namespace) end def redirect_if_progress diff --git a/app/finders/groups/accepting_project_imports_finder.rb b/app/finders/groups/accepting_project_imports_finder.rb new file mode 100644 index 00000000000..55d72edf7bb --- /dev/null +++ b/app/finders/groups/accepting_project_imports_finder.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Groups + class AcceptingProjectImportsFinder + def initialize(current_user) + @current_user = current_user + end + + def execute + ::Group.from_union( + [ + current_user.manageable_groups, + managable_groups_originating_from_group_shares + ] + ) + end + + private + + attr_reader :current_user + + def managable_groups_originating_from_group_shares + GroupGroupLink + .with_owner_or_maintainer_access + .groups_accessible_via( + current_user.owned_or_maintainers_groups + .select(:id) + ) + end + end +end diff --git a/app/finders/groups/user_groups_finder.rb b/app/finders/groups/user_groups_finder.rb index 83e012b3dbe..536b81b2300 100644 --- a/app/finders/groups/user_groups_finder.rb +++ b/app/finders/groups/user_groups_finder.rb @@ -39,6 +39,8 @@ module Groups Groups::AcceptingProjectCreationsFinder.new(target_user).execute # rubocop: disable CodeReuse/Finder elsif permission_scope_transfer_projects? Groups::AcceptingProjectTransfersFinder.new(target_user).execute # rubocop: disable CodeReuse/Finder + elsif permission_scope_import_projects? + Groups::AcceptingProjectImportsFinder.new(target_user).execute # rubocop: disable CodeReuse/Finder else target_user.groups end @@ -51,5 +53,9 @@ module Groups def permission_scope_transfer_projects? params[:permission_scope] == :transfer_projects end + + def permission_scope_import_projects? + params[:permission_scope] == :import_projects + end end end diff --git a/app/graphql/types/permission_types/group_enum.rb b/app/graphql/types/permission_types/group_enum.rb index f636d43790f..6d51d94a70d 100644 --- a/app/graphql/types/permission_types/group_enum.rb +++ b/app/graphql/types/permission_types/group_enum.rb @@ -10,6 +10,9 @@ module Types value 'TRANSFER_PROJECTS', value: :transfer_projects, description: 'Groups where the user can transfer projects to.' + value 'IMPORT_PROJECTS', + value: :import_projects, + description: 'Groups where the user can import projects to.' end end end diff --git a/app/policies/namespaces/user_namespace_policy.rb b/app/policies/namespaces/user_namespace_policy.rb index 1deeae8241f..bfed61e72d3 100644 --- a/app/policies/namespaces/user_namespace_policy.rb +++ b/app/policies/namespaces/user_namespace_policy.rb @@ -11,6 +11,7 @@ module Namespaces rule { owner | admin }.policy do enable :owner_access enable :create_projects + enable :import_projects enable :admin_namespace enable :read_namespace enable :read_statistics @@ -20,9 +21,9 @@ module Namespaces enable :edit_billing end - rule { ~can_create_personal_project }.prevent :create_projects + rule { ~can_create_personal_project }.prevent :create_projects, :import_projects - rule { bot_user_namespace }.prevent :create_projects + rule { bot_user_namespace }.prevent :create_projects, :import_projects rule { (owner | admin) & can?(:create_projects) }.enable :transfer_projects end diff --git a/app/services/import/base_service.rb b/app/services/import/base_service.rb index 6b5adcbc39e..64cf3cfa04a 100644 --- a/app/services/import/base_service.rb +++ b/app/services/import/base_service.rb @@ -9,7 +9,7 @@ module Import end def authorized? - can?(current_user, :create_projects, target_namespace) + can?(current_user, :import_projects, target_namespace) end private diff --git a/app/services/import/bitbucket_server_service.rb b/app/services/import/bitbucket_server_service.rb index f7f17f1e53e..5d496dc7cc3 100644 --- a/app/services/import/bitbucket_server_service.rb +++ b/app/services/import/bitbucket_server_service.rb @@ -10,7 +10,7 @@ module Import end unless authorized? - return log_and_return_error("You don't have permissions to create this project", :unauthorized) + return log_and_return_error("You don't have permissions to import this project", :unauthorized) end unless repo diff --git a/app/services/import/fogbugz_service.rb b/app/services/import/fogbugz_service.rb index d1003823456..9a8def43312 100644 --- a/app/services/import/fogbugz_service.rb +++ b/app/services/import/fogbugz_service.rb @@ -13,8 +13,8 @@ module Import unless authorized? return log_and_return_error( - "You don't have permissions to create this project", - _("You don't have permissions to create this project"), + "You don't have permissions to import this project", + _("You don't have permissions to import this project"), :unauthorized ) end diff --git a/app/services/import/github_service.rb b/app/services/import/github_service.rb index b30c344723d..7e7f7ea9810 100644 --- a/app/services/import/github_service.rb +++ b/app/services/import/github_service.rb @@ -103,7 +103,7 @@ module Import elsif target_namespace.nil? error(_('Namespace or group to import repository into does not exist.'), :unprocessable_entity) elsif !authorized? - error(_('This namespace has already been taken. Choose a different one.'), :unprocessable_entity) + error(_('You are not allowed to import projects in this namespace.'), :unprocessable_entity) elsif oversized? error(oversize_error_message, :unprocessable_entity) end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index cbea44d6aff..63b050faf9c 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -58,6 +58,7 @@ module Projects return @project if @project.errors.any? validate_create_permissions + validate_import_permissions return @project if @project.errors.any? @relations_block&.call(@project) @@ -98,6 +99,13 @@ module Projects @project.errors.add(:namespace, "is not valid") end + def validate_import_permissions + return unless @project.import? + return if current_user.can?(:import_projects, parent_namespace) + + @project.errors.add(:user, 'is not allowed to import projects') + end + def after_create_actions log_info("#{current_user.name} created a new project \"#{@project.full_name}\"") diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index e64ed2c7b8f..52ac8b58c9a 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -17,7 +17,8 @@ root_path: root_path, parent_group_url: @project.parent && group_url(@project.parent), parent_group_name: @project.parent&.name, - projects_url: dashboard_projects_url } } + projects_url: dashboard_projects_url, + can_import_projects: params[:namespace_id].presence ? current_user.can?(:import_projects, @namespace).to_s : 'true' } } .row{ 'v-cloak': true } #blank-project-pane.tab-pane.active |