Add audit events for label changes
What does this MR do and why?
Adds audit events for label creation, update, and deletion on project and group labels. This addresses Audit label creation, update and destroy events (#415036 - closed).
AI use notice: this MR is heavily based on Duo authoring.
Changes
Three new audit event types
-
label_created— recorded when a project or group label is created -
label_updated— recorded when a project or group label is updated. When the title changes, the message includes old and new values (e.g.Changed label title from Foo to Bar). For other field changes, a generic message is used (e.g.Updated label Foo), withadditional_detailscapturing which attributes changed. -
label_deleted— recorded when a project or group label is deleted
CE changes (minimal)
-
Labels::CreateServiceandLabels::UpdateServiceinitializers now accept an optional current_user as the first argument, followed by params. All callers are updated. - New
Labels::DestroyServicewrapslabel.destroy. Previously, label deletion was done inline via@label.destroyin controllers anddestroy_conditionally!in the API helper with no service object. -
prepend_mod_withadded to all three services for EE extension.
EE changes
- EE service overrides (EE::Labels::CreateService, EE::Labels::UpdateService, EE::Labels::DestroyService) that call Gitlab::Audit::Auditor.audit after successful operations.
- Three audit event YAML definitions in
ee/config/audit_events/types/.
Design decisions
Explicit nil for non-audited callers
Callers that should not produce audit events (e.g., FindOrCreateService, Jira import, admin template labels, seed tasks) pass nil explicitly as current_user: .new(nil, params). The EE overrides skip auditing when current_user is nil. This makes it easy to grep for .new(nil, to find all non-audited call sites, and ensures new callers must make a conscious choice.
CE changes kept minimal
Audit logic lives entirely in EE. The only CE changes are: (1) adding current_user to the service initializers, (2) creating DestroyService, and (3) adding prepend_mod_with lines.
This follows the established pattern used by EE::Projects::ArchiveService, EE::Keys::DestroyService, and others.
Title changes get special treatment
Renaming a label directly impacts users: filters, automation, and integrations depend on label titles.
The audit message for title changes includes the old and new values. Description and color changes are "backwards compatible" and use a generic message, with changed attributes recorded in additional_details for programmatic consumers.
Auto-created labels are not audited.
Labels created automatically (e.g., via FindOrCreateService during issue triage, or Jira imports) do not generate audit events because no current_user is passed. This is intentional and documented. I chose to do it this way to keep this change small.
Out of scope
- Admin/template labels — not audited (passed nil for
current_user) - Auditing label promote operations
Two tests were added for template labels (destroy_service_spec.rb and update_service_spec.rb)
solely to satisfy branch coverage requirements. When template label auditing is implemented, these coverage-only tests should be replaced with proper audit event assertions.
References
Screenshots or screen recordings
| Before | After |
|---|---|
![]() |
|
![]() |
How to set up and validate locally
Prerequisites
- GDK running with an EE/Ultimate license applied
- A group and/or project with at least one label
Steps
- Verify audit events for label creation
- Go to a group or project, for example http://127.0.0.1:3000/groups/twitter/-/labels.
- Select New label and create a label with a title, description, and color.
- Go to the audit events page: http://127.0.0.1:3000/groups/twitter/-/audit_events.
- Verify an entry exists with action Created label .
- Repeat for a project label at http://127.0.0.1:3000/<project_path>/-/labels and verify the audit event at http://127.0.0.1:3000/<project_path>/-/audit_events.
- Verify audit events for label update
- Edit an existing label and change only the title.
- Verify the audit event says Changed label title from to .
- Edit the same label and change only the description.
- Verify the audit event says Updated label .
- Edit the same label and change only the color.
- Verify the audit event says Updated label .
- Verify audit events for label deletion
- Delete a label from the labels page.
- Verify the audit event says Deleted label .
- Verify API endpoints produce audit events
# Create a label via API curl --header "PRIVATE-TOKEN: <your_token>" \ --data "name=API+Label&color=%23FF0000" \ "http://127.0.0.1:3000/api/v4/projects/<project_id>/labels" # Update a label via API curl --request PUT --header "PRIVATE-TOKEN: <your_token>" \ --data "new_name=Renamed+API+Label" \ "http://127.0.0.1:3000/api/v4/projects/<project_id>/labels/<label_id>" # Delete a label via API curl --request DELETE --header "PRIVATE-TOKEN: <your_token>" \ "http://127.0.0.1:3000/api/v4/projects/<project_id>/labels/<label_id>" - Verify auto-created labels are NOT audited
Verify that no label_created audit event appears for auto-created-label.
# Trigger a Jira import or create an issue with a new label via the API curl --header "PRIVATE-TOKEN: <your_token>" \ --data '{"title": "Test issue", "labels": "auto-created-label"}' \ --header "Content-Type: application/json" \ "http://127.0.0.1:3000/api/v4/projects/<project_id>/issues" - Verify admin/template labels are NOT audited
- Go to Admin > Labels (http://127.0.0.1:3000/admin/labels).
- Create, edit, and delete a template label.
- Verify no audit events are created (check Admin > Audit Events).
- Run the specs
# CE destroy service spec bundle exec rspec spec/services/labels/destroy_service_spec.rb # Existing CE specs (verify no regressions) bundle exec rspec spec/services/labels/create_service_spec.rb bundle exec rspec spec/services/labels/update_service_spec.rb # EE audit event specs bundle exec rspec ee/spec/services/ee/labels/create_service_spec.rb bundle exec rspec ee/spec/services/ee/labels/update_service_spec.rb bundle exec rspec ee/spec/services/ee/labels/destroy_service_spec.rb # Audit event type definition validation bundle exec rake gitlab:audit_event_types:check_docs
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #415036 (closed)

