Protected container tags: Add GET endpoint for container protection tag rules API
What does this MR do and why?
Implements the GET endpoint at /api/v4/projects/:id/registry/protection/tag/rules to list container registry protection tag rules for a project. This enables REST API access to tag protection rules, providing feature parity with the existing GraphQL API and enabling automation through tools like Terraform that do not support GraphQL.
The implementation follows established patterns from container repository protection rules REST API and package protection rules REST API. It reuses the existing ContainerRegistry::Protection::TagRule model and authorization via :admin_container_image permission (maintainer or higher).
Technical changes:
- Created API entity exposing
id,project_id,tag_name_pattern,minimum_access_level_for_push,minimum_access_level_for_delete - Added GET endpoint with centralized authorization in
after_validationblock - Registered new API class in
lib/api/api.rb - Added comprehensive request specs using GitLab shared examples for authorization testing
Test coverage includes 10 examples verifying success cases, authorization for all roles (reporter, developer, guest, non-member), empty results, and error scenarios (invalid project, invalid token).
This is the first of four endpoints for full CRUD operations on container protection tag rules. POST, PATCH, and DELETE endpoints will follow in subsequent merge requests.
References
Main issue:
- Closes #581199
Related issues:
- Container repository protection rules REST API: #457518 (closed)
Reference implementations:
- Container repository protection rules REST API: !155798 (merged), !157925 (merged), !158756 (merged), !159619 (merged)
- Package protection rules REST API: !153436 (merged), !153571 (merged), !153577 (merged), !151741 (merged)
Documentation:
Screenshots or screen recordings
N/A - This is a REST API endpoint with no UI changes.
How to set up and validate locally
-
Create a test project and container protection tag rule via Rails console:
project = Project.find_by_full_path('flightjs/flight') rule = ContainerRegistry::Protection::TagRule.create!( project: project, tag_name_pattern: 'v*', minimum_access_level_for_push: :maintainer, minimum_access_level_for_delete: :maintainer ) -
Test the GET endpoint with curl:
curl -H "PRIVATE-TOKEN: <your-token>" \ "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules" -
Expected response (HTTP 200)
✅ :[ { "id": 1, "project_id": 123, "tag_name_pattern": "v*", "minimum_access_level_for_push": "maintainer", "minimum_access_level_for_delete": "maintainer" } ] -
Test authorization with a developer user (should return 403 Forbidden):
curl -H "PRIVATE-TOKEN: <developer-token>" \ "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules"
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)
-
Changelog entry added, if necessary -
Documentation created/updated via this MR -
Documentation reviewed by technical writer or follow-up review issue created -
Tests added for this feature/bug -
Tested in all supported browsers - N/A for API endpoints -
Conforms to the code review guidelines -
Conforms to the style guides -
Conforms to the javascript style guides - N/A for backend-only changes -
Conforms to the database guides - N/A, no database changes -
Conforms to the merge request performance guidelines -
Follows established patterns from container repository protection rules API -
Uses existing model and services, no schema changes required -
Authorization properly implemented using :admin_container_imagepermission -
Test coverage includes all authorization scenarios using shared examples -
API entity structure follows GitLab conventions -
API documentation will be added in follow-up MR after all CRUD endpoints are complete