Add audit event for group permanent deletion request

Summary

When a group is permanently deleted, there is no audit event written to record that the permanent deletion was requested. This creates a gap in the audit trail that is particularly significant for large groups where the deletion worker may run for an extended period.

Current Behaviour

The group deletion flow produces the following audit events:

  • group_deletion_marked - written when the soft delete is requested (group enters pending deletion state)
  • group_destroyed - written only after GroupDestroyWorker has fully completed and the group record no longer exists in the database

There is no audit event written at the point that permanent deletion is explicitly requested (i.e. when permanently_remove=true is passed to GroupsController#destroy).

The permanent deletion request is captured in production_json.log as an HTTP request entry, but this is a request log and is not surfaced in the audit UI or audit events API.

Impact

For large groups containing many projects, GroupDestroyWorker can run for an extended period - potentially many hours. During this time:

  • The audit UI shows only group_deletion_marked, giving no indication that permanent deletion has been requested or is in progress
  • Administrators have no audit trail evidence that permanent deletion was explicitly triggered, as distinct from the scheduled background job that runs after the retention period expires
  • If the worker is interrupted before completion, group_destroyed is never written, leaving the audit trail with only the soft delete event and no record of the permanent deletion request

This makes it difficult to:

  • Distinguish between a user-initiated permanent deletion and the scheduled retention-period job
  • Determine when permanent deletion was requested in cases where the worker runs for a long time or is interrupted
  • Provide a complete audit trail for compliance purposes

Expected Behaviour

An audit event should be written at the point that permanent deletion is requested, before GroupDestroyWorker begins execution. This event should be written regardless of whether the worker completes successfully or is interrupted.

A suitable event name would be group_permanent_deletion_requested or similar, consistent with the existing naming convention.

Code Reference

The group_deletion_marked audit event is written in ee/app/services/ee/namespaces/mark_for_deletion_base_service.rb via log_event. An equivalent audit event for permanent deletion should be written in Groups::DestroyService or EE::Groups::DestroyService at the point execution begins, prior to any destructive operations.

The group_destroyed audit event is written in ee/app/services/ee/groups/destroy_service.rb in log_audit_event, which is only called after group&.persisted? returns false. This confirms that no audit event currently covers the initiation of permanent deletion.

Proposal

Add a new audit event, for example group_permanent_deletion_requested, written at the start of Groups::DestroyService#execute or unsafe_execute, before any projects or subgroups are destroyed. This would ensure the audit trail captures:

  1. group_deletion_marked - soft delete requested
  2. group_permanent_deletion_requested - permanent deletion initiated (new)
  3. group_destroyed - permanent deletion completed (written only on successful completion)

This would provide a complete and accurate audit trail for the full lifecycle of a group deletion, including long-running or interrupted deletions.

Edited by Iomhar Noone