Incorrect membership source attribution when users have multiple inheritance paths
## Summary
When users have membership through multiple inheritance paths (direct membership, subgroup inheritance, and/or group invites), GitLab incorrectly displays the membership source. The system should always display the source of the user's **highest permission level**, but currently shows incorrect or incomplete information about where that permission originates.
This manifests in several ways:
1. **Subgroup invite scenario**: When a subgroup is invited to a project and users are inherited through that subgroup, the source shows the top-level parent group instead of the invited subgroup
2. **Data integrity issue**: In [some cases](https://gitlab.com/gitlab-org/gitlab/-/work_items/504386), users who were never members of a namespace are shown as the source of membership
3. **Complex inheritance with role escalation**: When users have both direct group membership and subgroup membership with higher roles, and the subgroup is invited to a project, the source displays the lower-permission path instead of the highest-permission path
## Expected Behavior
**Core principle**: The membership source should always reflect where the user's displayed **highest permission** comes from.
When a user has multiple possible sources of access to a project:
- Display the source that grants the highest role
- Use the correct membership type ("Shared" vs "Inherited" vs "Direct") based on that highest-permission source
- Show the most specific group/path in the inheritance chain
**Membership type definitions:**
- **Shared**: Access comes from a group being invited to the group or project (group sharing)
- **Inherited**: Access comes from being a member of a parent group/namespace in the hierarchy
- **Direct**: User was directly added to the project
## Steps to Reproduce
### Scenario A: Subgroup invite with simple inheritance
1. Create a user `test` and add them to the `test` group
2. Ensure the `test/banking` subgroup inherits users from the `test` parent group
3. Add the `test/banking` group to `deploy/test/banking/banking` (another top-level group's project) via group invite
4. Navigate to the `deploy/test/banking/banking` project members page
5. Observe the inheritance information for user `test`
**Current Behavior:** User `test` displays `Source: Inherited from test` (top-level parent group)
**Expected Behavior:** User `test` should display `Source: Invited group test/banking` with membership type "Shared" (because the access comes from the subgroup being invited to the project)
### Scenario B: Complex inheritance with role escalation

1. Create a top-level group "Group 1" (with path `group-1`)
2. Create a subgroup within "Group 1" (`group-1/subgroup`)
3. Create a project within "Group 1" (`group-1/target-project`)
4. Invite a user (`example-user`) to "Group 1" with the **Guest** role
5. Invite `example-user` to `group-1/subgroup` with the **Developer** role
6. Invite `group-1/subgroup` to `group-1/target-project` with Developer permissions
7. View the `group-1/target-project > Manage > Members` page and check the "Source" for `example-user`
**Current Behavior:** `example-user` shows `Source: Inherited from Group 1` with Guest role
**Expected Behavior:** `example-user` should show `Source: Invited group group-1/subgroup` with Developer role and membership type "Shared" (because the highest permission comes from the subgroup being invited to the project, not the inherited Guest role from the parent)
**Example Project:** https://gitlab.com/membership-type-bug/target-project
### Scenario C: Incorrect non-member attribution
**Current Behavior:** [Users who aren't and have never been members of a namespace](https://gitlab.com/gitlab-org/gitlab/-/work_items/504386) are shown as the source of membership
**Expected Behavior:** Only actual members in the inheritance chain should be shown as sources
**Note:** This scenario is intermittent and affects certain namespaces - full reproduction steps not yet identified.
## Current vs Expected Comparison
| Scenario | Current Behavior | Expected Behavior | Expected Membership Type |
|----------|-----------------|-------------------|--------------------------|
| User in parent group → subgroup invited to project | Shows "Inherited from parent-group" | Shows "Invited group subgroup" | Shared |
| User: Parent (Guest) + Subgroup (Developer) → subgroup invited to project | Shows "Inherited from parent-group" (Guest) | Shows "Invited group subgroup" (Developer) | Shared |
| Non-member shown as source | Shows incorrect user as source | Shows actual source in permission inheritance chain | [Depends on actual source] |
## Impact
- **Permission auditing is unreliable**: Users cannot accurately determine who has access and why
- **Security confusion**: May lead to misunderstandings about actual access paths and permission levels
- **Troubleshooting difficulty**: Makes debugging permission issues significantly harder
- **User trust**: Violates principle of least surprise for access management
- **Compliance risk**: Incorrect source attribution could cause issues in security audits
## Technical Investigation Needed
- How does the system currently determine which source to display when multiple paths exist?
- Is there logic to compare permission levels across different sources?
- Are there edge cases where the "highest permission source" might be ambiguous?
- What happens when permissions are equal from multiple sources?
issue