Add metrics and event tracking for Immutable Container Tags

Overview

This MR adds usage metrics, a setting metric, and internal event tracking for Immutable Container Tags feature. This is the third and final MR in a series to split container registry protection instrumentation into smaller, focused changes.

What's Changed

Metrics Added (EE-only - Ultimate tier)

Database Metrics (state)

  1. counts.projects_with_container_registry_immutable_tag_rules

    • Count of distinct projects that have at least one immutable container tag rule
    • Instrumentation: CountProjectsWithContainerRegistryImmutableTagRulesMetric
  2. counts.container_registry_immutable_tag_rules

    • Total count of all immutable container tag rules across all projects
    • Instrumentation: CountContainerRegistryImmutableTagRulesMetric
  3. counts.distinct_top_level_groups_with_container_registry_immutable_tag_rules

    • Count of distinct top-level groups (customers) that have projects with immutable container tag rules
    • Instrumentation: CountDistinctTopLevelGroupsWithContainerRegistryImmutableTagRulesMetric
  4. settings.container_registry_immutable_tag_rules_enabled

    • Boolean indicating whether immutable container tag rules feature is enabled on the instance
    • Instrumentation: ContainerRegistryImmutableTagRulesEnabledMetric

Event-Based Metrics (activity)

  1. counts.create_container_registry_immutable_tag_rule
    • Count of immutable container tag rules created (all-time)
    • Data source: internal_events

Event Tracking

  1. create_container_registry_immutable_tag_rule
    • Tracked in EE::ContainerRegistry::Protection::CreateTagRuleService override
    • Includes context: project, namespace, user, additional_properties: { rule_type: 'immutable' }

Note: The delete_container_registry_protected_tag_rule event (tracked in DeleteTagRuleService) is shared with mutable tag rules and was included in MR 2. The rule_type context distinguishes between mutable and immutable rules.

Files Changed

  • Metrics: 4 new metric instrumentation classes (EE - in ee/lib/)
  • Metric Definitions: 5 new metric YAML files (EE - in ee/config/metrics/)
    • 3 database metrics
    • 1 setting metric
    • 1 event-based metric
  • Events: 1 new event YAML definition (EE - in ee/config/events/)
  • Service Classes: Added event tracking in EE CreateTagRuleService override
  • Specs: Added tests for metrics and event tracking (EE - in ee/spec/)

Why Metrics Are in EE

Immutable container tag rules are an EE-only feature (Ultimate tier), so all metrics and event tracking are implemented in EE. This is a licensed feature that requires an Ultimate license.

[Keep the Database Review section as-is - it's already correct]

Testing

  • Metric instrumentation specs added
  • Event tracking specs added in EE service specs
  • All existing tests pass

Related MRs

This MR is part of a series:

  • MR 1: Protected Container Repositories - !213721 (merged)
  • MR 2: Protected Container Tags (mutable) - !213723 (merged)
  • MR 3 (this MR): Immutable Container Tags

Feature Information

  • Feature: Immutable Container Tags
  • Feature Availability: Ultimate tier only (EE feature)
  • Metrics Tracking: EE (Ultimate tier only)
  • Product Group: Container Registry
  • Product Category: Container Registry

Database Review

This MR adds three new database metrics for immutable container tag rules. Below are the SQL queries for database review.

Query 1: counts.container_registry_immutable_tag_rules

Description: Total count of immutable container tag rules

SQL Query:

SELECT COUNT("container_registry_protection_tag_rules"."id")
FROM "container_registry_protection_tag_rules"
WHERE "container_registry_protection_tag_rules"."minimum_access_level_for_push" IS NULL
AND "container_registry_protection_tag_rules"."minimum_access_level_for_delete" IS NULL;

Query Plan:

Summary:


Query 2: counts.projects_with_container_registry_immutable_tag_rules

Description: Count of distinct projects with immutable container tag rules

SQL Query:

SELECT COUNT(DISTINCT "container_registry_protection_tag_rules"."project_id")
FROM "container_registry_protection_tag_rules"
WHERE "container_registry_protection_tag_rules"."minimum_access_level_for_push" IS NULL
AND "container_registry_protection_tag_rules"."minimum_access_level_for_delete" IS NULL;

Query Plan:

Summary:


Query 3: counts.distinct_top_level_groups_with_container_registry_immutable_tag_rules

Description: Count of distinct top-level groups with immutable container tag rules

SQL Query:

SELECT COUNT(DISTINCT "root_namespaces"."id")
FROM "container_registry_protection_tag_rules"
INNER JOIN "projects" ON "projects"."id" = "container_registry_protection_tag_rules"."project_id"
INNER JOIN "namespaces" ON "namespaces"."id" = "projects"."namespace_id"
INNER JOIN namespaces AS root_namespaces ON root_namespaces.id = namespaces.traversal_ids[1]
WHERE "container_registry_protection_tag_rules"."minimum_access_level_for_push" IS NULL
AND "container_registry_protection_tag_rules"."minimum_access_level_for_delete" IS NULL
AND (root_namespaces.type = 'Group' AND root_namespaces.parent_id IS NULL);

Query Plan:

Summary:

  • Link: https://postgres.ai/console/gitlab/gitlab-production-main/sessions/45807/commands/140238
  • Execution time: 271.956 ms (planning: 6.182 ms, execution: 265.774 ms)
  • Uses Sort operation with multiple joins (container_registry_protection_tag_rules → projects → namespaces → root_namespaces)
  • Found 43 rows in the snapshot
  • Most time spent on I/O reads (259.289 ms) - acceptable for a Service Ping metric that runs periodically, not in real-time
  • Uses array indexing on traversal_ids[1] which is a common pattern in GitLab for hierarchical namespace structures

Notes

  • All metrics use time_frame: all, so they count all records without time constraints
  • The queries filter for immutable tag rules only (using the .immutable scope) by selecting rules where both minimum_access_level_for_push and minimum_access_level_for_delete are NULL
  • The queries are executed as part of Service Ping collection
  • The container_registry_protection_tag_rules table has a foreign key index on project_id which will help with Query 2
  • Query 3 uses array indexing on traversal_ids[1] to get the root namespace, which is a common pattern in GitLab for hierarchical namespace structures
  • All queries are simple aggregations that should scale well as the table grows
Edited by Tim Rizzi

Merge request reports

Loading