Check for tag protection rules when deleting container images
What does this MR do and why?
We are introducing tag protection rules for a project. In this MR, we want to add the check such that when the container image's project has tag protection rules and the current user's access level is below the minimum_access_level_for_delete of those rules, we then block the deletion. We prevent the deletion as long as there are tag protection rules and regardless if their tag_name_pattern matches the container image's name as it is an expensive operation to do (see discussion in https://gitlab.com/gitlab-org/gitlab/-/issues/505442#note_2331748390).
We prevent deletion by adding a condition to the ContainerRepositoryPolicy that when true prevents destroy_container_image.
How to set up and validate locally
Prerequisites:
A. Create a tag protection rule for a project:
project = Project.find(id) # assign a project to the project variable
ContainerRegistry::Protection::TagRule.create(
project: project,
tag_name_pattern: 'sampleonly',
minimum_access_level_for_delete: 'admin',
minimum_access_level_for_push: 'maintainer'
)
B. There should be some container images in the project that we can try to delete
C. An admin account (to test that the tag rules will be allowed) and also a maintainer account (to test that it will be blocked it's below the minimum_access_level_for_delete)
👉 Scenario A: Feature flag is disabled
The tag protection rules do not matter. Container images can be deleted for both the admin and maintainer account.
Feature.disable(:container_registry_protected_tags)
👉 Scenario B: Feature flag is enabled
Feature.enable(:container_registry_protected_tags)
For the maintainer account, the delete button should be disabled and you are not able to delete the container image.
Aside from the UI restriction, when trying to delete the container image via GraphQL on the maintainer account, it would also result to an error:
mutation {
destroyContainerRepository(input: {id: "gid://gitlab/ContainerRepository/230"} ) {
containerRepository {
id
}
}
}
Result:
{
"errors": [
{
"graphQLErrors": [
{
"message": "The resource that you are attempting to access does not exist or you don't have permission to perform this action",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"destroyContainerRepository"
]
}
],
...
}
]
}
For the admin account, deletion should be enabled and succeed.
Related to #517513


