Fix crash in combined search authorization filter
What does this MR do and why?
Fixes a 500 error in the REST search API for users who are denied read_cross_project.
Search::Elastic::Filters.by_combined_search_level_and_membership passes a Search::Elastic::BoolExpr to by_search_level_and_membership and by_search_level_and_group_membership. When the user is denied read_cross_project, those filters call match_none_filter(query_hash). That method writes to query_hash[:query][:bool][:filter], which a BoolExpr does not have. The result is NoMethodError: undefined method 'concat' for nil.
The fix checks cross_project_search_restricted_for_user? once at the top of by_combined_search_level_and_membership. If the user is restricted, it returns match_none_filter(query_hash) on the real query hash, before the nested filters are built. Users with cross-project access get the same query as before.
Who is affected:
- Only instances with external authorization enabled.
read_cross_projectis only denied then (app/policies/base_policy.rb), and never for admins or auditors. As far as we know, GitLab.com does not use it. GET /api/v4/searchandGET /api/v4/groups/:id/searchwithscope=issuesorscope=work_items. These are built bySearch::Elastic::WorkItemQueryBuilder. They returned a 500 instead of empty results.- Not affected: the web search page, because
SearchControllerusesrequires_cross_project_accessand returns 403 first. Project-level search is also not affected.
I found this while working on #630618, where milestone search moves to the same combined filter. An existing milestone spec for cross-project restriction failed.
!260603 needs this fix to merge first. Without it, that MR would bring the same 500 to milestone search.
References
- #630618
- !260603 (depends on this MR)
- https://docs.gitlab.com/administration/settings/external_authorization/
Screenshots or screen recordings
Reproduced in GDK as a non-admin user with external authorization enabled.
| Before | After |
|---|---|
![]() |
![]() |
Before: GET /api/v4/search?scope=work_items&search=probe returns {"message":"500 Internal Server Error"}, with the concat stack trace in log/development.log. After: it returns [].
How to set up and validate locally
Advanced search must be enabled.
-
In a Rails console, enable external authorization:
ApplicationSetting.current.update!(external_authorization_service_enabled: true, external_authorization_service_url: 'https://external-auth.invalid/check', external_authorization_service_default_label: 'default') -
Sign in as a user who is not an admin or auditor.
-
Open
https://gdk.test:3443/api/v4/search?scope=work_items&search=test. Expect[]. Before this change it returned a 500. -
Disable external authorization again:
ApplicationSetting.current.update!(external_authorization_service_enabled: false)
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

