Add audit events for LDAP group link create/destroy
What does this MR do and why?
Neither creating nor removing an LDAP group link emitted an audit event, so admins had no audit trail for LDAP group sync configuration changes.
This MR is the first step: moves create/destroy into service objects (Members::CreateLdapGroupLinkService, updated Members::DestroyLdapGroupLinkService) so audit events can be wired in cleanly, matching the pattern already used for SAML group links and the LDAP block audit events (!247146 (merged), !248851 (merged)).
Two new audit event types are added: ldap_group_link_created and ldap_group_link_removed, both group-scoped. There is no update/edit path for LDAP group links anywhere in the codebase (routes are only: [:index, :create, :destroy], same on the API) — changing a link means destroying the old one and creating a new one, which the two events already cover together, so no separate "updated" event is needed.
Screenshots or screen recordings
How to set up and validate locally
Real bin/rails runner session against this branch on a local GDK (organization/visibility_level required by this instance's Group validations):
organization = Organizations::Organization.default_organization
group = Group.create!(
name: "Audit Demo Group",
path: "audit-demo-group-8072",
visibility_level: Gitlab::VisibilityLevel::PRIVATE,
organization: organization
)
group.create_namespace_settings!
admin = User.find_by(username: "root")
link = Members::CreateLdapGroupLinkService.execute(
group: group,
params: { cn: "engineering", group_access: Gitlab::Access::DEVELOPER, provider: "ldapmain" },
current_user: admin
)
AuditEvents::GroupAuditEvent.where(group_id: group.id).last.details[:custom_message]
# => "LDAP group link created. CN - engineering, Access Level - Developer, Provider - ldapmain"
Members::DestroyLdapGroupLinkService.execute(link, current_user: admin)
AuditEvents::GroupAuditEvent.where(group_id: group.id).order(:id).last.details[:custom_message]
# => "LDAP group link removed. CN - engineering, Access Level - Developer, Provider - ldapmain"Both events are also visible in the group's Secure > Audit events page (screenshot above), captured on this branch on a real GDK instance.
Also covered by request specs at the controller and API level (ee/spec/requests/groups/ldap_group_links_controller_spec.rb, ee/spec/requests/api/ldap_group_links_spec.rb) and unit specs for both services.
References
Closes #8072 (closed)
Disclosure
Implementation, service-object refactor, and test coverage were AI-assisted (Claude Code), following the shape already established by !247146 (merged) and !248851 (merged). The audit messages and screenshot above were captured by actually running the code on a local GDK checkout of this branch, not written from assumption. All specs (service, controller, and API level) were run and confirmed green, and rubocop was run clean, before pushing.
