Expose humanAuthor on AiAuditEvent GraphQL type
What does this MR do and why?
Adds a humanAuthor field of type UserType to Types::AuditEvents::AiAuditEventType, resolved from details['human_author_id'] stored in the event. Updates both session audit event GraphQL queries to fetch humanAuthor, and renders <Service account> on behalf of <Human> in the Agent artifacts UI.
Under composite identity, IngestAuditEventsService sets author_id to the service account and records the human in details as human_author_id, human_author_name, and human_author_username. To render the "on behalf of" attribution with a link to the human's profile, the frontend needs a webPath and avatarUrl — which details does not carry.
Why resolve from human_author_id rather than alternatives:
- Constructing
/{username}in the frontend is fragile (breaks under relative URL root, produces dead links after renames or for deleted users) - Storing
web_path/avatar_urlindetailsat ingest only works for new events, leaving existing compliance data broken
Resolving from human_author_id works retroactively for all existing events, stays correct after renames, and requires no storage or streaming changes.
Performance: Both author and human_author route through the same private batch_load_user method, which uses a single BatchLoader::GraphQL block. batch-loader groups pending loads by block source location, so sharing the block means one User.id_in(...) query per page regardless of how many events are on the page.
References
- Related to https://gitlab.com/gitlab-org/gitlab/-/work_items/611655
- Parent issue: https://gitlab.com/gitlab-org/gitlab/-/work_items/607616
- Backend change that introduced
human_author_*in details: !247149 (merged)
Screenshots or screen recordings
How to set up and validate locally
- Create a composite-identity session (service account acting on behalf of a human user)
- Navigate to GraphQL explorer
- Use the following query to verify the human user is returned in the response
query getGroupSessionAuditEvents(
$groupFullPath: ID!
$workflowId: AiDuoWorkflowsWorkflowID!
$after: String
$before: String
$first: Int
$last: Int
) {
group(fullPath: $groupFullPath) {
id
duoWorkflowSessionArtifacts(workflowId: $workflowId) {
nodes {
id
auditEvents(after: $after, before: $before, first: $first, last: $last) {
nodes {
id
author {
id
name
username
avatarUrl
webPath
}
humanAuthor {
id
name
username
avatarUrl
webPath
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
}
}
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.
