Audit event type YML file is not defined for ticket_closed_by_project_bot. returned when a group or project access token is used to close a Service Desk ticket

Summary

When attempting to close a Service Desk ticket using the Issues API, and authenticating with a project or group access token, the user is returned with a 500 error, however the work item closes successfully.

Checking Rails logs, you can see the below logged exception.

Audit event type YML file is not defined for ticket_closed_by_project_bot. Please read https://docs.gitlab.com/ee/development/audit_event_guide/#how-to-instrument-new-audit-events for adding a new audit event

Steps to reproduce

  1. Create a service desk ticket in a project
  2. Attempt to close the service desk issue using the API and authenticating with a project or group access token
  3. Notice the issue closes, but the HTTP response is 500

Example Project

N/A

What is the current bug behavior?

An erroneous 500 response is returned, and no audit event is created for the service desk issue being closed.

What is the expected correct behavior?

A non-500 response should be returned, and an audit event should be created for the closure.

Relevant logs and/or screenshots

Output of checks

This bug happens on GitLab.com

Results of GitLab environment info

<details> <summary>Expand for output related to GitLab environment info</summary>

<pre>

(For installations with omnibus-gitlab package run and paste the output of: sudo gitlab-rake gitlab:env:info)

(For installations from source run and paste the output of: sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production)

</pre> </details>

Results of GitLab application Check

<details> <summary>Expand for output related to the GitLab application check</summary> <pre>

(For installations with omnibus-gitlab package run and paste the output of: sudo gitlab-rake gitlab:check SANITIZE=true)

(For installations from source run and paste the output of: sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)

(we will only investigate if the tests are passing)

</pre> </details>

Possible fixes

Patch release information for backports

If the bug fix needs to be backported in a patch release to a version under the maintenance policy, please follow the steps on the patch release runbook for GitLab engineers.

Refer to the internal "Release Information" dashboard for information about the next patch release, including the targeted versions, expected release date, and current status.

High-severity bug remediation

To remediate high-severity issues requiring an internal release for single-tenant SaaS instances, refer to the internal release process for engineers.


Root Cause Analysis

The audit event name is dynamically generated in app/services/issues/close_service.rb (lines 58-60):

if current_user.project_bot?
  log_audit_event(issue, current_user, "#{issue.issue_type}_closed_by_project_bot",
    "Closed #{issue.issue_type.humanize(capitalize: false)} #{issue.title}")
end

When issue.issue_type returns ticket, the generated audit event name becomes ticket_closed_by_project_bot. However, no corresponding YML definition exists in ee/config/audit_events/types/, causing the error.

This gap exists because the ticket work item type was introduced as part of the Service Desk migration to work items after the original audit events were created in GitLab 16.1 (!121485 (merged)).

Why "project_bot" in the naming

The _by_project_bot suffix is a historical artifact. Both project and group access tokens create users with user_type: project_bot (defined in app/models/concerns/has_user_type.rb). The check current_user.project_bot? returns true for both token types, which is why the audit event naming uses project_bot even when a group access token is used.


Implementation Plan

1. Create audit event type definitions

Add the following files in ee/config/audit_events/types/:

  • ticket_closed_by_project_bot.yml
  • ticket_reopened_by_project_bot.yml
  • ticket_created_by_project_bot.yml (proactive, for future API support)

Each file should follow the existing pattern. Example for ticket_closed_by_project_bot.yml:

---
name: ticket_closed_by_project_bot
description: A Service Desk ticket is closed using a project access token
introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/592448
introduced_by_mr: &lt;MR URL&gt;
feature_category: service_desk
milestone: '&lt;current milestone&gt;'
saved_to_database: true
streamed: true
scope: [Project]

2. Regenerate audit event documentation

  • Run bundle exec rake gitlab:audit_event_types:compile_docs to update doc/user/compliance/audit_event_types.md

3. Add specs

Update existing spec files to include ticket-specific test cases:

  • ee/spec/services/ee/issues/close_service_spec.rb - Add test for closing a ticket with a project bot user
  • ee/spec/services/ee/issues/reopen_service_spec.rb - Add test for reopening a ticket with a project bot user
  • ee/spec/workers/ee/new_issue_worker_spec.rb - Add test for ticket creation audit event (proactive)

Example spec pattern (based on existing issue tests in ee/spec/services/ee/issues/close_service_spec.rb):

context 'when closing a ticket with project bot' do
  let(:service) { described_class.new(container: project, current_user: project_bot) }
  let_it_be(:project_bot) { create(:user, :project_bot, email: "bot@example.com") }
  let_it_be(:ticket_type) { create(:work_item_type, :ticket) }

  before do
    project.add_maintainer(project_bot)
  end

  include_examples 'audit event logging' do
    let(:ticket) { create(:issue, title: "My ticket", project: project, author: project_bot, work_item_type: ticket_type) }
    let(:operation) { service.execute(ticket) }
    let(:event_type) { 'ticket_closed_by_project_bot' }
    let(:fail_condition!) { expect(project_bot).to receive(:project_bot?).and_return(false) }
    let(:attributes) do
      {
        author_id: project_bot.id,
        entity_id: ticket.project.id,
        entity_type: 'Project',
        details: {
          author_name: project_bot.name,
          event_name: "ticket_closed_by_project_bot",
          target_id: ticket.id,
          target_type: 'Issue',
          target_details: {
            iid: ticket.iid,
            id: ticket.id
          }.to_s,
          author_class: project_bot.class.name,
          custom_message: "Closed ticket #{ticket.title}"
        }
      }
    end
  end
end

4. Verify the fix

  • Manually test closing a Service Desk ticket via API with a project access token
  • Manually test closing a Service Desk ticket via API with a group access token
  • Verify audit event is recorded in the project's audit events
  • Verify no 500 error is returned

Files to Create

File Purpose
ee/config/audit_events/types/ticket_closed_by_project_bot.yml Audit event definition for closing tickets
ee/config/audit_events/types/ticket_reopened_by_project_bot.yml Audit event definition for reopening tickets
ee/config/audit_events/types/ticket_created_by_project_bot.yml Audit event definition for creating tickets (proactive)

Files to Update

File Change
doc/user/compliance/audit_event_types.md Auto-generated via rake task
ee/spec/services/ee/issues/close_service_spec.rb Add ticket-specific audit event test
ee/spec/services/ee/issues/reopen_service_spec.rb Add ticket-specific audit event test
ee/spec/workers/ee/new_issue_worker_spec.rb Add ticket-specific audit event test (proactive)
Edited by Marc Saleiko