diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb index 5699925ae9df2e0892392fa9d2a58ad785884713..e6de6d4df5b675a2396f56ea39c78619a590c060 100644 --- a/app/controllers/groups/settings/ci_cd_controller.rb +++ b/app/controllers/groups/settings/ci_cd_controller.rb @@ -54,6 +54,7 @@ def update_auto_devops def authorize_show_cicd_settings! return if can_any?(current_user, [ :admin_cicd_variables, + :admin_protected_environments, :admin_runner ], group) diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index 21deac8b74cb8b73f5135ab44a550adbe568b0a3..3b3b5cb78a6a33159780542be8e87877a3e18314 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -113,6 +113,7 @@ def authorize_reset_cache! def authorize_show_cicd_settings! return if can_any?(current_user, [ :admin_cicd_variables, + :admin_protected_environments, :admin_runner ], project) diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 295cc0eb5e8b4b99ec3aee4d95205a49da15c6ca..b3e5f65e303e3ce2f85bebebc4543e2359fccd9c 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -283,6 +283,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy enable :admin_package enable :admin_runner enable :admin_integrations + enable :admin_protected_environments enable :change_visibility_level enable :read_usage_quotas diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 5fb962692920234d06e7743508647da3fb66673f..3c782fd7cce5d4c8759a8810462c0997e172668d 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -665,6 +665,7 @@ class ProjectPolicy < BasePolicy enable :change_restrict_user_defined_variables enable :create_protected_branch enable :admin_protected_branch + enable :admin_protected_environments end rule { can?(:manage_protected_tags) }.policy do diff --git a/app/validators/json_schemas/member_role_permissions.json b/app/validators/json_schemas/member_role_permissions.json index b365412c333be15f3e160b02ab71636cc8d8782a..dc5a9f81b96ca17cb2d7ce52f1da17b62e6e4c8b 100644 --- a/app/validators/json_schemas/member_role_permissions.json +++ b/app/validators/json_schemas/member_role_permissions.json @@ -22,6 +22,9 @@ "admin_protected_branch": { "type": "boolean" }, + "admin_protected_environments": { + "type": "boolean" + }, "admin_push_rules": { "type": "boolean" }, diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml index a066eee31f6d2abb5bc983de526d4068adfa8ef5..2ffb61291a6e1939e270b8f7b175bfa5c4069bf1 100644 --- a/app/views/groups/settings/ci_cd/show.html.haml +++ b/app/views/groups/settings/ci_cd/show.html.haml @@ -50,4 +50,5 @@ - c.with_body do = render 'groups/settings/ci_cd/auto_devops_form', group: @group +- if can?(current_user, :admin_protected_environments, @group) = render_if_exists 'groups/settings/ci_cd/protected_environments', expanded: expanded diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml index f36d4b5bf443ce78f25711c1238b0a887cbf87a1..1583f2ff3b120ca90f90081c50a244c753aa7688 100644 --- a/app/views/projects/settings/ci_cd/show.html.haml +++ b/app/views/projects/settings/ci_cd/show.html.haml @@ -29,6 +29,7 @@ - c.with_body do = render 'autodevops_form', auto_devops_enabled: @project.auto_devops_enabled? +- if can?(current_user, :admin_protected_environments, @project) = render_if_exists 'projects/settings/ci_cd/protected_environments', expanded: expanded - if can?(current_user, :admin_runner, @project) diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index a56622dc9936c20d17dde13a2fe2ee4f380f3373..025ef77dbf0e466c3feb14d0fa32a1692733685f 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -41214,6 +41214,7 @@ Member role permission. | `ADMIN_INTEGRATIONS` | Create, read, update, and delete integrations with external applications. | | `ADMIN_MERGE_REQUEST` | Allows approval of merge requests. | | `ADMIN_PROTECTED_BRANCH` | Create, read, update, and delete protected branches for a project. | +| `ADMIN_PROTECTED_ENVIRONMENTS` | Create, read, update, and delete environments. | | `ADMIN_PUSH_RULES` | Configure push rules for repositories at the group or project level. | | `ADMIN_RUNNERS` | Create, view, edit, and delete group or project Runners. Includes configuring Runner settings. | | `ADMIN_SECURITY_TESTING` | Edit and manage security testing configurations and settings. | @@ -41253,6 +41254,7 @@ Member role standard permission. | `ADMIN_INTEGRATIONS` | Create, read, update, and delete integrations with external applications. | | `ADMIN_MERGE_REQUEST` | Allows approval of merge requests. | | `ADMIN_PROTECTED_BRANCH` | Create, read, update, and delete protected branches for a project. | +| `ADMIN_PROTECTED_ENVIRONMENTS` | Create, read, update, and delete environments. | | `ADMIN_PUSH_RULES` | Configure push rules for repositories at the group or project level. | | `ADMIN_RUNNERS` | Create, view, edit, and delete group or project Runners. Includes configuring Runner settings. | | `ADMIN_SECURITY_TESTING` | Edit and manage security testing configurations and settings. | diff --git a/ee/app/controllers/groups/protected_environments_controller.rb b/ee/app/controllers/groups/protected_environments_controller.rb index 793999d888a83d262b28c528b4bb8d6c6da89aaa..7a2c4d7c613bc84b225c5b890ea20f18b2d157eb 100644 --- a/ee/app/controllers/groups/protected_environments_controller.rb +++ b/ee/app/controllers/groups/protected_environments_controller.rb @@ -2,7 +2,7 @@ module Groups class ProtectedEnvironmentsController < Groups::ApplicationController - before_action :authorize_admin_protected_environment! + before_action :authorize_admin_protected_environments! before_action :protected_environment, except: [:create] feature_category :continuous_delivery @@ -62,8 +62,8 @@ def deploy_access_level_attributes %i[id _destroy group_id] end - def authorize_admin_protected_environment! - not_found unless can?(current_user, :admin_protected_environment, group) + def authorize_admin_protected_environments! + not_found unless can?(current_user, :admin_protected_environments, group) end def serialized_protected_environment diff --git a/ee/app/controllers/projects/protected_environments_controller.rb b/ee/app/controllers/projects/protected_environments_controller.rb index 5044edd869f443906b13239d640d565d9d8d29c8..9279a2cc999265f4ee8db182d731b7d74fda0df4 100644 --- a/ee/app/controllers/projects/protected_environments_controller.rb +++ b/ee/app/controllers/projects/protected_environments_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true class Projects::ProtectedEnvironmentsController < Projects::ApplicationController - before_action :authorize_admin_project! + before_action :authorize_admin_protected_environments! before_action :protected_environment, except: [:create, :search] feature_category :continuous_delivery diff --git a/ee/app/policies/ee/group_policy.rb b/ee/app/policies/ee/group_policy.rb index d88d7393feb2de68a8dda646f5465cc8df48d578..3f05693d461ce8246c4c2de0350c30d53fa664ef 100644 --- a/ee/app/policies/ee/group_policy.rb +++ b/ee/app/policies/ee/group_policy.rb @@ -348,7 +348,7 @@ module GroupPolicy end rule { owner }.policy do - enable :admin_protected_environment + enable :admin_protected_environments enable :admin_licensed_seat end @@ -630,6 +630,10 @@ module GroupPolicy enable :admin_cicd_variables end + rule { custom_role_enables_admin_protected_environments }.policy do + enable :admin_protected_environments + end + rule { custom_role_enables_admin_compliance_framework }.policy do enable :admin_compliance_framework enable :admin_compliance_pipeline_configuration diff --git a/ee/app/policies/ee/project_policy.rb b/ee/app/policies/ee/project_policy.rb index 670c33a46f48da8bc46b77de28ba5cf6b1c05a6e..60236bce79f89845f5344ff3bb293c30661c091e 100644 --- a/ee/app/policies/ee/project_policy.rb +++ b/ee/app/policies/ee/project_policy.rb @@ -298,6 +298,10 @@ module ProjectPolicy enable :admin_cicd_variables end + rule { custom_role_enables_admin_protected_environments }.policy do + enable :admin_protected_environments + end + rule { custom_role_enables_admin_push_rules }.policy do enable :admin_push_rules end diff --git a/ee/config/custom_abilities/admin_protected_environments.yml b/ee/config/custom_abilities/admin_protected_environments.yml new file mode 100644 index 0000000000000000000000000000000000000000..7f45448bde3211759e6289470809b6a9b22e6f91 --- /dev/null +++ b/ee/config/custom_abilities/admin_protected_environments.yml @@ -0,0 +1,12 @@ +--- +title: Manage Protected Environments +name: admin_protected_environments +description: Create, read, update, and delete environments +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/471385 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178283 +feature_category: continuous_delivery +milestone: '17.9' +group_ability: true +enabled_for_group_access_levels: [50] +project_ability: true +enabled_for_project_access_levels: [40, 50] diff --git a/ee/config/feature_flags/wip/custom_ability_admin_protected_environments.yml b/ee/config/feature_flags/wip/custom_ability_admin_protected_environments.yml new file mode 100644 index 0000000000000000000000000000000000000000..7b8b9bbb25aaa07e0be8009d901541e9cd71886d --- /dev/null +++ b/ee/config/feature_flags/wip/custom_ability_admin_protected_environments.yml @@ -0,0 +1,9 @@ +--- +name: custom_ability_admin_protected_environments +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/471385 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178283 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/514698 +milestone: '17.9' +group: group::authorization +type: wip +default_enabled: false diff --git a/ee/lib/api/protected_environments.rb b/ee/lib/api/protected_environments.rb index c82f52cf90f13353d5b2c4b54a90b368b0332a93..ebfa03caf214aea28d828f36c000602b8ca1ebf9 100644 --- a/ee/lib/api/protected_environments.rb +++ b/ee/lib/api/protected_environments.rb @@ -97,7 +97,7 @@ def protected_environment end end - before { authorize_admin_project } + before { authorize! :admin_protected_environments, user_project } desc 'List protected environments' do detail 'Gets a list of protected environments from a project. This feature was introduced in GitLab 12.8.' @@ -232,7 +232,7 @@ def protected_environment end before do - authorize! :admin_protected_environment, user_group + authorize! :admin_protected_environments, user_group end desc 'List group-level protected environments' do diff --git a/ee/lib/ee/sidebars/groups/menus/settings_menu.rb b/ee/lib/ee/sidebars/groups/menus/settings_menu.rb index 26bd314b11521b14cefbeab2de0040655c53b639..e3fcb17bd599c9a35a9a90232e59ac22ba46011f 100644 --- a/ee/lib/ee/sidebars/groups/menus/settings_menu.rb +++ b/ee/lib/ee/sidebars/groups/menus/settings_menu.rb @@ -34,7 +34,8 @@ def configure_menu_items add_menu_item_for_abilities(integrations_menu_item, :admin_integrations) add_menu_item_for_abilities(access_tokens_menu_item, :read_resource_access_tokens) add_menu_item_for_abilities(repository_menu_item, [:admin_push_rules, :manage_deploy_tokens]) - add_menu_item_for_abilities(ci_cd_menu_item, [:admin_cicd_variables, :admin_runner]) + add_menu_item_for_abilities(ci_cd_menu_item, [:admin_cicd_variables, + :admin_protected_environments, :admin_runner]) add_menu_item_for_abilities(billing_menu_item, :read_billing) add_menu_item_for_abilities(workspaces_menu_item, :read_remote_development_cluster_agent_mapping) end diff --git a/ee/lib/ee/sidebars/projects/menus/settings_menu.rb b/ee/lib/ee/sidebars/projects/menus/settings_menu.rb index 41d2fc1e8ba2e24aacd7a5888397e7fc357a121b..185829ab19f9589d099ecfa905af0cded4efc623 100644 --- a/ee/lib/ee/sidebars/projects/menus/settings_menu.rb +++ b/ee/lib/ee/sidebars/projects/menus/settings_menu.rb @@ -25,6 +25,7 @@ module SettingsMenu ], ci_cd_menu_item: [ :admin_cicd_variables, + :admin_protected_environments, :admin_runner ], integrations_menu_item: [ diff --git a/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb b/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb index af775c736b4558c544b1a84bfa75a26e807aed55..304f26b0c66dfd46a1260146e90ff7031134bb6f 100644 --- a/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb +++ b/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb @@ -439,6 +439,7 @@ :admin_cicd_variables | 'CI/CD' :admin_compliance_framework | 'General' :admin_push_rules | 'Repository' + :admin_protected_environments | 'CI/CD' :admin_runners | 'CI/CD' :manage_deploy_tokens | 'Repository' :manage_group_access_tokens | 'Access tokens' diff --git a/ee/spec/lib/ee/sidebars/projects/menus/settings_menu_spec.rb b/ee/spec/lib/ee/sidebars/projects/menus/settings_menu_spec.rb index ab09edf5cfe36fea7e7a538b7cba274149d148f3..251ecc4b6a97f4634628f71e3c47993648b8e7c6 100644 --- a/ee/spec/lib/ee/sidebars/projects/menus/settings_menu_spec.rb +++ b/ee/spec/lib/ee/sidebars/projects/menus/settings_menu_spec.rb @@ -90,6 +90,7 @@ :admin_push_rules | 'Repository' :manage_protected_tags | 'Repository' :admin_protected_branch | 'Repository' + :admin_protected_environments | 'CI/CD' :admin_runners | 'CI/CD' :manage_deploy_tokens | 'Repository' :manage_merge_request_settings | 'Merge requests' diff --git a/ee/spec/policies/group_policy_spec.rb b/ee/spec/policies/group_policy_spec.rb index ce737440e5976d3fc94ec07037e1c75e45dfc91c..7f217113f928b1200b925dec0c193c5a568024da 100644 --- a/ee/spec/policies/group_policy_spec.rb +++ b/ee/spec/policies/group_policy_spec.rb @@ -3888,6 +3888,13 @@ def create_member_role(member, abilities = member_role_abilities) it_behaves_like 'custom roles abilities' end + context 'for a custom role with the `admin_protected_environments` ability' do + let(:member_role_abilities) { { admin_protected_environments: true } } + let(:allowed_abilities) { [:admin_protected_environments] } + + it_behaves_like 'custom roles abilities' + end + context 'for a member role with admin_compliance_framework true' do let(:member_role_abilities) { { read_compliance_dashboard: true, admin_compliance_framework: true } } diff --git a/ee/spec/policies/project_policy_spec.rb b/ee/spec/policies/project_policy_spec.rb index 067bbfa4ef277afe3cb0d14366502ea4124cc7e8..d4e494a6cbd4cd3fbf31969eed7b439226474d5e 100644 --- a/ee/spec/policies/project_policy_spec.rb +++ b/ee/spec/policies/project_policy_spec.rb @@ -2966,6 +2966,13 @@ def create_member_role(member, abilities = member_role_abilities) it_behaves_like 'custom roles abilities' end + context 'for a custom role with the `admin_protected_environments` ability' do + let(:member_role_abilities) { { admin_protected_environments: true } } + let(:allowed_abilities) { [:admin_protected_environments] } + + it_behaves_like 'custom roles abilities' + end + context 'for a custom role with the `admin_push_rules` ability' do let(:member_role_abilities) { { admin_push_rules: true } } let(:allowed_abilities) { [:admin_push_rules] } diff --git a/ee/spec/requests/custom_roles/admin_protected_environments/groups_request_spec.rb b/ee/spec/requests/custom_roles/admin_protected_environments/groups_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..a786b2629f1fb5481ed3455bb144f27f46114b76 --- /dev/null +++ b/ee/spec/requests/custom_roles/admin_protected_environments/groups_request_spec.rb @@ -0,0 +1,200 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User with admin_protected_environments custom role', feature_category: :continuous_delivery do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:protected_environment) { create(:protected_environment, :production, :group_level, group: group) } + + shared_context 'with protected environment setting' do |enabled| + let_it_be(:role) { create(:member_role, :guest, namespace: group, admin_protected_environments: enabled) } + let_it_be(:group_member) { create(:group_member, :guest, member_role: role, user: user, group: group) } + end + + before do + stub_licensed_features(custom_roles: true) + sign_in(user) + end + + describe Groups::Settings::CiCdController do + let(:settings_page_path) { group_settings_ci_cd_path(group) } + let(:update_params) { { group: { max_artifacts_size: 100 } } } + + context 'when user has protected environment access' do + include_context 'with protected environment setting', true + + describe '#GET show' do + subject(:view_settings_page) { get settings_page_path } + + it 'displays the CI/CD settings page successfully' do + view_settings_page + + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to include('CI/CD Settings') + end + end + + describe '#PUT update' do + subject(:update_settings) { put settings_page_path, params: update_params } + + it 'prevents modification of CI/CD settings' do + update_settings + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when user lacks protected environment access' do + include_context 'with protected environment setting', false + + describe '#GET show' do + subject(:view_settings_page) { get settings_page_path } + + it 'denies access to the CI/CD settings page' do + view_settings_page + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#PUT update' do + subject(:update_settings) { put settings_page_path, params: update_params } + + it 'prevents modification of CI/CD settings' do + update_settings + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + + describe Groups::ProtectedEnvironmentsController do + let_it_be(:group) { create(:group) } + let_it_be(:protected_environment) { create(:protected_environment, :group_level, group: group, name: 'production') } + + let(:environment_params) do + { + protected_environment: { + name: 'staging', + deploy_access_levels_attributes: [{ group_id: group.id }] + } + } + end + + let(:base_path) { group_protected_environments_path(group) } + let(:environment_path) { group_protected_environment_path(group, protected_environment) } + let(:settings_redirect) { group_settings_ci_cd_path(group, anchor: 'js-protected-environments-settings') } + + context 'when user has protected environment access' do + include_context 'with protected environment setting', true + + describe '#POST create' do + subject(:create_environment) { post base_path, params: environment_params, as: :json } + + it 'creates a new protected environment' do + expect { create_environment }.to change { ProtectedEnvironment.count } + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:notice]).to eq('Your environment has been protected.') + expect(response).to redirect_to(settings_redirect) + end + end + + describe '#PUT update' do + let(:update_params) do + { + protected_environment: { + name: protected_environment.name, + deploy_access_levels_attributes: [ + { id: protected_environment.deploy_access_levels.first.id, group_id: group.id } + ] + } + } + end + + subject(:update_environment) { put environment_path, params: update_params } + + it 'updates the protected environment' do + expect { update_environment } + .not_to change { protected_environment.reload.name } + + expect(response).to have_gitlab_http_status(:ok) + end + end + + describe '#DELETE destroy' do + let_it_be(:deletable_environment) do + create(:protected_environment, :group_level, + group: group, + name: 'testing' + ) + end + + subject(:delete_environment) { delete group_protected_environment_path(group, deletable_environment) } + + it 'removes the protected environment' do + expect { delete_environment }.to change { ProtectedEnvironment.count } + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:notice]).to eq('Your environment has been unprotected') + expect(response).to redirect_to(settings_redirect) + end + end + end + + context 'when user lacks protected environment access' do + include_context 'with protected environment setting', false + + describe '#POST create' do + subject(:create_environment) { post base_path, params: environment_params, as: :json } + + it 'denies environment creation' do + expect { create_environment }.not_to change { ProtectedEnvironment.count } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#PUT update' do + let(:update_params) do + { + protected_environment: { + name: protected_environment.name, + deploy_access_levels_attributes: [ + { id: protected_environment.deploy_access_levels.first.id, group_id: group.id } + ] + } + } + end + + subject(:update_environment) { put environment_path, params: update_params } + + it 'denies environment update' do + update_environment + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#DELETE destroy' do + let_it_be(:deletable_environment) do + create(:protected_environment, :group_level, + group: group, + name: 'testing' + ) + end + + subject(:delete_environment) { delete group_protected_environment_path(group, deletable_environment) } + + it 'denies environment deletion' do + expect { delete_environment }.not_to change { ProtectedEnvironment.count } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end +end diff --git a/ee/spec/requests/custom_roles/admin_protected_environments/projects_request_spec.rb b/ee/spec/requests/custom_roles/admin_protected_environments/projects_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..74b1ce7065c90112105b4e7175d625a90e8ad480 --- /dev/null +++ b/ee/spec/requests/custom_roles/admin_protected_environments/projects_request_spec.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User with admin_protected_environments custom role', feature_category: :continuous_delivery do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + let_it_be(:protected_environment) { create(:protected_environment, project: project) } + + before do + stub_licensed_features(custom_roles: true) + sign_in(user) + end + + shared_context 'with protected environment value' do |env| + let_it_be(:role) { create(:member_role, :guest, namespace: group, admin_protected_environments: env) } + let_it_be(:member) { create(:project_member, :guest, member_role: role, user: user, project: project) } + end + + describe Projects::Settings::CiCdController do + let(:settings_page_path) { project_settings_ci_cd_path(project) } + let(:update_params) { { namespace_id: project.namespace, project_id: project } } + + context 'when user has protected environment access' do + include_context 'with protected environment value', true + + describe '#GET show' do + subject(:view_settings_page) { get settings_page_path } + + it 'displays the CI/CD settings page successfully' do + view_settings_page + + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to include('CI/CD Settings') + end + end + + describe '#PUT update' do + subject(:update_settings) { put settings_page_path, params: update_params } + + it 'prevents modification of CI/CD settings' do + update_settings + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when user lacks protected environment access' do + include_context 'with protected environment value', false + + describe '#GET show' do + subject(:view_settings_page) { get settings_page_path } + + it 'denies access to the CI/CD settings page' do + view_settings_page + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#PUT update' do + subject(:update_settings) { put settings_page_path, params: update_params } + + it 'prevents modification of CI/CD settings' do + update_settings + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + + describe Projects::ProtectedEnvironmentsController do + let(:environment_params) do + { + name: 'testenv', + deploy_access_levels_attributes: [ + { access_level: Gitlab::Access::DEVELOPER } + ] + } + end + + let(:base_path) { project_protected_environments_path(project) } + let(:environment_path) { project_protected_environment_path(project, protected_environment) } + let(:search_path) { search_project_protected_environments_path(project) } + + context 'when user has protected environment access' do + include_context 'with protected environment value', true + + describe '#POST create' do + subject(:create_environment) { post base_path, params: { protected_environment: environment_params } } + + it 'creates a new protected environment' do + create_environment + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:notice]).to eq('Your environment has been protected.') + end + end + + describe '#PUT update' do + subject(:update_environment) { put environment_path, params: { protected_environment: environment_params } } + + it 'updates the protected environment' do + update_environment + + expect(response).to have_gitlab_http_status(:ok) + end + end + + describe '#DELETE destroy' do + subject(:delete_environment) { delete environment_path } + + it 'removes the protected environment' do + delete_environment + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:notice]).to eq('Your environment has been unprotected') + end + end + + describe '#GET search' do + subject(:search_environments) { get search_path, params: { query: 'prod' } } + + it 'performs environment search' do + search_environments + + expect(response).to have_gitlab_http_status(:ok) + end + end + end + + context 'when user lacks protected environment access' do + include_context 'with protected environment value', false + + describe '#POST create' do + subject(:create_environment) { post base_path, params: { protected_environment: environment_params } } + + it 'denies environment creation' do + create_environment + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#PUT update' do + subject(:update_environment) { put environment_path, params: { protected_environment: environment_params } } + + it 'denies environment update' do + update_environment + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#DELETE destroy' do + subject(:delete_environment) { delete environment_path } + + it 'denies environment deletion' do + delete_environment + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe '#GET search' do + subject(:search_environments) { get search_path, params: { query: 'prod' } } + + it 'denies environment search' do + search_environments + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end +end