Allow one request to link several AI service accounts
What does this MR do and why?
Requesting a review from two AI reviewers in a single quick action (for example /request_review @GitLabDuo @duo-security-review-gitlab) returned a 500. Gitlab::Auth::Identity raised TooManyIdentitiesLinkedError whenever a request linked more than one composite identity, but a request legitimately links one per composite service account named in reviewer_ids, plus one per AI flow it starts.
The guard protected the single-valued read in currently_linked rather than an authorization rule, so this scopes it to the case that is genuinely single-valued: a request may act as at most one authenticated principal, while any number of service accounts may be linked so their permissions can be checked. The guard now raises before writing to the request store, so a rescued failure no longer makes every later link in the request raise. That cascade is why the failure surfaced as an unrescued 500 in Ai::FlowTriggers::RunService rather than as one localised failure.
currently_linked and find_primary_user_by_scoped_user_id prefer the authenticated identity, then the most recently linked one, so an incidental link cannot decide authorization and each AI flow propagates its own service account to Gitaly, Workhorse, and background jobs. resolve_composite_identity_actor now reads the link context of the primary user it resolved rather than the request-wide one, which would otherwise attribute a human's writes to a service account linked only for a permission check.
The two AI flow-start services now link with the :permission_check context. They relied on the :authentication default, which recorded the service account as the request's principal and attributed writes made after the flow started to it. A human initiated these requests, so the human is the actor.
References
Screenshots or screen recordings
How to set up and validate locally
- Configure two AI service accounts with
composite_identity_enforced: true, each backed by a flow trigger on the same project for theassign_reviewerevent. - On a merge request in that project, comment
/request_review @first-account @second-account. - Before this change the comment fails with a 500 (
TooManyIdentitiesLinkedError) and only one flow starts. After it, both reviewers are assigned and both flows start.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.