diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml index 03ef2924617c002611dc1d961ed2236000ffd8cd..c07bafbe302edad52381240f43a2932694ce4be5 100644 --- a/app/views/admin/application_settings/_visibility_and_access.html.haml +++ b/app/views/admin/application_settings/_visibility_and_access.html.haml @@ -8,6 +8,7 @@ .form-group = f.label s_('ProjectCreationLevel|Default project creation protection'), class: 'label-bold' = f.select :default_project_creation, options_for_select(Gitlab::Access.project_creation_options, @application_setting.default_project_creation), {}, class: 'form-control' + = render_if_exists 'admin/application_settings/default_project_deletion_protection_setting', form: f .form-group.visibility-level-setting = f.label :default_project_visibility, class: 'label-bold' = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new) diff --git a/changelogs/unreleased/5615-non-admins-only-archieve-ce.yml b/changelogs/unreleased/5615-non-admins-only-archieve-ce.yml new file mode 100644 index 0000000000000000000000000000000000000000..ac1aa249b8291c9bc7b4b42cfe79babd0f6aabec --- /dev/null +++ b/changelogs/unreleased/5615-non-admins-only-archieve-ce.yml @@ -0,0 +1,5 @@ +--- +title: Add deletion protection setting column to application_settings table +merge_request: 29268 +author: +type: other diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index b5fa0a4ab6173be4b70ba0b19dd76f84b6d96361..cca195d7118437530a7eaede60aa1a7b649dd3cb 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -138,6 +138,7 @@ Settings['issues_tracker'] ||= {} # Settings['gitlab'] ||= Settingslogic.new({}) Settings.gitlab['default_project_creation'] ||= ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS +Settings.gitlab['default_project_deletion_protection'] ||= false Settings.gitlab['default_projects_limit'] ||= 100000 Settings.gitlab['default_branch_protection'] ||= 2 Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil? diff --git a/db/migrate/20190605104727_add_default_project_deletion_protection_to_application_settings.rb b/db/migrate/20190605104727_add_default_project_deletion_protection_to_application_settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..ee04b49813b9d04569c96bbfbfd54c38ecd0d846 --- /dev/null +++ b/db/migrate/20190605104727_add_default_project_deletion_protection_to_application_settings.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddDefaultProjectDeletionProtectionToApplicationSettings < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default :application_settings, :default_project_deletion_protection, :boolean, default: false, allow_null: false + end + + def down + remove_column :application_settings, :default_project_deletion_protection + end +end diff --git a/db/schema.rb b/db/schema.rb index 473fc1e1050f98b94b82d5b8c7560b4a967f7d48..3365005cb84342a13e9f291e5986d394c57dd76d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -226,6 +226,7 @@ ActiveRecord::Schema.define(version: 20190611161641) do t.text "encrypted_lets_encrypt_private_key" t.text "encrypted_lets_encrypt_private_key_iv" t.boolean "dns_rebinding_protection_enabled", default: true, null: false + t.boolean "default_project_deletion_protection", default: false, null: false t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id", using: :btree t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id", using: :btree t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree diff --git a/ee/app/controllers/ee/admin/application_settings_controller.rb b/ee/app/controllers/ee/admin/application_settings_controller.rb index 7d22c4a8b60e9db2432be4a0b7f7e1a15015182a..15cb56db8479a71449c2ec7ea6f49a32cc254c0c 100644 --- a/ee/app/controllers/ee/admin/application_settings_controller.rb +++ b/ee/app/controllers/ee/admin/application_settings_controller.rb @@ -26,6 +26,10 @@ module EE attrs << :pseudonymizer_enabled end + if License.feature_available?(:default_project_deletion_protection) + attrs << :default_project_deletion_protection + end + attrs end end diff --git a/ee/app/helpers/ee/application_settings_helper.rb b/ee/app/helpers/ee/application_settings_helper.rb index c8813a7c7413a3c6bca1ba8db0036555b7c18b07..8a97ae43c8ccc5ec036308e0c4a4da80571d9c18 100644 --- a/ee/app/helpers/ee/application_settings_helper.rb +++ b/ee/app/helpers/ee/application_settings_helper.rb @@ -75,6 +75,7 @@ module EE repository_mirror_attributes + %i[ email_additional_text file_template_project_id + default_project_deletion_protection ] end end diff --git a/ee/app/models/ee/application_setting.rb b/ee/app/models/ee/application_setting.rb index 48a59d397e52ac2f32febbf6293fec282728bbca..faf7bd481636102d2cfe71de8f0219d529aeb230 100644 --- a/ee/app/models/ee/application_setting.rb +++ b/ee/app/models/ee/application_setting.rb @@ -75,6 +75,7 @@ module EE def defaults super.merge( allow_group_owners_to_manage_ldap: true, + default_project_deletion_protection: false, elasticsearch_aws: false, elasticsearch_aws_region: ENV['ELASTIC_REGION'] || 'us-east-1', elasticsearch_replicas: 1, diff --git a/ee/app/models/license.rb b/ee/app/models/license.rb index d458e867a3ecb960248b3702b7f475fa1d9208aa..c8ae07ed7d1b2f95acc9cfe208f3b354fc4a304c 100644 --- a/ee/app/models/license.rb +++ b/ee/app/models/license.rb @@ -69,6 +69,7 @@ class License < ApplicationRecord reject_unsigned_commits commit_committer_check ci_cd_projects + default_project_deletion_protection protected_environments custom_project_templates group_project_templates diff --git a/ee/app/policies/ee/project_policy.rb b/ee/app/policies/ee/project_policy.rb index 4b1c7ccaa41f0ed7c4e731c711efb24b0e940ba1..dc592d531f04349c47464d204e633990b64ab74a 100644 --- a/ee/app/policies/ee/project_policy.rb +++ b/ee/app/policies/ee/project_policy.rb @@ -210,6 +210,8 @@ module EE rule { owner | reporter }.enable :build_read_project + rule { ~admin & owner & owner_cannot_destroy_project }.prevent :remove_project + rule { archived }.policy do READONLY_FEATURES_WHEN_ARCHIVED.each do |feature| prevent(*::ProjectPolicy.create_update_admin_destroy(feature)) @@ -228,6 +230,11 @@ module EE ::Gitlab::Auth::GroupSaml::SsoEnforcer.group_access_restricted?(subject.group) end + condition(:owner_cannot_destroy_project) do + ::Gitlab::CurrentSettings.current_application_settings + .default_project_deletion_protection + end + rule { web_ide_terminal_available & can?(:create_pipeline) & can?(:maintainer_access) }.enable :create_web_ide_terminal # Design abilities could also be prevented in the issue policy. diff --git a/ee/app/views/admin/application_settings/_default_project_deletion_protection_setting.html.haml b/ee/app/views/admin/application_settings/_default_project_deletion_protection_setting.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..494aed18d5bddb72ff63e0763d6982a9926875c1 --- /dev/null +++ b/ee/app/views/admin/application_settings/_default_project_deletion_protection_setting.html.haml @@ -0,0 +1,10 @@ +- return unless License.feature_available?(:default_project_deletion_protection) + +- f = local_assigns.fetch(:form) + +.form-group + = f.label s_('Default project deletion protection'), class: 'label-bold' + .form-check + = f.check_box :default_project_deletion_protection, class: 'form-check-input' + = f.label :default_project_deletion_protection, class: 'form-check-label' do + = _('Only admins can delete project') diff --git a/ee/changelogs/unreleased/5615-non-admins-only-archieve.yml b/ee/changelogs/unreleased/5615-non-admins-only-archieve.yml new file mode 100644 index 0000000000000000000000000000000000000000..9f2eb8d40eed0c5fa0655469257c63dd4a9bbb1d --- /dev/null +++ b/ee/changelogs/unreleased/5615-non-admins-only-archieve.yml @@ -0,0 +1,5 @@ +--- +title: Add Admin settings to disable project deletion +merge_request: 14002 +author: +type: added diff --git a/ee/lib/ee/api/entities.rb b/ee/lib/ee/api/entities.rb index 62adbe9a8edddfd72843d1e01db3668cc44757b9..bf58fc7f8390aff20a66ee266ac8db3e4d9732d1 100644 --- a/ee/lib/ee/api/entities.rb +++ b/ee/lib/ee/api/entities.rb @@ -158,6 +158,7 @@ module EE end) expose :email_additional_text, if: ->(_instance, _opts) { ::License.feature_available?(:email_additional_text) } expose :file_template_project_id, if: ->(_instance, _opts) { ::License.feature_available?(:custom_file_templates) } + expose :default_project_deletion_protection, if: ->(_instance, _opts) { ::License.feature_available?(:default_project_deletion_protection) } end end diff --git a/ee/lib/ee/api/helpers/settings_helpers.rb b/ee/lib/ee/api/helpers/settings_helpers.rb index f11551bb6464baf6fef41bf0c42658e173c56349..e9b9cc95ad0649617ba5c298977ea9ecaa35ec9f 100644 --- a/ee/lib/ee/api/helpers/settings_helpers.rb +++ b/ee/lib/ee/api/helpers/settings_helpers.rb @@ -30,6 +30,7 @@ module EE end optional :email_additional_text, type: String, desc: 'Additional text added to the bottom of every email for legal/auditing/compliance reasons' + optional :default_project_deletion_protection, type: Grape::API::Boolean, desc: 'Disable project owners ability to delete project' optional :help_text, type: String, desc: 'GitLab server administrator information' optional :repository_size_limit, type: Integer, desc: 'Size limit per repository (MB)' optional :file_template_project_id, type: Integer, desc: 'ID of project where instance-level file templates are stored.' diff --git a/ee/lib/ee/api/settings.rb b/ee/lib/ee/api/settings.rb index 5577b47520ef643abe96aca12b77ae3e9ddfea6e..5e398b0b14e593b7ed146db0867787e392bbb13e 100644 --- a/ee/lib/ee/api/settings.rb +++ b/ee/lib/ee/api/settings.rb @@ -24,6 +24,10 @@ module EE attrs = attrs.except(:file_template_project_id) end + unless ::License.feature_available?(:default_project_deletion_protection) + attrs = attrs.except(:default_project_deletion_protection) + end + attrs end # rubocop: enable CodeReuse/ActiveRecord diff --git a/ee/spec/controllers/admin/application_settings_controller_spec.rb b/ee/spec/controllers/admin/application_settings_controller_spec.rb index 476138c9bd19b88f7d681466cee8e5d89e30ba8c..6117349acfe8bf5e565078b0df46d71acf7ce1d8 100644 --- a/ee/spec/controllers/admin/application_settings_controller_spec.rb +++ b/ee/spec/controllers/admin/application_settings_controller_spec.rb @@ -81,6 +81,13 @@ describe Admin::ApplicationSettingsController do it_behaves_like 'settings for licensed features' end + context 'default project deletion protection' do + let(:settings) { { default_project_deletion_protection: true } } + let(:feature) { :default_project_deletion_protection } + + it_behaves_like 'settings for licensed features' + end + context 'additional email footer' do let(:settings) { { email_additional_text: 'scary legal footer' } } let(:feature) { :email_additional_text } diff --git a/ee/spec/policies/project_policy_spec.rb b/ee/spec/policies/project_policy_spec.rb index d6b0c21e24df0fc9101c8d9e3882613b605ea4a0..1b08177f1a10499db06d4bd1016344859a1b5bb2 100644 --- a/ee/spec/policies/project_policy_spec.rb +++ b/ee/spec/policies/project_policy_spec.rb @@ -451,6 +451,31 @@ describe ProjectPolicy do end end + describe 'remove_project when default_project_deletion_protection is set to true' do + before do + allow(Gitlab::CurrentSettings.current_application_settings) + .to receive(:default_project_deletion_protection) { true } + end + + context 'with admin' do + let(:current_user) { admin } + + it { is_expected.to be_allowed(:remove_project) } + + context 'who owns the project' do + let(:project) { create(:project, :public, namespace: admin.namespace) } + + it { is_expected.to be_allowed(:remove_project) } + end + end + + context 'with owner' do + let(:current_user) { owner } + + it { is_expected.to be_disallowed(:remove_project) } + end + end + describe 'read_feature_flag' do context 'with admin' do let(:current_user) { admin } diff --git a/ee/spec/requests/api/settings_spec.rb b/ee/spec/requests/api/settings_spec.rb index 4f4fdc0c5f735c24e4b6e3a671228b7d1b113337..ebb44d45d7a2108136e5fb1d6b46fe804898bde0 100644 --- a/ee/spec/requests/api/settings_spec.rb +++ b/ee/spec/requests/api/settings_spec.rb @@ -142,6 +142,13 @@ describe API::Settings, 'EE Settings' do it_behaves_like 'settings for licensed features' end + context 'default project deletion protection' do + let(:settings) { { default_project_deletion_protection: true } } + let(:feature) { :default_project_deletion_protection } + + it_behaves_like 'settings for licensed features' + end + context 'custom file template project' do let(:settings) { { file_template_project_id: project.id } } let(:feature) { :custom_file_templates } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 3313f62fd309e52beb654a78da91d0ae424ba113..2e4f40067ce39e7e80b08efc098e74c9f68a862d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3982,6 +3982,9 @@ msgstr "" msgid "Default issue template" msgstr "" +msgid "Default project deletion protection" +msgstr "" + msgid "Default: Directly import the Google Code email address or username" msgstr "" @@ -9059,6 +9062,9 @@ msgstr "" msgid "Only admins" msgstr "" +msgid "Only admins can delete project" +msgstr "" + msgid "Only mirror protected branches" msgstr ""