Implement update group secret mutation

What does this MR do and why?

This MR implements the update mutation for group-level secrets as part of the group secrets management feature. This is MR 3 in the implementation sequence, building on the create mutation from !218365 (closed).

What this adds:

  • groupSecretUpdate GraphQL mutation - Allows updating existing group secrets with optimistic locking
  • Internal event tracking for group secret updates
  • Metrics definitions for tracking update operations
  • Comprehensive test coverage for update scenarios

Key implementation details:

Update mutation features:

  • Partial updates - Only specified fields are updated; omitted fields remain unchanged
  • Optimistic locking - Uses metadata_cas (Compare-And-Set) parameter to prevent concurrent update conflicts
  • Flexible updates - Can update any combination of: description, secret value, environment, or protected status
  • Policy management - Automatically updates CI policies when environment or protected status changes
  • Error handling - Returns user-friendly errors for conflicts, missing secrets, or validation failures

Optimistic locking (metadata_cas):

  • Client must provide the current metadataVersion when updating
  • If another update occurred since the client read the secret, the update fails with a clear error message
  • Prevents lost updates in concurrent scenarios
  • Metadata version increments with each successful update

Update flow:

  1. Validate the secret exists and user has permissions
  2. Update metadata with update_started_at timestamp (using metadata_cas for conflict detection)
  3. Update secret value in OpenBao (if provided)
  4. Refresh CI policies if environment or protected status changed
  5. Update metadata with update_completed_at timestamp
  6. Return updated secret with new metadata version

Analytics and metrics:

  • update_group_ci_secret internal event tracking
  • Metrics for unique users and namespaces updating group secrets
  • Total count of group secret updates
  • Aligns with existing project secret update metrics

Additional changes:

  • Removes additional_properties.label from update_ci_secret event (no longer needed)
  • Adds missing metrics definitions for project secret updates
  • Ensures consistent event tracking between project and group secrets

Dependencies

This MR depends on !218365 (closed) being merged first. Will rebase on master once merged.

Sample GraphQL Queries

Update a group secret (full update):

mutation {
  groupSecretUpdate(input: {
    groupPath: "gitlab-org"
    name: "DATABASE_PASSWORD"
    description: "Updated production database password"
    secret: "new-secret-value"
    environment: "production"
    protected: false
    metadataCas: 2
  }) {
    groupSecret {
      name
      description
      environment
      protected
      metadataVersion
      status
    }
    errors
  }
}

Update only specific fields (partial update):

mutation {
  groupSecretUpdate(input: {
    groupPath: "gitlab-org"
    name: "DATABASE_PASSWORD"
    description: "Updated description only"
    metadataCas: 2
  }) {
    groupSecret {
      name
      description
      metadataVersion
    }
    errors
  }
}

Update only the secret value:

mutation {
  groupSecretUpdate(input: {
    groupPath: "gitlab-org"
    name: "DATABASE_PASSWORD"
    secret: "new-secret-value"
    metadataCas: 2
  }) {
    groupSecret {
      name
      metadataVersion
    }
    errors
  }
}

Error response when metadata version doesn't match:

{
  "data": {
    "groupSecretUpdate": {
      "groupSecret": null,
      "errors": [
        "This secret has been modified recently. Please refresh the page and try again."
      ]
    }
  }
}

Related to #577342

This is MR 3 based on !217485 (comment 2989161362)

Edited by Erick Bajao

Merge request reports

Loading