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.rbee/spec/lib/gitlab_subscriptions/subscriptions_usage/user_usage_spec.rb
How to set up and validate locally
- As an owner of a root group with a GitLab Credits entitlement, open
/groups/<group>/-/settings/gitlab_credits_dashboard. - Stub
Gitlab::SubscriptionPortal::SubscriptionUsageClient#get_consumers(or point at a CDot with a mixed-deployment subscription) so theconsumersresponse includes auserIdthat exists on the instance but is not a member of the group hierarchy. - 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.
- I have evaluated the MR acceptance checklist for this MR.