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 cfc882bd1f78b4b2289c07261be531ad609e1945..bb48799946f00645eb8a148bbb6d8e6d48b90896 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -33703,6 +33703,7 @@ Member role permission.
| `ADMIN_VULNERABILITY` | Edit the vulnerability object, including the status and linking an issue. Includes the `read_vulnerability` permission actions. |
| `ADMIN_WEB_HOOK` | Manage webhooks. |
| `ARCHIVE_PROJECT` | Allows archiving of projects. |
+| `MANAGE_DEPLOY_TOKENS` | Manage deploy tokens at the group or project level. |
| `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. |
| `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. |
| `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