`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](https://docs.gitlab.com/api/issues/#update-an-issue), 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](https://docs.gitlab.com/api/issues/#update-an-issue) and authenticating with a project or group access token
3. Notice the issue closes, but the HTTP response is [500](https://http.cat/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](https://handbook.gitlab.com/handbook/engineering/releases/patch-releases) to a version
under [the maintenance policy](https://docs.gitlab.com/policy/maintenance/), please follow the steps on the
[patch release runbook for GitLab engineers](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/patch/engineers.md).
Refer to the [internal "Release Information" dashboard](https://dashboards.gitlab.net/d/delivery-release_info/delivery3a-release-information?orgId=1)
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](https://handbook.gitlab.com/handbook/engineering/releases/internal-releases/) for single-tenant SaaS instances,
refer to the [internal release process for engineers](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/internal-releases/engineers.md?ref_type=heads).
---
## Root Cause Analysis
The audit event name is dynamically generated in `app/services/issues/close_service.rb` (lines 58-60):
```ruby
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).
### 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`:
```yaml
---
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: <MR URL>
feature_category: service_desk
milestone: '<current milestone>'
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`):
```ruby
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) |
issue