Skip to content

[2.x] fix: scope UserResource groups relationship to viewable groups#4629

Merged
imorland merged 2 commits into
2.xfrom
im/user-resource-hidden-groups
May 6, 2026
Merged

[2.x] fix: scope UserResource groups relationship to viewable groups#4629
imorland merged 2 commits into
2.xfrom
im/user-resource-hidden-groups

Conversation

@imorland

@imorland imorland commented May 6, 2026

Copy link
Copy Markdown
Member

Summary

GET /api/users/{id} was including hidden group IDs in data.relationships.groups.data for actors without the viewHiddenGroups permission.

The groups ToMany relationship on UserResource resolved against the unfiltered User::groups() Eloquent relation, so linkage leaked hidden group IDs even though GroupResource::scope() correctly filtered the hidden groups themselves out of the included resources. The frontend store (and User.badges() rendering) therefore received hidden group references it shouldn't have known about.

Adds a get() callback on the relationship that returns User::visibleGroups() (which already excludes is_hidden = 1) for actors without viewHiddenGroups, mirroring the visibility check in Group\Access\ScopeGroupVisibility.

Fixes #4618

Changes

  • framework/core/src/Api/Resource/UserResource.php — add ->get(...) to the groups relationship that branches on $context->getActor()->can('viewHiddenGroups').
  • New test file framework/core/tests/integration/api/users/ShowGroupsRelationshipTest.php covering guest, normal user, and admin actors against /api/users/{id}.

Test plan

  • New ShowGroupsRelationshipTest passes (3 tests, 9 assertions).
  • All existing user + group API integration tests still pass (123 tests, 274 assertions).
  • Manual: assign a hidden group to a user, request /api/users/{id} as guest / non-privileged member — confirm relationships.groups.data only contains visible group IDs.
  • Manual: same request as admin — confirm both visible and hidden group IDs appear.

Notes

  • Backward compatible — third-party consumers reading relationships.groups.data were already broken on the hidden-groups case (the included resources weren't there); now the linkage matches the included resources.
  • The same field declaration is reused for Update and Index endpoints (both defaultInclude(['groups'])), so the fix applies there too.

The groups ToMany relationship on UserResource resolved against
User::groups() unfiltered, so relationships.groups.data leaked hidden
group IDs to actors without viewHiddenGroups — even though
GroupResource::scope() filtered out the hidden groups themselves from
the included resources.

Add a get() callback that returns User::visibleGroups() for actors
without viewHiddenGroups, mirroring the visibility check used by
ScopeGroupVisibility.

Fixes #4618
@imorland imorland requested a review from a team as a code owner May 6, 2026 18:35
@imorland imorland added this to the 2.0.0-rc.2 milestone May 6, 2026
@imorland imorland merged commit 354286d into 2.x May 6, 2026
25 checks passed
@imorland imorland deleted the im/user-resource-hidden-groups branch May 6, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UserResource groups relationship exposes hidden group linkage to actors without viewHiddenGroups

2 participants