diff --git a/app/controllers/projects/deploy_tokens_controller.rb b/app/controllers/projects/deploy_tokens_controller.rb index ed77fa2fee617bdbeaa61678a2d6584087f81ba6..7ee9b271a1cb6af5ff87f42c0978c83c8e4003a5 100644 --- a/app/controllers/projects/deploy_tokens_controller.rb +++ b/app/controllers/projects/deploy_tokens_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Projects::DeployTokensController < Projects::ApplicationController - before_action :authorize_admin_project! + before_action :authorize_destroy_deploy_token! feature_category :continuous_delivery urgency :low diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb index 8dc30ed5f68c46b1cdb2cb1eed396bf980997168..2d7a3d698f03ac6469982f93ab1cec66c6da4b68 100644 --- a/app/controllers/projects/settings/repository_controller.rb +++ b/app/controllers/projects/settings/repository_controller.rb @@ -4,8 +4,7 @@ module Projects module Settings class RepositoryController < Projects::ApplicationController layout 'project_settings' - before_action :authorize_admin_project!, except: [:show, :update] - before_action :authorize_admin_push_rules!, only: [:show, :update] + before_action :authorize_admin_project! before_action :define_variables, only: [:create_deploy_token] before_action do diff --git a/app/helpers/deploy_tokens_helper.rb b/app/helpers/deploy_tokens_helper.rb index 597823cdac71658e078ba87af4f71e95048337dd..cd6eb7b2dab8549c31d0e1ccd97624fa86168b09 100644 --- a/app/helpers/deploy_tokens_helper.rb +++ b/app/helpers/deploy_tokens_helper.rb @@ -8,13 +8,17 @@ def expand_deploy_tokens_section?(new_deploy_token, created_deploy_token) end def container_registry_enabled?(group_or_project) - Gitlab.config.registry.enabled && - can?(current_user, :read_container_image, group_or_project) + return false unless ::Gitlab.config.registry.enabled + + can?(current_user, :read_container_image, group_or_project) || + can?(current_user, :manage_deploy_tokens, group_or_project) end def packages_registry_enabled?(group_or_project) - Gitlab.config.packages.enabled && - can?(current_user, :read_package, group_or_project&.packages_policy_subject) + return false unless ::Gitlab.config.packages.enabled + + can?(current_user, :read_package, group_or_project&.packages_policy_subject) || + can?(current_user, :manage_deploy_tokens, group_or_project) end def deploy_token_revoke_button_data(token:, group_or_project:) diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 7ce72a8f7313737438c0dd81a1a21ec5082a776d..badbd5761e39b54dbe1fc5e8285ac6e322d196ef 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -605,6 +605,7 @@ class ProjectPolicy < BasePolicy enable :read_import_error enable :admin_cicd_variables enable :admin_push_rules + enable :manage_deploy_tokens end rule { can?(:admin_build) }.enable :manage_trigger diff --git a/app/validators/json_schemas/member_role_permissions.json b/app/validators/json_schemas/member_role_permissions.json index 8b75568ce8132ebe419d3674fe26f3cbf7bac648..a2d45d354fb10f7b966533a4674ba16a17252c70 100644 --- a/app/validators/json_schemas/member_role_permissions.json +++ b/app/validators/json_schemas/member_role_permissions.json @@ -31,6 +31,9 @@ "archive_project": { "type": "boolean" }, + "manage_deploy_tokens": { + "type": "boolean" + }, "manage_group_access_tokens": { "type": "boolean" }, diff --git a/app/views/groups/settings/repository/show.html.haml b/app/views/groups/settings/repository/show.html.haml index fc81d22391af6b58f4b0642da8705699d1615234..6b95189fbb6507e889addbc57818e009a928ca86 100644 --- a/app/views/groups/settings/repository/show.html.haml +++ b/app/views/groups/settings/repository/show.html.haml @@ -2,13 +2,13 @@ - page_title _('Repository') - @force_desktop_expanded_sidebar = true -- if can?(current_user, :admin_group, @group) +- if can?(current_user, :create_deploy_token, @group) - deploy_token_description = s_('DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group.') - = render "shared/deploy_tokens/index", group_or_project: @group, description: deploy_token_description - = render "default_branch", group: @group -= render_if_exists "protected_branches/protected_branches", protected_branch_entity: @group +- if can?(current_user, :admin_group, @group) + = render "default_branch", group: @group + = render_if_exists "protected_branches/protected_branches", protected_branch_entity: @group - if can?(current_user, :change_push_rules, @group) = render "push_rules" diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml index f0ca2a18e5b3a2190aa49049966c041a82bd68b8..dede437d2b35a0367cb1de5bfc66accb2fccac27 100644 --- a/app/views/projects/settings/repository/show.html.haml +++ b/app/views/projects/settings/repository/show.html.haml @@ -18,7 +18,11 @@ -# Those are used throughout the actual views. These `shared` views are then -# reused in EE. = render "projects/settings/repository/protected_branches", protected_branch_entity: @project + +- if current_user.can?(:manage_deploy_tokens, @project) = render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description + +- if can?(current_user, :admin_project, @project) = render 'shared/deploy_keys/index' = render "projects/maintenance/show" diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 561f34b80461766e173320e7e000fd1e8ef4929e..f8c3654d74fe9640a25720fa28573a3e6d6f2577 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -33810,6 +33810,7 @@ Member role permission. | <a id="memberrolepermissionadmin_vulnerability"></a>`ADMIN_VULNERABILITY` | Edit the vulnerability object, including the status and linking an issue. Includes the `read_vulnerability` permission actions. | | <a id="memberrolepermissionadmin_web_hook"></a>`ADMIN_WEB_HOOK` | Manage webhooks. | | <a id="memberrolepermissionarchive_project"></a>`ARCHIVE_PROJECT` | Allows archiving of projects. | +| <a id="memberrolepermissionmanage_deploy_tokens"></a>`MANAGE_DEPLOY_TOKENS` | Manage deploy tokens at the group or project level. | | <a id="memberrolepermissionmanage_group_access_tokens"></a>`MANAGE_GROUP_ACCESS_TOKENS` | Create, read, update, and delete group access tokens. When creating a token, users with this custom permission must select a role for that token that has the same or fewer permissions as the default role used as the base for the custom role. | | <a id="memberrolepermissionmanage_project_access_tokens"></a>`MANAGE_PROJECT_ACCESS_TOKENS` | Create, read, update, and delete project access tokens. When creating a token, users with this custom permission must select a role for that token that has the same or fewer permissions as the default role used as the base for the custom role. | | <a id="memberrolepermissionmanage_security_policy_link"></a>`MANAGE_SECURITY_POLICY_LINK` | Allows linking security policy projects. | diff --git a/doc/user/custom_roles/abilities.md b/doc/user/custom_roles/abilities.md index c19192be819d785a9110af91642ddb6b676337f3..a3cfb1a653084e1ca7b6a61865f48910b1122760 100644 --- a/doc/user/custom_roles/abilities.md +++ b/doc/user/custom_roles/abilities.md @@ -29,6 +29,12 @@ These requirements are documented in the `Required permission` column in the fol |:-----|:------------|:------------------|:---------|:--------------|:---------| | [`admin_compliance_framework`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144183) | | Create, read, update, and delete compliance frameworks. Users with this permission can also assign a compliance framework label to a project, and set the default framework of a group. | GitLab [17.0](https://gitlab.com/gitlab-org/gitlab/-/issues/411502) | | | +## Continuous delivery + +| Name | Required permission | Description | Introduced in | Feature flag | Enabled in | +|:-----|:------------|:------------------|:---------|:--------------|:---------| +| [`manage_deploy_tokens`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151677) | | Manage deploy tokens at the group or project level. | GitLab [17.0](https://gitlab.com/gitlab-org/gitlab/-/issues/448843) | | | + ## Groups and projects | Name | Required permission | Description | Introduced in | Feature flag | Enabled in | diff --git a/ee/app/controllers/ee/groups/settings/repository_controller.rb b/ee/app/controllers/ee/groups/settings/repository_controller.rb index bbf75f0797daf3bafbd672072ed25a2433760d6f..40c3bb5fb8d793e61a0690f6156734c8a96385ff 100644 --- a/ee/app/controllers/ee/groups/settings/repository_controller.rb +++ b/ee/app/controllers/ee/groups/settings/repository_controller.rb @@ -16,7 +16,8 @@ module RepositoryController override :authorize_access! def authorize_access! - render_404 unless can?(current_user, :admin_group, group) || can?(current_user, :change_push_rules, group) + render_404 unless can?(current_user, :admin_group, group) || can?(current_user, :change_push_rules, group) || + can?(current_user, :manage_deploy_tokens, group) end def define_push_rule_variable diff --git a/ee/app/controllers/ee/projects/settings/repository_controller.rb b/ee/app/controllers/ee/projects/settings/repository_controller.rb index 0bb43f383ecac72dc35861ab26b4434d96bac4e0..35baae67dfb77a34e6d82e3d889fd44a96b4211e 100644 --- a/ee/app/controllers/ee/projects/settings/repository_controller.rb +++ b/ee/app/controllers/ee/projects/settings/repository_controller.rb @@ -8,6 +8,8 @@ module RepositoryController extend ::Gitlab::Utils::Override prepended do + skip_before_action :authorize_admin_project!, only: [:show, :create_deploy_token] + before_action :authorize_view_repository_settings!, only: [:show, :create_deploy_token] before_action :push_rule, only: :show end @@ -89,6 +91,13 @@ def allow_protected_branches_for_group?(group) ::Feature.enabled?(:group_protected_branches, group) || ::Feature.enabled?(:allow_protected_branches_for_group, group) end + + def authorize_view_repository_settings! + return if can?(current_user, :admin_push_rules, project) || + can?(current_user, :manage_deploy_tokens, project) + + authorize_admin_project! + end end end end diff --git a/ee/app/policies/ee/group_policy.rb b/ee/app/policies/ee/group_policy.rb index 016219fd21554a570a54f5203e7668d6ad3eed76..097a3ad2791fa99559ee3f173e70839d0d52a4be 100644 --- a/ee/app/policies/ee/group_policy.rb +++ b/ee/app/policies/ee/group_policy.rb @@ -550,10 +550,17 @@ module GroupPolicy enable :admin_push_rules end - rule { can?(:admin_group) | can?(:admin_compliance_framework) }.policy do + rule { can?(:admin_group) | can?(:admin_compliance_framework) | can?(:manage_deploy_tokens) }.policy do enable :view_edit_page end + rule { custom_role_enables_manage_deploy_tokens }.policy do + enable :manage_deploy_tokens + enable :read_deploy_token + enable :create_deploy_token + enable :destroy_deploy_token + end + rule { can?(:read_vulnerability) }.policy do enable :read_group_security_dashboard enable :create_vulnerability_export diff --git a/ee/app/policies/ee/project_policy.rb b/ee/app/policies/ee/project_policy.rb index d8fbab0c1f291e4029f2c1cc38b0a071c7a4d2b5..995fb29198c5d8c683dff68f44525dc6d900dadf 100644 --- a/ee/app/policies/ee/project_policy.rb +++ b/ee/app/policies/ee/project_policy.rb @@ -529,6 +529,7 @@ module ProjectPolicy enable :modify_merge_request_committer_setting enable :modify_product_analytics_settings enable :admin_push_rules + enable :manage_deploy_tokens end rule { license_scanning_enabled & can?(:maintainer_access) }.enable :admin_software_license_policy @@ -778,6 +779,13 @@ module ProjectPolicy enable :admin_compliance_framework end + rule { custom_role_enables_manage_deploy_tokens }.policy do + enable :manage_deploy_tokens + enable :read_deploy_token + enable :create_deploy_token + enable :destroy_deploy_token + end + rule { can?(:create_issue) & okrs_enabled }.policy do enable :create_objective enable :create_key_result diff --git a/ee/config/custom_abilities/manage_deploy_tokens.yml b/ee/config/custom_abilities/manage_deploy_tokens.yml new file mode 100644 index 0000000000000000000000000000000000000000..1a16216d6cd49a64e3f0165238472d164bb23df5 --- /dev/null +++ b/ee/config/custom_abilities/manage_deploy_tokens.yml @@ -0,0 +1,11 @@ +--- +name: manage_deploy_tokens +description: Manage deploy tokens at the group or project level. +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/448843 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151677 +feature_category: continuous_delivery +milestone: "17.0" +group_ability: true +project_ability: true +requirements: [] +available_from_access_level: diff --git a/ee/lib/ee/sidebars/groups/menus/settings_menu.rb b/ee/lib/ee/sidebars/groups/menus/settings_menu.rb index e00a9734828b1a19e44b6c3086637bb84b9814ad..04ae18bd753232772b320144348841285a338789 100644 --- a/ee/lib/ee/sidebars/groups/menus/settings_menu.rb +++ b/ee/lib/ee/sidebars/groups/menus/settings_menu.rb @@ -26,7 +26,7 @@ def configure_menu_items else add_menu_item_for_abilities(general_menu_item, [:remove_group, :admin_compliance_framework]) add_menu_item_for_abilities(access_tokens_menu_item, :read_resource_access_tokens) - add_menu_item_for_abilities(repository_menu_item, :admin_push_rules) + 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) add_menu_item_for_abilities(billing_menu_item, :read_billing) end diff --git a/ee/lib/ee/sidebars/projects/menus/settings_menu.rb b/ee/lib/ee/sidebars/projects/menus/settings_menu.rb index a9d1015ec0cf80971b2caa9916a46e70fec2a6a1..215bb866a6f08b52f3decc8723bcb2a8db2dfd54 100644 --- a/ee/lib/ee/sidebars/projects/menus/settings_menu.rb +++ b/ee/lib/ee/sidebars/projects/menus/settings_menu.rb @@ -44,8 +44,8 @@ def custom_roles_menu_items items << general_menu_item if custom_roles_general_menu_item? items << access_tokens_menu_item if custom_roles_access_token_menu_item? - items << ci_cd_menu_item if custom_roles_ci_cd_menu_item? items << repository_menu_item if custom_roles_repository_menu_item? + items << ci_cd_menu_item if custom_roles_ci_cd_menu_item? items end @@ -58,12 +58,13 @@ def custom_roles_access_token_menu_item? can?(context.current_user, :manage_resource_access_tokens, context.project) end - def custom_roles_ci_cd_menu_item? - can?(context.current_user, :admin_cicd_variables, context.project) + def custom_roles_repository_menu_item? + can?(context.current_user, :admin_push_rules, context.project) || + can?(context.current_user, :manage_deploy_tokens, context.project) end - def custom_roles_repository_menu_item? - can?(context.current_user, :admin_push_rules, context.project) + def custom_roles_ci_cd_menu_item? + can?(context.current_user, :admin_cicd_variables, context.project) end end end 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 72802db9112167ae9d63da6dfe36487fa9e76e93..38ebd24dd60cc5722f968f7852ce7689c2d753a0 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 @@ -403,5 +403,27 @@ end end end + + context 'when the user is not an owner but has `manage_deploy_tokens` custom permission', feature_category: :continuous_delivery do + let_it_be(:user) { create(:user) } + + subject { menu.renderable_items.find { |e| e.item_id == item_id } } + + before do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :admin_group, group).and_return(false) + allow(Ability).to receive(:allowed?).with(user, :manage_deploy_tokens, group).and_return(true) + end + + describe 'General menu item' do + let(:item_id) { :repository } + + it { is_expected.to be_present } + + it 'does not show any other menu items' do + expect(menu.renderable_items.length).to equal(1) + end + end + end end end 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 b7dc170037d564533385e667c1bf417f3af31fd1..37f27647c8fe9ad261a3de765ca8a198b19a023e 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 @@ -130,6 +130,18 @@ expect(subject.title).to eql('Repository') end end + + describe 'when the user is not an admin but has the `manage_deploy_tokens` custom permission' do + before do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :admin_project, project).and_return(false) + allow(Ability).to receive(:allowed?).with(user, :manage_deploy_tokens, project).and_return(true) + end + + it 'includes Repository menu item' do + expect(subject.title).to eql('Repository') + end + end end end end diff --git a/ee/spec/policies/group_policy_spec.rb b/ee/spec/policies/group_policy_spec.rb index 4d53868a75b8e0e71861f253c84ccb7aabad0a1c..3d8c4f28b2ac6427772a96ba17520b836ae77454 100644 --- a/ee/spec/policies/group_policy_spec.rb +++ b/ee/spec/policies/group_policy_spec.rb @@ -3563,6 +3563,16 @@ def create_member_role(member, abilities = member_role_abilities) it_behaves_like 'custom roles abilities' end + + context 'for a custom role with the `manage_deploy_tokens` permission' do + let(:member_role_abilities) { { manage_deploy_tokens: true } } + + let(:allowed_abilities) do + [:manage_deploy_tokens, :read_deploy_token, :create_deploy_token, :destroy_deploy_token, :view_edit_page] + end + + it_behaves_like 'custom roles abilities' + end end context 'for :read_limit_alert' do diff --git a/ee/spec/policies/project_policy_spec.rb b/ee/spec/policies/project_policy_spec.rb index d94c50fd08ac98c3fe72084d15707804966ecaa9..29f85f5f700d8d3a0dee5cd0e0faf4762f422175 100644 --- a/ee/spec/policies/project_policy_spec.rb +++ b/ee/spec/policies/project_policy_spec.rb @@ -2989,6 +2989,13 @@ def create_member_role(member, abilities = member_role_abilities) it_behaves_like 'custom roles abilities' end + + context 'for a member role with `manage_deploy_tokens` true' do + let(:member_role_abilities) { { manage_deploy_tokens: true } } + let(:allowed_abilities) { [:manage_deploy_tokens, :read_deploy_token, :create_deploy_token, :destroy_deploy_token] } + + it_behaves_like 'custom roles abilities' + end end describe 'permissions for suggested reviewers bot', :saas do diff --git a/ee/spec/requests/custom_roles/manage_deploy_tokens/request_spec.rb b/ee/spec/requests/custom_roles/manage_deploy_tokens/request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ef5acf2a362373e4ef6ccbf19d51dc8340215377 --- /dev/null +++ b/ee/spec/requests/custom_roles/manage_deploy_tokens/request_spec.rb @@ -0,0 +1,188 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User with manage_deploy_tokens custom role', feature_category: :continuous_delivery do + include ApiHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, :repository, namespace: group) } + let_it_be_with_reload(:role) { create(:member_role, :guest, namespace: group, manage_deploy_tokens: true) } + + before do + stub_licensed_features(custom_roles: true) + + sign_in(user) + end + + describe 'manage project deploy tokens' do + let_it_be(:membership) { create(:project_member, :guest, user: user, source: project, member_role: role) } + let_it_be(:deploy_token) { create(:deploy_token, projects: [project]) } + + describe Projects::Settings::RepositoryController do + describe '#show' do + it 'user has access via a custom role' do + get project_settings_repository_path(project) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to have_text(s_('DeployTokens|Deploy tokens')) + end + end + + describe '#create_deploy_token' do + it 'user has access via a custom role' do + params = { deploy_token: { name: 'name', expires_at: 1.day.from_now.to_datetime.to_s, read_repository: '1' } } + + expect do + post create_deploy_token_project_settings_repository_path(project, params: params, format: :json) + end.to change { project.deploy_tokens.count }.by(1) + + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/deploy_token') + end + end + end + + describe Projects::DeployTokensController do + describe '#revoke' do + it 'user has access via a custom role' do + expect do + put revoke_project_deploy_token_path(project, deploy_token) + end.to change { deploy_token.reload.revoked }.to(true) + + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to(project_settings_repository_path(project, anchor: 'js-deploy-tokens')) + end + end + end + + describe API::DeployTokens do + let_it_be(:url) { "/projects/#{project.id}/deploy_tokens" } + + describe 'GET all tokens' do + it 'user has access via a custom role' do + get api(url, user) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/deploy_tokens') + end + end + + describe 'GET a single token' do + it 'user has access via a custom role' do + get api("#{url}/#{deploy_token.id}", user) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/deploy_token') + end + end + + describe 'POST' do + it 'user has access via a custom role' do + expect do + post api(url, user), params: { name: 'Foo', expires_at: 1.day.from_now, scopes: ['read_repository'] } + end.to change { DeployToken.count }.by(1) + + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/deploy_token') + end + end + + describe 'DELETE' do + it 'user has access via a custom role' do + expect do + delete api("#{url}/#{deploy_token.id}", user) + end.to change { DeployToken.count }.by(-1) + + expect(response).to have_gitlab_http_status(:no_content) + end + end + end + end + + describe 'manage group deploy tokens' do + let_it_be(:membership) { create(:group_member, :guest, user: user, source: group, member_role: role) } + let_it_be(:deploy_token) { create(:deploy_token, :group, groups: [group]) } + + describe Groups::Settings::RepositoryController do + describe '#show' do + it 'user has access via a custom role' do + get group_settings_repository_path(group) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to have_text(s_('DeployTokens|Deploy tokens')) + end + end + + describe '#create_deploy_token' do + it 'user has access via a custom role' do + params = { deploy_token: { name: 'name', expires_at: 1.day.from_now.to_datetime.to_s, read_repository: '1' } } + + expect do + post create_deploy_token_group_settings_repository_path(group, params: params, format: :json) + end.to change { group.deploy_tokens.count }.by(1) + + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/deploy_token') + end + end + end + + describe Groups::DeployTokensController do + describe '#revoke' do + it 'user has access via a custom role' do + expect do + put revoke_group_deploy_token_path(group, deploy_token) + end.to change { deploy_token.reload.revoked }.to(true) + + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to(group_settings_repository_path(group, anchor: 'js-deploy-tokens')) + end + end + end + + describe API::DeployTokens do + let_it_be(:url) { "/groups/#{group.id}/deploy_tokens" } + + describe 'GET all tokens' do + it 'user has access via a custom role' do + get api(url, user) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/deploy_tokens') + end + end + + describe 'GET a single token' do + it 'user has access via a custom role' do + get api("#{url}/#{deploy_token.id}", user) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/deploy_token') + end + end + + describe 'POST' do + it 'user has access via a custom role' do + expect do + post api(url, user), params: { name: 'Foo', expires_at: 1.day.from_now, scopes: ['read_repository'] } + end.to change { DeployToken.count }.by(1) + + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/deploy_token') + end + end + + describe 'DELETE' do + it 'user has access via a custom role' do + expect do + delete api("#{url}/#{deploy_token.id}", user) + end.to change { DeployToken.count }.by(-1) + + expect(response).to have_gitlab_http_status(:no_content) + end + end + end + end +end diff --git a/spec/helpers/deploy_tokens_helper_spec.rb b/spec/helpers/deploy_tokens_helper_spec.rb index e5dd5ff79a2e13499d01403caee9f2cc3db01a13..3ec00c87141eda2403e11cc94d5a163bd62eb86a 100644 --- a/spec/helpers/deploy_tokens_helper_spec.rb +++ b/spec/helpers/deploy_tokens_helper_spec.rb @@ -2,7 +2,9 @@ require 'spec_helper' -RSpec.describe DeployTokensHelper do +RSpec.describe DeployTokensHelper, feature_category: :continuous_delivery do + using RSpec::Parameterized::TableSyntax + describe '#deploy_token_revoke_button_data' do let_it_be(:token) { build(:deploy_token) } let_it_be(:project) { build(:project) } @@ -17,4 +19,62 @@ }) end end + + describe '#container_registry_enabled?' do + let_it_be(:project) { build(:project) } + let_it_be(:user) { build(:user) } + + where(:registry_enabled, :can_read_container_image, :can_manage_deploy_tokens, :result) do + true | true | true | true + true | true | false | true + true | false | true | true + true | false | false | false + false | true | true | false + end + + with_them do + before do + allow(helper).to receive(:current_user).and_return(user) + allow(Gitlab.config.registry).to receive(:enabled).and_return(registry_enabled) + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_container_image, project) + .and_return(can_read_container_image) + allow(Ability).to receive(:allowed?).with(user, :manage_deploy_tokens, project) + .and_return(can_manage_deploy_tokens) + end + + it 'returns expected value' do + expect(helper.container_registry_enabled?(project)).to eq(result) + end + end + end + + describe '#packages_registry_enabled?' do + let_it_be(:project) { build(:project) } + let_it_be(:user) { build(:user) } + + where(:packages_enabled, :can_read_package, :can_manage_deploy_tokens, :result) do + true | true | true | true + true | true | false | true + true | false | true | true + true | false | false | false + false | true | true | false + end + + with_them do + before do + allow(helper).to receive(:current_user).and_return(user) + allow(Gitlab.config.packages).to receive(:enabled).and_return(packages_enabled) + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_package, instance_of(::Packages::Policies::Project)) + .and_return(can_read_package) + allow(Ability).to receive(:allowed?).with(user, :manage_deploy_tokens, project) + .and_return(can_manage_deploy_tokens) + end + + it 'returns expected value' do + expect(helper.packages_registry_enabled?(project)).to eq(result) + end + end + end end