Skip to content

Protected containers: Integrate delete protection in REST API

What does this MR do and why?

Protected containers: Integrate delete protection in REST API

  • In GitLab v17.8, push protection for new container repositories has been released.
  • This commits adds the delete protection for container repositories
  • Addresses on of the necessary changes for deletion protection of container repositories described in issue #406797
  • This commits has been implemented in the context of the following EPIC &9825
  • This MR introduces the feature flag :container_registry_protected_containers_delete

Changelog: added

🛠️ with ❤️ at Siemens

References

Please include cross links to any resources that are relevant to this MR This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

MR Checklist (@gerardo-navarro)

Screenshots or screen recordings

Before this MR

When you send a DELETE request for the container repository to the REST API then hte container respository will be successfully scheduled for deletion.

curl -v --request DELETE \
  --url http://gdk.test:3000/api/v4/projects/7/registry/repositories/3 \
  --header 'PRIVATE-TOKEN: {{patWithoutAdminScope}}'

After this MR

When you send a DELETE request for the container repository to the REST API then you will receive a 403 error message with the following output. This will only work when the feature flag :container_registry_protected_containers_delete is enabled and the given container repository is protected.

curl -v --request DELETE \
  --url http://gdk.test:3000/api/v4/projects/7/registry/repositories/3 \
  --header 'PRIVATE-TOKEN: {{patWithoutAdminScope}}'
Click to expand the curl console output
* Host gdk.test:3000 was resolved.
* IPv6: (none)
* IPv4: 192.168.64.5
*   Trying 192.168.64.5:3000...
* Connected to gdk.test (192.168.64.5) port 3000
> DELETE /api/v4/projects/7/registry/repositories/3 HTTP/1.1
> Host: gdk.test:3000
> User-Agent: curl/8.7.1
> Accept: */*
> PRIVATE-TOKEN: {{patWithoutAdminScope}}
> 
* Request completely sent off
< HTTP/1.1 403 Forbidden
< Cache-Control: no-cache
< Content-Length: 80
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json
< Vary: Origin
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Gitlab-Meta: {"correlation_id":"01JNXP6AMVAPM0XDAJSMYEFDBR","version":"1"}
< X-Request-Id: 01JNXP6AMVAPM0XDAJSMYEFDBR
< X-Runtime: 0.078494
< Date: Sun, 09 Mar 2025 14:50:51 GMT
< 
* Connection #0 to host gdk.test left intact
{"message":"403 Forbidden - Deleting protected container repository forbidden."}%

How to set up and validate locally

  1. Enable the feature flag :container_registry_protected_containers_delete
Feature.enable(:container_registry_protected_containers_delete)
  1. Ensure the container regsitry is enabled.
  2. Push container image for a project to the container registry, e.g. flightjs/flight/protected-1
  3. Create a protection rule for the container repository
ContainerRegistry::Protection::Rule.create(
  project: Project.find_by_full_path('flightjs/Flight'),
  repository_path_pattern: 'flightjs/flight/protected*',
  minimum_access_level_for_delete: :admin,
  minimum_access_level_for_push: :admin
)
  1. Send a DELETE request to the REST API => this should fail because the container repository is protected 💥
curl -v --request DELETE \
  --url http://gdk.test:3000/api/v4/projects/7/registry/repositories/3 \
  --header 'PRIVATE-TOKEN: {{patWithoutAdminScope}}'
  1. Disable the feature flag
Feature.disable(:container_registry_protected_containers_delete)
  1. Send a DELETE request to the REST API => this time, the container repository shuold be scheduled for deletion because this functionality has been disabled before.
curl -v --request DELETE \
  --url http://gdk.test:3000/api/v4/projects/7/registry/repositories/3 \
  --header 'PRIVATE-TOKEN: {{patWithoutAdminScope}}'

Related to #406797

Edited by Gerardo Navarro

Merge request reports

Loading