Draft: Return public and internal project snippets to non-members
What does this MR do and why?
Step 3 of 3 for #35760.
Advanced Search never returned public or internal project snippets to users who are not project members. The same was true for admins without admin mode. Elastic::Latest::SnippetClassProxy#filter_project_snippets only matched snippets in user.authorized_projects. Basic search did return these snippets.
filter_project_snippets now has a second branch next to the existing membership branch. It matches a project snippet when both of these are true:
project_visibility_leveland the snippet'svisibility_levelare both inGitlab::VisibilityLevel.levels_for_user(user).snippets_access_levelisProjectFeature::ENABLED.
The existing read_cross_project check still applies first. The new branch is only added once the backfill_project_access_on_snippets migration has finished. This way, search never relies on documents that don't have the new fields yet.
This stack must merge in order:
- !259626 (merged) indexes
project_visibility_levelandsnippets_access_levelon project snippet documents. - !259752 (merged) adds the
BackfillProjectAccessOnSnippetsmigration. - This MR.
This MR is stacked on the branch of step 2. It must merge after both.
The rule matches ProjectSnippetPolicy for non-members.
How the rule was checked
The rule was compared against Ability.allowed?(user, :read_snippet, snippet) across these inputs:
- Project visibility: public, internal, private.
- Snippets access level: enabled, private, disabled.
- Snippet visibility.
- Users: anonymous, regular, external, admin without admin mode, guest member.
There were no differences.
External users only get public snippets, because levels_for_user returns only public for them. Private projects and private snippets never match the new branch.
Also removed:
- The 8 pending rows in
ee/spec/services/ee/search/snippet_service_spec.rb. They now pass. - The
pending:option inee/spec/support/helpers/search_results_helpers.rb. It has no other caller. - The TODO in
ee/lib/elastic/latest/snippet_instance_proxy.rb.
Tests
ee/spec/models/concerns/elastic/snippet_spec.rbhas a new spec. A non-member finds a public project snippet. A non-member does not find it when the backfill migration has not finished. The spec fails if the new branch is removed.ee/spec/features/search/elastic/snippet_search_spec.rbused a public project snippet in a non-member project as its check that the Elasticsearch path is in use. That check relied on this bug. The spec now asserts that this snippet is shown.- The new check uses a snippet that matches the query only through its file name. Basic search (
Snippet.search) matches title, description, and file name. The Elasticsearch path matches title and description only. The header comment is updated to match. - Known gap, not changed here: the
:anonymousrows in the snippet visibility table pass vacuously.user_from_membership(:anonymous)returns nil, andexpect_search_resultsiterates overArray(users).
References
- Closes #35760
- Step 1: !259626 (merged)
- Step 2: !259752 (merged)
- Related: !259299 also edits the pending rows. This MR removes them, so that MR would no longer be needed.
Screenshots or screen recordings
Not applicable. Search results only change for non-members. There is no UI change.
How to set up and validate locally
- Enable Advanced Search in GDK and make sure all migrations have finished.
- Sign in as a user who is not a member of a public project that has snippets enabled.
- In global snippet search, search for the title of a public project snippet in that project. The snippet now appears.
- Set the project's snippets feature to "Only project members".
- Search again. The snippet no longer appears.
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.