Scope credits-sorted usage users to the namespace hierarchy

What does this MR do and why?

Related to https://gitlab.com/gitlab-org/customers-gitlab-com/-/work_items/19091 (confidential). RFH: https://gitlab.com/gitlab-com/request-for-help/-/work_items/5381 Root-cause fix in CustomersDot: https://gitlab.com/gitlab-org/customers-gitlab-com/-/merge_requests/17247

A group's GitLab Credits dashboard (/groups/:group/-/settings/gitlab_credits_dashboard) listed ~19 GitLab.com accounts that had never been members of the group, shown as consuming credits. The customer's subscription had been transferred from a self-managed instance to GitLab.com.

The dashboard's default sort (TOTAL_CREDITS_USED_DESC) goes through GitlabSubscriptions::SubscriptionsUsage::UserUsage#users_sorted_by_credits_used, which took the userIds from CustomersDot's usersUsage.consumers and resolved them with ::User.by_ids(user_ids) — no membership check. Those ids are consumer entity_ids; a transferred subscription still carries the old instance's consumers, whose entity_ids are local user ids from that instance. Small integers collided with old GitLab.com accounts.

The other branch of the same method (name sort / username / searchQuery) already resolves against users_from_descendant_members. This MR makes the credits-sorted branch use the same scope, so both paths have the same trust model for CustomersDot-supplied ids. Instance-level usage (subscription_target: :instance) keeps resolving against every user, since that is its scope.

This is defence in depth: the CustomersDot MR above stops the foreign ids being returned in the first place. The two are independent and safe to merge in either order.

References

  • ee/lib/gitlab_subscriptions/subscriptions_usage/user_usage.rb
  • ee/spec/lib/gitlab_subscriptions/subscriptions_usage/user_usage_spec.rb

How to set up and validate locally

  1. As an owner of a root group with a GitLab Credits entitlement, open /groups/<group>/-/settings/gitlab_credits_dashboard.
  2. Stub Gitlab::SubscriptionPortal::SubscriptionUsageClient#get_consumers (or point at a CDot with a mixed-deployment subscription) so the consumers response includes a userId that exists on the instance but is not a member of the group hierarchy.
  3. Before: that user is listed in the "Usage by user" table. After: only hierarchy members are listed; order and pagination cursors are preserved.

The new examples under when a returned user id does not belong to the namespace hierarchy in user_usage_spec.rb cover the namespace and instance cases.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Merge request reports

Loading
Loading