Fix composite identity support for dependency proxy access

What does this MR do and why?

Duo bot service accounts (composite_identity_enforced: true) were denied access to the dependency proxy for two reasons:

  1. GroupPolicy#dependency_proxy_access_allowed checked the service account's own group membership. Service accounts are only added as project-level members, so max_member_access_for_user returned NO_ACCESS for the group, causing the primary ability check to fail before the composite identity dual-check could run.

  2. Composite identity was not re-linked when the JWT was consumed. The dependency proxy uses a two-step flow: a short-lived JWT is issued at /jwt/auth and then used for the actual image pull. The JWT only carried user_id, so the scoped user context established during OAuth authentication was lost. When JwtAuthenticatable reconstructed current_user from the JWT, no composite identity was linked in the request store, causing Identity#valid? to return false.

Fix

  • Embed scoped_user_id in the dependency proxy JWT when composite identity is linked at token-issuance time (ContainerProxyAuthenticationService).
  • Re-link the composite identity in JwtAuthenticatable when the JWT is consumed, using the embedded scoped_user_id.
  • Define User#ai_service_account? as service_account? && composite_identity_enforced?. All composite-identity-enforced service accounts are AI bots, so this is both accurate and free of fragile username-prefix heuristics.
  • Add an ai_service_account_with_composite_identity condition to GroupPolicy so AI service accounts with an active composite identity link pass the primary policy check. The scoped user's group membership is left entirely to Ability#with_composite_identity_check, keeping the policy free of redundant access-level lookups.

How the dual-check works

When Ability.allowed? is called for a user with composite_identity_enforced?, it runs the ability check twice: once for the current user (the AI service account) and once for the scoped user. Both must pass. The ai_service_account_with_composite_identity policy condition handles the service account side; Ability#with_composite_identity_check independently verifies Ability.allowed?(scoped_user, :read_dependency_proxy, group) for the scoped user side. Cross-group protection follows automatically — a linked identity from a different group will fail the scoped user's membership check.

References

Relates to #594535 (closed)

Edited by Stan Hu

Merge request reports

Loading