From 84a3b5687ea066f5ca8419fe7575efdbc94047ca Mon Sep 17 00:00:00 2001 From: Matthew MacRae-Bovell Date: Mon, 22 Sep 2025 10:21:04 -0400 Subject: [PATCH 1/5] Rename container permisions from destroy to delete --- .../container_registry/protection/tag_rule/delete.rb | 2 +- .../mutations/container_repositories/destroy.rb | 2 +- .../mutations/container_repositories/destroy_tags.rb | 2 +- .../container_registry/protection/tag_rule.rb | 2 +- .../permission_types/container_repository_tag.rb | 4 ++-- .../container_registry/protection/tag_rule_policy.rb | 2 +- app/policies/container_registry/tag_policy.rb | 2 +- app/policies/container_repository_policy.rb | 2 +- app/policies/project_policy.rb | 12 ++++++------ .../container_registry_authentication_service.rb | 4 ++-- .../protection/check_rule_existence_service.rb | 2 +- .../container_repository/cleanup_tags_service.rb | 2 +- .../container_repository/delete_tags_service.rb | 2 +- .../projects/container_repository/destroy_service.rb | 2 +- config/authz/permissions/container_image/delete.yml | 6 ++++++ .../authz/permissions/container_image_tag/delete.yml | 6 ++++++ .../delete.yml | 6 ++++++ config/authz/permissions/definitions_todo.txt | 3 --- doc/api/graphql/reference/_index.md | 4 ++-- .../protection/tag_rule_policy_spec.rb | 2 +- ee/spec/policies/container_repository_policy_spec.rb | 10 +++++----- lib/api/project_container_repositories.rb | 4 ++-- .../projects/registry/tags_controller_spec.rb | 2 +- .../container_repositories/destroy_tags_spec.rb | 2 +- .../protection/tag_rule_policy_spec.rb | 6 +++--- spec/policies/container_registry/tag_policy_spec.rb | 12 ++++++------ spec/policies/container_repository_policy_spec.rb | 12 ++++++------ spec/policies/project_policy_spec.rb | 2 +- .../protection/tag_rule/delete_spec.rb | 2 +- .../policies/project_policy_shared_context.rb | 2 +- 30 files changed, 69 insertions(+), 54 deletions(-) create mode 100644 config/authz/permissions/container_image/delete.yml create mode 100644 config/authz/permissions/container_image_tag/delete.yml create mode 100644 config/authz/permissions/container_registry_protection_tag_rule/delete.yml diff --git a/app/graphql/mutations/container_registry/protection/tag_rule/delete.rb b/app/graphql/mutations/container_registry/protection/tag_rule/delete.rb index c9e39bd8ca5e46..c8d9e4f935cdd8 100644 --- a/app/graphql/mutations/container_registry/protection/tag_rule/delete.rb +++ b/app/graphql/mutations/container_registry/protection/tag_rule/delete.rb @@ -9,7 +9,7 @@ class Delete < ::Mutations::BaseMutation description 'Deletes a protection rule that controls which user ' \ 'roles can modify container image tags matching a specified pattern.' - authorize :destroy_container_registry_protection_tag_rule + authorize :delete_container_registry_protection_tag_rule argument :id, ::Types::GlobalIDType[::ContainerRegistry::Protection::TagRule], diff --git a/app/graphql/mutations/container_repositories/destroy.rb b/app/graphql/mutations/container_repositories/destroy.rb index 3f59e1b396aea5..e7fdad0c160b8f 100644 --- a/app/graphql/mutations/container_repositories/destroy.rb +++ b/app/graphql/mutations/container_repositories/destroy.rb @@ -5,7 +5,7 @@ module ContainerRepositories class Destroy < ::Mutations::ContainerRepositories::DestroyBase graphql_name 'DestroyContainerRepository' - authorize :destroy_container_image + authorize :delete_container_image argument :id, ::Types::GlobalIDType[::ContainerRepository], diff --git a/app/graphql/mutations/container_repositories/destroy_tags.rb b/app/graphql/mutations/container_repositories/destroy_tags.rb index 9b6106dac34b3f..04878c20785b6c 100644 --- a/app/graphql/mutations/container_repositories/destroy_tags.rb +++ b/app/graphql/mutations/container_repositories/destroy_tags.rb @@ -8,7 +8,7 @@ class DestroyTags < ::Mutations::ContainerRepositories::DestroyBase LIMIT = 20 TOO_MANY_TAGS_ERROR_MESSAGE = "Number of tags is greater than #{LIMIT}" - authorize :destroy_container_image_tag + authorize :delete_container_image_tag argument :id, ::Types::GlobalIDType[::ContainerRepository], diff --git a/app/graphql/types/permission_types/container_registry/protection/tag_rule.rb b/app/graphql/types/permission_types/container_registry/protection/tag_rule.rb index 40c2d6561986b7..95d7c430d30517 100644 --- a/app/graphql/types/permission_types/container_registry/protection/tag_rule.rb +++ b/app/graphql/types/permission_types/container_registry/protection/tag_rule.rb @@ -7,7 +7,7 @@ module Protection class TagRule < BasePermissionType graphql_name 'ContainerRegistryProtectionTagRulePermissions' - ability_field :destroy_container_registry_protection_tag_rule + ability_field :delete_container_registry_protection_tag_rule end end end diff --git a/app/graphql/types/permission_types/container_repository_tag.rb b/app/graphql/types/permission_types/container_repository_tag.rb index dca12b6b7b920e..fd28471c9af8f0 100644 --- a/app/graphql/types/permission_types/container_repository_tag.rb +++ b/app/graphql/types/permission_types/container_repository_tag.rb @@ -5,9 +5,9 @@ module PermissionTypes class ContainerRepositoryTag < BasePermissionType graphql_name 'ContainerRepositoryTagPermissions' - ability_field :destroy_container_image_tag, + ability_field :delete_container_image_tag, name: 'destroy_container_repository_tag', - resolver_method: :destroy_container_image_tag + resolver_method: :delete_container_image_tag end end end diff --git a/app/policies/container_registry/protection/tag_rule_policy.rb b/app/policies/container_registry/protection/tag_rule_policy.rb index 3db3327eff5e4c..e092be32339f7d 100644 --- a/app/policies/container_registry/protection/tag_rule_policy.rb +++ b/app/policies/container_registry/protection/tag_rule_policy.rb @@ -8,7 +8,7 @@ class TagRulePolicy < BasePolicy condition(:cannot_be_deleted_by_user) { !@subject.can_be_deleted?(@user) } rule { cannot_be_deleted_by_user }.policy do - prevent :destroy_container_registry_protection_tag_rule + prevent :delete_container_registry_protection_tag_rule end end end diff --git a/app/policies/container_registry/tag_policy.rb b/app/policies/container_registry/tag_policy.rb index 748775a65761a7..264db15889c15a 100644 --- a/app/policies/container_registry/tag_policy.rb +++ b/app/policies/container_registry/tag_policy.rb @@ -6,7 +6,7 @@ class TagPolicy < BasePolicy condition(:protected_for_delete) { @subject.protected_for_delete?(@user) } rule { protected_for_delete }.policy do - prevent :destroy_container_image_tag + prevent :delete_container_image_tag end end end diff --git a/app/policies/container_repository_policy.rb b/app/policies/container_repository_policy.rb index eebca68c8ad9ba..0d199264a73cbf 100644 --- a/app/policies/container_repository_policy.rb +++ b/app/policies/container_repository_policy.rb @@ -6,6 +6,6 @@ class ContainerRepositoryPolicy < BasePolicy condition(:protected_for_delete) { @subject.protected_from_delete_by_tag_rules?(@user) } rule { protected_for_delete }.policy do - prevent :destroy_container_image + prevent :delete_container_image end end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index a185d4a185c623..637b5f10332303 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -611,9 +611,9 @@ class ProjectPolicy < BasePolicy enable :resolve_note enable :create_container_image enable :update_container_image - enable :destroy_container_image - enable :destroy_container_image_tag - enable :destroy_container_registry_protection_tag_rule + enable :delete_container_image + enable :delete_container_image_tag + enable :delete_container_registry_protection_tag_rule enable :create_environment enable :update_environment enable :destroy_environment @@ -921,9 +921,9 @@ class ProjectPolicy < BasePolicy prevent :create_container_image prevent :update_container_image prevent :admin_container_image - prevent :destroy_container_image - prevent :destroy_container_image_tag - prevent :destroy_container_registry_protection_tag_rule + prevent :delete_container_image + prevent :delete_container_image_tag + prevent :delete_container_registry_protection_tag_rule end rule { anonymous & ~public_project }.prevent_all diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index f92e48189ba930..665c0745a45f0e 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -6,8 +6,8 @@ class ContainerRegistryAuthenticationService < BaseService REGISTRY_LOGIN_ABILITIES = [ :read_container_image, :create_container_image, - :destroy_container_image, - :destroy_container_image_tag, + :delete_container_image, + :delete_container_image_tag, :update_container_image, :admin_container_image, :build_read_container_image, diff --git a/app/services/container_registry/protection/check_rule_existence_service.rb b/app/services/container_registry/protection/check_rule_existence_service.rb index e7d8fb1c5505c1..67b13aa3beb34c 100644 --- a/app/services/container_registry/protection/check_rule_existence_service.rb +++ b/app/services/container_registry/protection/check_rule_existence_service.rb @@ -37,7 +37,7 @@ def current_user_can_do_action? if params[:action] == :push can?(current_user, :create_container_image, project) else - can?(current_user, :destroy_container_image, project) + can?(current_user, :delete_container_image, project) end end diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb index 43c481e17b9609..a4b8d8be520f0a 100644 --- a/app/services/projects/container_repository/cleanup_tags_service.rb +++ b/app/services/projects/container_repository/cleanup_tags_service.rb @@ -36,7 +36,7 @@ def use_gitlab_service? def can_destroy? return true if container_expiration_policy - can?(current_user, :destroy_container_image_tag, project) + can?(current_user, :delete_container_image_tag, project) end def valid_regex? diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb index 150cf6235e7416..e4d6a8a12ec7ca 100644 --- a/app/services/projects/container_repository/delete_tags_service.rb +++ b/app/services/projects/container_repository/delete_tags_service.rb @@ -9,7 +9,7 @@ def execute(container_repository) @container_repository = container_repository unless container_expiration_policy? - return error('access denied') unless can?(current_user, :destroy_container_image_tag, project) + return error('access denied') unless can?(current_user, :delete_container_image_tag, project) end @tag_names = params[:tags] diff --git a/app/services/projects/container_repository/destroy_service.rb b/app/services/projects/container_repository/destroy_service.rb index 6cb0d55aea46f9..e445a2a9868789 100644 --- a/app/services/projects/container_repository/destroy_service.rb +++ b/app/services/projects/container_repository/destroy_service.rb @@ -46,7 +46,7 @@ def destroy_container_repository(container_repository) def can_destroy? return true if skip_permission_check? - can?(current_user, :destroy_container_image, project) + can?(current_user, :delete_container_image, project) end def error_message(container_repository, message) diff --git a/config/authz/permissions/container_image/delete.yml b/config/authz/permissions/container_image/delete.yml new file mode 100644 index 00000000000000..856e2578e55b81 --- /dev/null +++ b/config/authz/permissions/container_image/delete.yml @@ -0,0 +1,6 @@ +--- +name: delete_container_image +description: Grants the ability to delete container images +scopes: + - project +feature_category: container_registry diff --git a/config/authz/permissions/container_image_tag/delete.yml b/config/authz/permissions/container_image_tag/delete.yml new file mode 100644 index 00000000000000..b87d1a9bdbdc25 --- /dev/null +++ b/config/authz/permissions/container_image_tag/delete.yml @@ -0,0 +1,6 @@ +--- +name: delete_container_image_tag +description: Grants the ability to delete container image tags +scopes: + - project +feature_category: container_registry diff --git a/config/authz/permissions/container_registry_protection_tag_rule/delete.yml b/config/authz/permissions/container_registry_protection_tag_rule/delete.yml new file mode 100644 index 00000000000000..fae8fbccf7a881 --- /dev/null +++ b/config/authz/permissions/container_registry_protection_tag_rule/delete.yml @@ -0,0 +1,6 @@ +--- +name: delete_container_registry_protection_tag_rule +description: Grants the ability to delete container registry protection tag rules +scopes: + - project +feature_category: container_registry diff --git a/config/authz/permissions/definitions_todo.txt b/config/authz/permissions/definitions_todo.txt index 5118759acc3d76..1cbc89bb7899fe 100644 --- a/config/authz/permissions/definitions_todo.txt +++ b/config/authz/permissions/definitions_todo.txt @@ -293,9 +293,6 @@ destroy_branch_rule destroy_build destroy_cluster destroy_commit_status -destroy_container_image -destroy_container_image_tag -destroy_container_registry_protection_tag_rule destroy_deploy_token destroy_deployment destroy_design diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index 2a776e60b2ab1d..71c6e40b1ec803 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -26813,7 +26813,7 @@ A container repository tag protection rule designed to prevent users with a cert | Name | Type | Description | | ---- | ---- | ----------- | -| `destroyContainerRegistryProtectionTagRule` | [`Boolean!`](#boolean) | If `true`, the user can perform `destroy_container_registry_protection_tag_rule` on this resource. | +| `deleteContainerRegistryProtectionTagRule` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_container_registry_protection_tag_rule` on this resource. | ### `ContainerRepository` @@ -26975,7 +26975,7 @@ A tag from a container repository. | Name | Type | Description | | ---- | ---- | ----------- | -| `destroyContainerRepositoryTag` | [`Boolean!`](#boolean) | If `true`, the user can perform `destroy_container_image_tag` on this resource. | +| `destroyContainerRepositoryTag` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_container_image_tag` on this resource. | ### `ContainerTagsExpirationPolicy` diff --git a/ee/spec/policies/container_registry/protection/tag_rule_policy_spec.rb b/ee/spec/policies/container_registry/protection/tag_rule_policy_spec.rb index f3096b815df187..a3115b887c07c8 100644 --- a/ee/spec/policies/container_registry/protection/tag_rule_policy_spec.rb +++ b/ee/spec/policies/container_registry/protection/tag_rule_policy_spec.rb @@ -24,7 +24,7 @@ project.send(:"add_#{user_role}", user) end - it { is_expected.to send(expected_result, :destroy_container_registry_protection_tag_rule) } + it { is_expected.to send(expected_result, :delete_container_registry_protection_tag_rule) } end end end diff --git a/ee/spec/policies/container_repository_policy_spec.rb b/ee/spec/policies/container_repository_policy_spec.rb index f9cd845c3fab95..b5c495102d80fe 100644 --- a/ee/spec/policies/container_repository_policy_spec.rb +++ b/ee/spec/policies/container_repository_policy_spec.rb @@ -9,7 +9,7 @@ subject { described_class.new(user, container_repository) } - describe 'destroy_container_image' do + describe 'delete_container_image' do context 'when the project has an immutable tag protection rule' do before_all do create(:container_registry_protection_tag_rule, :immutable, project:) @@ -28,14 +28,14 @@ project.send(:"add_#{user_role}", user) end - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end end context 'when the current user is an admin', :enable_admin_mode do let(:user) { build_stubbed(:admin) } - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end end @@ -48,14 +48,14 @@ project.send(:"add_#{user_role}", user) end - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end end context 'when the current user is an admin', :enable_admin_mode do let(:user) { build_stubbed(:admin) } - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end end end diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb index 73455cb236d75e..cc808ab77bff6b 100644 --- a/lib/api/project_container_repositories.rb +++ b/lib/api/project_container_repositories.rb @@ -221,8 +221,8 @@ def authorize_read_container_image! authorize! :read_container_image, repository end - def authorize_destroy_container_image_tag! - authorize! :destroy_container_image_tag, tag + def authorize_delete_container_image_tag! + authorize! :delete_container_image_tag, tag end def authorize_admin_container_image! diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb index e5d8ea752eefa2..d043d35f72374d 100644 --- a/spec/controllers/projects/registry/tags_controller_spec.rb +++ b/spec/controllers/projects/registry/tags_controller_spec.rb @@ -126,7 +126,7 @@ def get_tags before do project.add_developer(user) allow(Ability).to receive(:allowed?).and_call_original - allow(Ability).to receive(:allowed?).with(user, :destroy_container_image_tag, project).and_return(false) + allow(Ability).to receive(:allowed?).with(user, :delete_container_image_tag, project).and_return(false) end it 'returns not_found' do diff --git a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb index d4c96c5bca2d43..da72922f61bdf6 100644 --- a/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb +++ b/spec/graphql/mutations/container_repositories/destroy_tags_spec.rb @@ -11,7 +11,7 @@ let(:id) { repository.to_global_id } let(:current_user) { create(:user) } - specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image_tag) } + specify { expect(described_class).to require_graphql_authorizations(:delete_container_image_tag) } describe '#resolve' do let(:tags) { %w[A C D E] } diff --git a/spec/policies/container_registry/protection/tag_rule_policy_spec.rb b/spec/policies/container_registry/protection/tag_rule_policy_spec.rb index f70a04d0c6731d..3a4c619208363a 100644 --- a/spec/policies/container_registry/protection/tag_rule_policy_spec.rb +++ b/spec/policies/container_registry/protection/tag_rule_policy_spec.rb @@ -14,14 +14,14 @@ let(:user) { nil } let_it_be(:rule) { build(:container_registry_protection_tag_rule) } - it { expect_disallowed(:destroy_container_registry_protection_tag_rule) } + it { expect_disallowed(:delete_container_registry_protection_tag_rule) } end context 'for admin', :enable_admin_mode do let(:user) { build_stubbed(:admin) } let_it_be(:rule) { build(:container_registry_protection_tag_rule) } - it { expect_allowed(:destroy_container_registry_protection_tag_rule) } + it { expect_allowed(:delete_container_registry_protection_tag_rule) } end context 'for a tag rule' do @@ -38,7 +38,7 @@ project.send(:"add_#{user_role}", user) end - it { is_expected.to send(expected_result, :destroy_container_registry_protection_tag_rule) } + it { is_expected.to send(expected_result, :delete_container_registry_protection_tag_rule) } end end end diff --git a/spec/policies/container_registry/tag_policy_spec.rb b/spec/policies/container_registry/tag_policy_spec.rb index 04eecd7c73d785..3dfa225b2efaad 100644 --- a/spec/policies/container_registry/tag_policy_spec.rb +++ b/spec/policies/container_registry/tag_policy_spec.rb @@ -11,7 +11,7 @@ subject { described_class.new(user, tag) } - describe 'destroy_container_image_tag' do + describe 'delete_container_image_tag' do using RSpec::Parameterized::TableSyntax shared_examples 'matching expected result with protection rules' do @@ -23,13 +23,13 @@ allow(tag).to receive(:protection_rule).and_return(protection_rule) end - it { is_expected.to send(expected_result, :destroy_container_image_tag) } + it { is_expected.to send(expected_result, :delete_container_image_tag) } end context 'for admin', :enable_admin_mode do let(:user) { build_stubbed(:admin) } - it { expect_allowed(:destroy_container_image_tag) } + it { expect_allowed(:delete_container_image_tag) } end context 'for owner' do @@ -38,7 +38,7 @@ end context 'when tag has no protection rule' do - it { expect_allowed(:destroy_container_image_tag) } + it { expect_allowed(:delete_container_image_tag) } end context 'when tag has protection rule' do @@ -60,7 +60,7 @@ end context 'when tag has no protection rule' do - it { expect_allowed(:destroy_container_image_tag) } + it { expect_allowed(:delete_container_image_tag) } end context 'when tag has protection rule' do @@ -82,7 +82,7 @@ end context 'when tag has no protection rule' do - it { expect_allowed(:destroy_container_image_tag) } + it { expect_allowed(:delete_container_image_tag) } end context 'when tag has protection rule' do diff --git a/spec/policies/container_repository_policy_spec.rb b/spec/policies/container_repository_policy_spec.rb index f3a09ea34a319a..61957fd6bd9547 100644 --- a/spec/policies/container_repository_policy_spec.rb +++ b/spec/policies/container_repository_policy_spec.rb @@ -13,11 +13,11 @@ context 'when the current user is anonymous' do let(:user) { nil } - it { is_expected.to be_disallowed(:destroy_container_image) } + it { is_expected.to be_disallowed(:delete_container_image) } end end - describe 'destroy_container_image' do + describe 'delete_container_image' do using RSpec::Parameterized::TableSyntax before do @@ -47,13 +47,13 @@ project.send(:"add_#{user_role}", user) end - it { is_expected.to send(expected_result, :destroy_container_image) } + it { is_expected.to send(expected_result, :delete_container_image) } end context 'when the current user is an admin', :enable_admin_mode do let(:user) { build_stubbed(:admin) } - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end it_behaves_like 'not allowing anonymous user' @@ -68,7 +68,7 @@ project.send(:"add_#{user_role}", user) end - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end end @@ -85,7 +85,7 @@ project.send(:"add_#{user_role}", user) end - it { expect_allowed(:destroy_container_image) } + it { expect_allowed(:delete_container_image) } end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index d3b3b852dcf365..d9533b87653854 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -3221,7 +3221,7 @@ def update_access_level(project, feature, state) let(:developer_operations_permissions) do guest_operations_permissions + [ - :create_container_image, :update_container_image, :destroy_container_image, :destroy_container_image_tag + :create_container_image, :update_container_image, :delete_container_image, :delete_container_image_tag ] end diff --git a/spec/requests/api/graphql/mutations/container_registry/protection/tag_rule/delete_spec.rb b/spec/requests/api/graphql/mutations/container_registry/protection/tag_rule/delete_spec.rb index 2ffd1aead9b029..f0841bfa36af5d 100644 --- a/spec/requests/api/graphql/mutations/container_registry/protection/tag_rule/delete_spec.rb +++ b/spec/requests/api/graphql/mutations/container_registry/protection/tag_rule/delete_spec.rb @@ -21,7 +21,7 @@ stub_gitlab_api_client_to_support_gitlab_api(supported: true) end - specify { expect(described_class).to require_graphql_authorizations(:destroy_container_registry_protection_tag_rule) } + specify { expect(described_class).to require_graphql_authorizations(:delete_container_registry_protection_tag_rule) } subject(:post_graphql_mutation_request) do post_graphql_mutation(mutation, current_user: current_user) diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb index ec36bf8f8453ce..39377958c250f7 100644 --- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb +++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb @@ -67,7 +67,7 @@ create_commit_status create_container_image create_deployment create_environment create_merge_request_from create_pipeline create_release create_wiki - destroy_container_image destroy_container_image_tag push_code read_pod_logs + delete_container_image delete_container_image_tag push_code read_pod_logs read_terraform_state resolve_note update_build cancel_build update_container_image update_deployment update_environment update_merge_request update_pipeline update_release destroy_release -- GitLab From 37693402aecdb57a2efa93b30bb1783f18667875 Mon Sep 17 00:00:00 2001 From: Matthew MacRae-Bovell Date: Mon, 22 Sep 2025 10:57:04 -0400 Subject: [PATCH 2/5] Update permission name on destroy spec --- app/graphql/types/permission_types/container_repository.rb | 4 ++-- doc/api/graphql/reference/_index.md | 2 +- spec/graphql/mutations/container_repositories/destroy_spec.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/graphql/types/permission_types/container_repository.rb b/app/graphql/types/permission_types/container_repository.rb index f6a76fb4d940bf..f844a6b68d6f64 100644 --- a/app/graphql/types/permission_types/container_repository.rb +++ b/app/graphql/types/permission_types/container_repository.rb @@ -5,9 +5,9 @@ module PermissionTypes class ContainerRepository < BasePermissionType graphql_name 'ContainerRepositoryPermissions' - ability_field :destroy_container_image, + ability_field :delete_container_image, name: 'destroy_container_repository', - resolver_method: :destroy_container_image + resolver_method: :delete_container_image end end end diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index 71c6e40b1ec803..33443bebc8ed70 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -26904,7 +26904,7 @@ four standard [pagination arguments](#pagination-arguments): | Name | Type | Description | | ---- | ---- | ----------- | -| `destroyContainerRepository` | [`Boolean!`](#boolean) | If `true`, the user can perform `destroy_container_image` on this resource. | +| `destroyContainerRepository` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_container_image` on this resource. | ### `ContainerRepositoryReferrer` diff --git a/spec/graphql/mutations/container_repositories/destroy_spec.rb b/spec/graphql/mutations/container_repositories/destroy_spec.rb index ff2d35ffecf2a1..56a87d61e56d1f 100644 --- a/spec/graphql/mutations/container_repositories/destroy_spec.rb +++ b/spec/graphql/mutations/container_repositories/destroy_spec.rb @@ -12,7 +12,7 @@ let_it_be(:project) { container_repository.project } let(:id) { container_repository.to_global_id } - specify { expect(described_class).to require_graphql_authorizations(:destroy_container_image) } + specify { expect(described_class).to require_graphql_authorizations(:delete_container_image) } describe '#resolve' do let(:tags) { %w[a b c] } -- GitLab From bd9ec8b2cbf80ce7a170ffa414e23098f9f53605 Mon Sep 17 00:00:00 2001 From: Matthew MacRae-Bovell Date: Mon, 22 Sep 2025 11:32:59 -0400 Subject: [PATCH 3/5] Fix broken method name --- app/controllers/projects/registry/tags_controller.rb | 2 +- lib/api/project_container_repositories.rb | 2 +- .../controllers/projects/registry/tags_controller_spec.rb | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb index 295f93fa89d859..25b10e78f4b1e0 100644 --- a/app/controllers/projects/registry/tags_controller.rb +++ b/app/controllers/projects/registry/tags_controller.rb @@ -5,7 +5,7 @@ module Registry class TagsController < ::Projects::Registry::ApplicationController include PackagesHelper - before_action :authorize_destroy_container_image_tag!, only: [:destroy] + before_action :authorize_delete_container_image_tag!, only: [:destroy] LIMIT = 15 diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb index cc808ab77bff6b..eeeadf9e74f15b 100644 --- a/lib/api/project_container_repositories.rb +++ b/lib/api/project_container_repositories.rb @@ -194,7 +194,7 @@ class ProjectContainerRepositories < ::API::Base requires :tag_name, type: String, desc: 'The name of the tag' end delete ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do - authorize_destroy_container_image_tag! + authorize_delete_container_image_tag! result = ::Projects::ContainerRepository::DeleteTagsService .new(repository.project, current_user, tags: [declared_params[:tag_name]]) diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb index d043d35f72374d..08ce053fc48db4 100644 --- a/spec/controllers/projects/registry/tags_controller_spec.rb +++ b/spec/controllers/projects/registry/tags_controller_spec.rb @@ -83,7 +83,7 @@ def get_tags describe 'POST destroy' do before do - allow(controller).to receive(:authorize_destroy_container_image_tag!).and_call_original + allow(controller).to receive(:authorize_delete_container_image_tag!).and_call_original end context 'when user has access to registry' do @@ -101,7 +101,7 @@ def get_tags destroy_tag('rc1') - expect(controller).to have_received(:authorize_destroy_container_image_tag!) + expect(controller).to have_received(:authorize_delete_container_image_tag!) end it 'makes it possible to delete a tag that ends with a dot' do @@ -109,7 +109,7 @@ def get_tags destroy_tag('test.') - expect(controller).to have_received(:authorize_destroy_container_image_tag!) + expect(controller).to have_received(:authorize_delete_container_image_tag!) end it 'tracks the event', :snowplow do @@ -132,7 +132,7 @@ def get_tags it 'returns not_found' do destroy_tag('test.') - expect(controller).to have_received(:authorize_destroy_container_image_tag!) + expect(controller).to have_received(:authorize_delete_container_image_tag!) expect(response).to have_gitlab_http_status(:not_found) end end -- GitLab From b60211a75f3d2e2d1d4c2cbcd394edecc6604ac6 Mon Sep 17 00:00:00 2001 From: Matthew MacRae-Bovell Date: Mon, 22 Sep 2025 12:05:29 -0400 Subject: [PATCH 4/5] Update frontend permission --- .../project/components/container_protection_tag_rules.vue | 2 +- .../queries/get_container_protection_tag_rules.query.graphql | 2 +- .../container_registry/protection/tag_rule/delete_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/container_protection_tag_rules.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/container_protection_tag_rules.vue index 860af1e9738a78..ff9a7fcce6abb3 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/container_protection_tag_rules.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/container_protection_tag_rules.vue @@ -346,7 +346,7 @@ export default { @click="openEditFormDrawer(item)" /> container_protection_rule.minimum_access_level_for_delete.upcase, 'minimumAccessLevelForPush' => container_protection_rule.minimum_access_level_for_push.upcase, 'userPermissions' => { - 'destroyContainerRegistryProtectionTagRule' => true + 'deleteContainerRegistryProtectionTagRule' => true } ) ) -- GitLab From 03c01c754c7ca14b92b55396caf20263a95a1d45 Mon Sep 17 00:00:00 2001 From: Matthew MacRae-Bovell Date: Mon, 6 Oct 2025 14:15:39 -0400 Subject: [PATCH 5/5] Add deprecated fields back --- app/graphql/types/permission_types/container_repository.rb | 5 +++++ .../types/permission_types/container_repository_tag.rb | 5 +++++ doc/api/graphql/reference/_index.md | 2 ++ 3 files changed, 12 insertions(+) diff --git a/app/graphql/types/permission_types/container_repository.rb b/app/graphql/types/permission_types/container_repository.rb index f844a6b68d6f64..febcd8ca1e55b9 100644 --- a/app/graphql/types/permission_types/container_repository.rb +++ b/app/graphql/types/permission_types/container_repository.rb @@ -8,6 +8,11 @@ class ContainerRepository < BasePermissionType ability_field :delete_container_image, name: 'destroy_container_repository', resolver_method: :delete_container_image + + permission_field(:destroy_container_image, + deprecated: { milestone: '18.5', reason: :renamed, replacement: 'delete_container_image' }) + + alias_method :destroy_container_image, :delete_container_image end end end diff --git a/app/graphql/types/permission_types/container_repository_tag.rb b/app/graphql/types/permission_types/container_repository_tag.rb index fd28471c9af8f0..ce50f628f65816 100644 --- a/app/graphql/types/permission_types/container_repository_tag.rb +++ b/app/graphql/types/permission_types/container_repository_tag.rb @@ -8,6 +8,11 @@ class ContainerRepositoryTag < BasePermissionType ability_field :delete_container_image_tag, name: 'destroy_container_repository_tag', resolver_method: :delete_container_image_tag + + permission_field(:destroy_container_image_tag, + deprecated: { milestone: '18.5', reason: :renamed, replacement: 'delete_container_image_tag' }) + + alias_method :destroy_container_image_tag, :delete_container_image_tag end end end diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index 33443bebc8ed70..67048b2e407db0 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -26904,6 +26904,7 @@ four standard [pagination arguments](#pagination-arguments): | Name | Type | Description | | ---- | ---- | ----------- | +| `destroyContainerImage` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Deprecated** in GitLab 18.5. This was renamed. Use: `delete_container_image`. | | `destroyContainerRepository` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_container_image` on this resource. | ### `ContainerRepositoryReferrer` @@ -26975,6 +26976,7 @@ A tag from a container repository. | Name | Type | Description | | ---- | ---- | ----------- | +| `destroyContainerImageTag` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Deprecated** in GitLab 18.5. This was renamed. Use: `delete_container_image_tag`. | | `destroyContainerRepositoryTag` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_container_image_tag` on this resource. | ### `ContainerTagsExpirationPolicy` -- GitLab