Protected Containers tags: Add DELETE endpoint to REST API

What does this MR do and why?

Implements the DELETE endpoint for container protection tag rules to complete the REST API CRUD operations. The endpoint allows maintainers to remove protection rules via REST API at /api/v4/projects/:id/registry/protection/tag/rules/:rule_id.

The implementation follows the established pattern from container registry repository rules, using destroy_conditionally! helper for optimistic locking support and delegating deletion logic to the existing DeleteTagRuleService. Returns 204 No Content on success with proper authorization checks for maintainer access.

Technical changes:

  • Added nested resource with :protection_rule_id parameter
  • DELETE endpoint uses destroy_conditionally! for optimistic locking via If-Unmodified-Since header
  • Delegates to DeleteTagRuleService for business logic and validation
  • Returns 204 No Content with empty body on successful deletion
  • Proper error handling with 400 Bad Request for service errors

Test coverage includes 12 examples verifying successful deletion, authorization for all roles, error cases (non-existent rule, invalid format, cross-project security), and optimistic locking with precondition failed (412) responses.

This completes the REST API alongside the existing GET endpoint, enabling full management of container tag protection rules via REST API for infrastructure-as-code tools like Terraform.

🛠️ with ❤️ at Siemens

References

Main issue:

Previous MR in this series:

  • GET endpoint: (Add MR link when available)

Reference implementations:

  • Container repository protection rules DELETE endpoint: lib/api/project_container_registry_protection_rules.rb:109-128
  • Helper implementation: lib/api/helpers.rb:47-60 (destroy_conditionally!)

Documentation:

Screenshots or screen recordings

N/A - This is a REST API endpoint with no UI changes.

How to set up and validate locally

  1. Start your GitLab Development Kit:

    gdk start
  2. Create a test project and container protection tag rule via Rails console:

    project = Project.find_by_full_path('root/test-project')
    rule = ContainerRegistry::Protection::TagRule.create!(
      project: project,
      tag_name_pattern: 'test-delete-*',
      minimum_access_level_for_push: :maintainer,
      minimum_access_level_for_delete: :maintainer
    )
    rule_id = rule.id
  3. Get a personal access token (via UI or console):

    token = PersonalAccessToken.create!(user: User.first, name: 'test-api', scopes: ['api'])
    token.token  # Copy this token
  4. Test the DELETE endpoint with curl:

    curl -i -X DELETE -H "PRIVATE-TOKEN: <your-token>" \
      "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules/<rule-id>"
  5. Expected response (HTTP 204 No Content):

    HTTP/1.1 204 No Content

    (Empty body)

  6. Verify deletion:

    ContainerRegistry::Protection::TagRule.find(rule_id)
    # Should raise ActiveRecord::RecordNotFound
  7. Test optimistic locking with If-Unmodified-Since header:

    rule = ContainerRegistry::Protection::TagRule.create!(
      project: project,
      tag_name_pattern: 'lock-test-*',
      minimum_access_level_for_push: :maintainer,
      minimum_access_level_for_delete: :maintainer
    )
    # With old timestamp (should fail with 412)
    curl -i -X DELETE -H "PRIVATE-TOKEN: <your-token>" \
      -H "If-Unmodified-Since: Mon, 01 Jan 2000 00:00:00 GMT" \
      "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules/<rule-id>"
  8. Test authorization with a developer user (should return 403 Forbidden):

    curl -i -X DELETE -H "PRIVATE-TOKEN: <developer-token>" \
      "http://gdk.test:3000/api/v4/projects/<project-id>/registry/protection/tag/rules/<rule-id>"
  9. Run the automated tests:

    bundle exec rspec spec/requests/api/project_container_registry_protection_tag_rules_spec.rb -e "DELETE"

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)

Merge request reports

Loading