Add audit event for group permanent deletion request
What does this MR do and why?
Adds a new group_permanent_deletion_requested audit event. It is written when a user explicitly requests permanent deletion of a group, before any destructive work begins.
Previously, no audit event was written at the point that permanent deletion was requested (i.e. when permanently_remove=true is passed). The existing group_destroyed event is only written after GroupDestroyWorker completes successfully. For large groups where the worker can run for hours, or in cases where the worker is interrupted, this left a gap in the audit trail with no record that permanent deletion was ever triggered.
The event is written in an EE override of Groups::DestroyService#async_execute (ee/app/services/ee/groups/destroy_service.rb). This is the method called by the group settings page (GroupsController#destroy), the admin area (Admin::GroupsController#destroy) and the REST API (DELETE /groups/:id with permanently_remove). It checks authorization, marks deletion in progress, and schedules GroupDestroyWorker. #execute runs later, inside that Sidekiq worker.
The event is written after the authorization check passes. Unauthorized users and blocked users get no event.
Because it is written in the request path:
- It captures the request context, including the IP address.
- It is written once per request, not on every worker run or retry (
GroupDestroyWorkerhasretry: 3). - It exists even if the worker later fails or is interrupted.
The scheduled deletion after the retention period goes through Namespaces::Groups::AdjournedDeletionService. That service schedules GroupDestroyWorker directly and does not call async_execute, so it does not produce this event. This lets admins tell an explicit user request apart from the scheduled job.
The complete audit trail for a group deletion is now:
group_deletion_marked— soft delete requestedgroup_permanent_deletion_requested— user explicitly requested permanent deletion (new; not written for scheduled deletion)group_destroyed— permanent deletion completed (written only on successful completion)
Specs cover:
- The event is logged once, with the correct attributes, from
async_execute. - No event for an unauthorized user.
- No event for a blocked user.
- No event from
#execute.
References
Screenshots or screen recordings
Not applicable — no UI changes.
How to set up and validate locally
- Create a group and mark it for deletion (Settings → General → Advanced → Delete group).
- In the Rails console, confirm the group is in a pending-deletion state:
Group.find_by_full_path('your-group').deletion_scheduled? - Visit the group settings page and click Delete group again, confirming permanent removal.
- Query the audit events:
group = Group.find_by_full_path('your-group') AuditEvents::GroupAuditEvent.where(group_id: group.id).order(:created_at).pluck(:event_name) # => ["group_deletion_marked", "group_permanent_deletion_requested", "group_destroyed"]
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.