Protected container tags: Add PATCH endpoint to REST API

What does this MR do and why?

Implements the PATCH endpoint at /api/v4/projects/:id/registry/protection/tag/rules/:protection_rule_id to enable partial updates of container registry protection tag rules. This completes the REST API implementation alongside the existing GET endpoint.

The endpoint supports true PATCH semantics using declared_params(include_missing: false), allowing updates to individual fields without requiring all parameters. Users can send empty strings to unset optional access levels.

Key implementation details:

  • Nested resource routing with :protection_rule_id parameter
  • All parameters optional for partial update support
  • Scoped find prevents cross-project rule modifications
  • Reuses existing UpdateTagRuleService for consistency
  • Supports EE immutable rules (both access levels nil)

The implementation handles both CE and EE validation rules correctly, where CE requires both access levels present while EE allows both to be nil for immutable tag rules.

🛠️ with ❤️ at Siemens

References

Screenshots or screen recordings

N/A - Backend API endpoint only

How to set up and validate locally

Test full update:

# Create a test rule first (if needed)
curl -X POST -H "PRIVATE-TOKEN: <your-token>" \
  -H "Content-Type: application/json" \
  -d '{"tag_name_pattern":"original-*","minimum_access_level_for_push":"maintainer","minimum_access_level_for_delete":"maintainer"}' \
  "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules"

# Update all fields
curl -X PATCH -H "PRIVATE-TOKEN: <your-token>" \
  -H "Content-Type: application/json" \
  -d '{"tag_name_pattern":"updated-*","minimum_access_level_for_push":"owner","minimum_access_level_for_delete":"admin"}' \
  "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules/<rule-id>"

Test partial update (single field):

curl -X PATCH -H "PRIVATE-TOKEN: <your-token>" \
  -H "Content-Type: application/json" \
  -d '{"tag_name_pattern":"partial-*"}' \
  "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules/<rule-id>"

Test unsetting access level (EE only - creates immutable rule):

curl -X PATCH -H "PRIVATE-TOKEN: <your-token>" \
  -H "Content-Type: application/json" \
  -d '{"minimum_access_level_for_push":"","minimum_access_level_for_delete":""}' \
  "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules/<rule-id>"

Verify the tests pass:

bundle exec rspec spec/requests/api/project_container_registry_protection_tag_rules_spec.rb

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)
Edited by Shabini Rajadas

Merge request reports

Loading