Commit 95296bae authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch '36439-redact-2' into 'master'

Wrap Elasticsearch results as blob

See merge request gitlab-org/gitlab!22676
parents 26265cf1 5da6794d
......@@ -86,19 +86,6 @@ module SearchHelper
}).html_safe
end
def find_project_for_result_blob(projects, result)
@project
end
# Used in EE
def blob_projects(results)
nil
end
def parse_search_result(result)
result
end
# Overriden in EE
def search_blob_title(project, path)
path
......
......@@ -32,8 +32,7 @@
.term
= render 'shared/projects/list', projects: @search_objects, pipeline_status: false
- else
- locals = { projects: blob_projects(@search_objects) } if %w[blobs wiki_blobs].include?(@scope)
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects, locals: locals
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
- if @scope != 'projects'
= paginate_collection(@search_objects)
- project = find_project_for_result_blob(projects, blob)
- project = blob.project
- return unless project
- blob = parse_search_result(blob)
- blob_link = project_blob_path(project, tree_join(blob.ref, blob.path))
= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob.path, blob_link: blob_link }
- project = find_project_for_result_blob(projects, wiki_blob)
- wiki_blob = parse_search_result(wiki_blob)
- project = wiki_blob.project
- wiki_blob_link = project_wiki_path(project, wiki_blob.basename)
= render partial: 'search/results/blob_data', locals: { blob: wiki_blob, project: project, path: wiki_blob.path, blob_link: wiki_blob_link }
......@@ -13,29 +13,6 @@ module EE
options
end
override :find_project_for_result_blob
def find_project_for_result_blob(projects, result)
return super if result.is_a?(::Gitlab::Search::FoundBlob)
super || projects&.find { |project| project.id == blob_project_id(result) }
end
override :blob_projects
def blob_projects(results)
return super if results.first.is_a?(::Gitlab::Search::FoundBlob)
project_ids = results.map(&method(:blob_project_id))
::ProjectsFinder.new(current_user: current_user, project_ids_relation: project_ids).execute
end
override :parse_search_result
def parse_search_result(result)
return super if result.is_a?(::Gitlab::Search::FoundBlob)
::Gitlab::Elastic::SearchResults.parse_search_result(result)
end
override :search_blob_title
def search_blob_title(project, path)
if @project
......@@ -88,10 +65,6 @@ module EE
context.feature_available?(:multiple_issue_assignees))
end
def blob_project_id(blob_result)
blob_result.dig('_source', 'join_field', 'parent')&.split('_')&.last.to_i
end
def gitlab_com_snippet_db_search?
@current_user &&
@show_snippets &&
......
......@@ -7,8 +7,7 @@ module EE
# doesn't seem to be a common ancestor to check.
REDACTABLE_RESULTS = [
Kaminari::PaginatableArray,
Elasticsearch::Model::Response::Records,
Elasticsearch::Model::Response::Response
Elasticsearch::Model::Response::Records
].freeze
# This is a proper method instead of a `delegate` in order to
......
......@@ -21,17 +21,6 @@ module EE
def use_elasticsearch?(resource)
::Gitlab::CurrentSettings.search_using_elasticsearch?(scope: resource)
end
override :process_results
def process_results(results)
return [] if results.empty?
if results.any? { |result| result.is_a?(::Elasticsearch::Model::Response::Result) && result.respond_to?(:blob) }
return paginate(results).map { |blob| ::Gitlab::Elastic::SearchResults.parse_search_result(blob) }
end
super
end
end
end
end
......
......@@ -20,6 +20,16 @@ module Elastic
results
end
# @return [Kaminari::PaginatableArray]
def elastic_search_as_found_blob(query, page: 1, per: 20, options: {})
# Highlight is required for parse_search_result to locate relevant line
options = options.merge(highlight: true)
elastic_search_and_wrap(query, type: es_type, page: page, per: per, options: options) do |result, project|
::Gitlab::Elastic::SearchResults.parse_search_result(result, project)
end
end
private
def extract_repository_ids(options)
......@@ -156,7 +166,7 @@ module Elastic
}
end
options[:project_ids] = repository_ids.map { |id| id.to_s[/\d+/].to_i } if type == :wiki_blob && repository_ids.any?
options[:project_ids] = repository_ids.map { |id| id.to_s[/\d+/].to_i } if type.to_sym == :wiki_blob && repository_ids.any?
res = search(query_hash, options)
......@@ -165,6 +175,56 @@ module Elastic
total_count: res.size
}
end
# Wrap returned results into GitLab model objects and paginate
#
# @return [Kaminari::PaginatableArray]
def elastic_search_and_wrap(query, type:, page: 1, per: 20, options: {}, &blk)
type = type.to_s
response = elastic_search(
query,
type: type,
page: page,
per: per,
options: options
)[type.pluralize.to_sym][:results]
items, total_count = yield_each_search_result(response, type, &blk)
# Before "map" we had a paginated array so we need to recover it
offset = per * ((page || 1) - 1)
Kaminari.paginate_array(items, total_count: total_count, limit: per, offset: offset)
end
def yield_each_search_result(response, type)
# Avoid one SELECT per result by loading all projects into a hash
project_ids = response.map { |result| project_id_for_commit_or_blob(result, type) }.uniq
projects = Project.with_route.id_in(project_ids).index_by(&:id)
total_count = response.total_count
items = response.map do |result|
project_id = project_id_for_commit_or_blob(result, type)
project = projects[project_id]
if project.nil? || project.pending_delete?
total_count -= 1
next
end
yield(result, project)
end
# Remove results for deleted projects
items.compact!
[items, total_count]
end
# Indexed commit does not include project_id
def project_id_for_commit_or_blob(result, type)
result.dig('_source', 'project_id') || result.dig('_source', type, 'rid').to_i
end
end
end
end
......@@ -16,10 +16,18 @@ module Elastic
end
def elastic_search(query, type: :all, page: 1, per: 20, options: {})
options[:repository_id] = repository_id if options[:repository_id].nil?
options = repository_specific_options(options)
self.class.elastic_search(query, type: type, page: page, per: per, options: options)
end
# @return [Kaminari::PaginatableArray]
def elastic_search_as_found_blob(query, page: 1, per: 20, options: {})
options = repository_specific_options(options)
self.class.elastic_search_as_found_blob(query, page: page, per: per, options: options)
end
def delete_index_for_commits_and_blobs(wiki: false)
types =
if wiki
......@@ -62,6 +70,14 @@ module Elastic
def repository_id
raise NotImplementedError
end
def repository_specific_options(options)
if options[:repository_id].nil?
options = options.merge(repository_id: repository_id)
end
options
end
end
end
end
......@@ -8,6 +8,12 @@ module Elastic
def es_type
'wiki_blob'
end
def elastic_search_as_wiki_page(*args)
elastic_search_as_found_blob(*args).map! do |blob|
Gitlab::Search::FoundWikiPage.new(blob)
end
end
end
end
end
......@@ -8,6 +8,13 @@ module Elastic
delegate :project, to: :target
delegate :id, to: :project, prefix: true
# @return [Kaminari::PaginatableArray]
def elastic_search_as_wiki_page(query, page: 1, per: 20, options: {})
options = repository_specific_options(options)
self.class.elastic_search_as_wiki_page(query, page: page, per: per, options: options)
end
private
def repository_id
......
......@@ -9,30 +9,9 @@ module Elastic
'blob'
end
# @return [Kaminari::PaginatableArray]
def find_commits_by_message_with_elastic(query, page: 1, per_page: 20, options: {})
response = elastic_search(
query,
type: :commit,
page: page,
per: per_page,
options: options
)[:commits][:results]
response_count = response.total_count
# Avoid one SELECT per result by loading all projects into a hash
project_ids = response.map {|result| result["_source"]["commit"]["rid"] }.uniq
projects = Project.with_route.id_in(project_ids).index_by(&:id)
commits = response.map do |result|
project_id = result["_source"]["commit"]["rid"].to_i
project = projects[project_id]
if project.nil? || project.pending_delete?
response_count -= 1
next
end
elastic_search_and_wrap(query, type: :commit, page: page, per: per_page, options: options) do |result, project|
raw_commit = Gitlab::Git::Commit.new(
project.repository.raw,
prepare_commit(result['_source']['commit']),
......@@ -40,13 +19,6 @@ module Elastic
)
Commit.new(raw_commit, project)
end
# Remove results for deleted projects
commits.compact!
# Before "map" we had a paginated array so we need to recover it
offset = per_page * ((page || 1) - 1)
Kaminari.paginate_array(commits, total_count: response_count, limit: per_page, offset: offset)
end
private
......
......@@ -24,9 +24,9 @@ module Gitlab
when 'notes'
notes.page(page).per(per_page).records
when 'blobs'
blobs.page(page).per(per_page)
blobs(page: page, per_page: per_page)
when 'wiki_blobs'
wiki_blobs.page(page).per(per_page)
wiki_blobs(page: page, per_page: per_page)
when 'commits'
commits(page: page, per_page: per_page)
when 'users'
......@@ -42,7 +42,7 @@ module Gitlab
private
def blobs
def blobs(page: 1, per_page: 20)
return Kaminari.paginate_array([]) unless Ability.allowed?(@current_user, :download_code, project)
if project.empty_repo? || query.blank?
......@@ -50,11 +50,11 @@ module Gitlab
else
# We use elastic for default branch only
if root_ref?
project.repository.elastic_search(
project.repository.__elasticsearch__.elastic_search_as_found_blob(
query,
type: :blob,
options: { highlight: true }
)[:blobs][:results].response
page: (page || 1).to_i,
per: per_page
)
else
Kaminari.paginate_array(
Gitlab::FileFinder.new(project, repository_ref).find(query)
......@@ -63,15 +63,15 @@ module Gitlab
end
end
def wiki_blobs
def wiki_blobs(page: 1, per_page: 20)
return Kaminari.paginate_array([]) unless Ability.allowed?(@current_user, :read_wiki, project)
if project.wiki_enabled? && !project.wiki.empty? && query.present?
project.wiki.elastic_search(
project.wiki.__elasticsearch__.elastic_search_as_wiki_page(
query,
type: :wiki_blob,
options: { highlight: true }
)[:wiki_blobs][:results].response
page: (page || 1).to_i,
per: per_page
)
else
Kaminari.paginate_array([])
end
......
......@@ -37,9 +37,9 @@ module Gitlab
when 'notes'
eager_load(notes, page, eager: { project: [:route, :namespace] })
when 'blobs'
blobs.page(page).per(per_page)
blobs(page: page, per_page: per_page)
when 'wiki_blobs'
wiki_blobs.page(page).per(per_page)
wiki_blobs(page: page, per_page: per_page)
when 'commits'
commits(page: page, per_page: per_page)
when 'users'
......@@ -112,7 +112,7 @@ module Gitlab
false
end
def self.parse_search_result(result)
def self.parse_search_result(result, project)
ref = result["_source"]["blob"]["commit_sha"]
path = result["_source"]["blob"]["path"]
extname = File.extname(path)
......@@ -156,6 +156,7 @@ module Gitlab
ref: ref,
startline: from + 1,
data: data.join,
project: project,
project_id: project_id
)
end
......@@ -225,7 +226,7 @@ module Gitlab
end
end
def blobs
def blobs(page: 1, per_page: 20)
return Kaminari.paginate_array([]) if query.blank?
strong_memoize(:blobs) do
......@@ -233,15 +234,16 @@ module Gitlab
additional_filter: repository_filter(limit_project_ids)
)
Repository.elastic_search(
Repository.__elasticsearch__.elastic_search_as_found_blob(
query,
type: :blob,
options: options.merge({ highlight: true })
)[:blobs][:results].response
page: (page || 1).to_i,
per: per_page,
options: options
)
end
end
def wiki_blobs
def wiki_blobs(page: 1, per_page: 20)
return Kaminari.paginate_array([]) if query.blank?
strong_memoize(:wiki_blobs) do
......@@ -249,11 +251,12 @@ module Gitlab
additional_filter: wiki_filter(limit_project_ids)
)
ProjectWiki.elastic_search(
ProjectWiki.__elasticsearch__.elastic_search_as_wiki_page(
query,
type: :wiki_blob,
options: options.merge({ highlight: true })
)[:wiki_blobs][:results].response
page: (page || 1).to_i,
per: per_page,
options: options
)
end
end
......
......@@ -51,67 +51,6 @@ describe SearchHelper do
end
end
describe '#parse_search_result with elastic enabled', :elastic do
let(:user) { create(:user) }
before do
allow(self).to receive(:current_user).and_return(user)
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
end
it "returns parsed result", :sidekiq_might_not_need_inline do
project = create :project, :repository
project.repository.index_commits_and_blobs
Gitlab::Elastic::Helper.refresh_index
result = project.repository.elastic_search(
'def popen',
type: :blob,
options: { highlight: true }
)[:blobs][:results][0]
parsed_result = helper.parse_search_result(result)
expect(parsed_result.ref). to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
expect(parsed_result.path).to eq('files/ruby/popen.rb')
expect(parsed_result.startline).to eq(2)
expect(parsed_result.data).to include("Popen")
end
end
describe '#blob_projects', :elastic do
let(:user) { create(:user) }
before do
allow(self).to receive(:current_user).and_return(user)
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
end
def es_blob_search
Repository.elastic_search(
'def popen',
type: :blob,
options: { highlight: true }
)[:blobs][:results]
end
it 'returns all projects in the result page without causing an N+1', :sidekiq_might_not_need_inline do
control_count = ActiveRecord::QueryRecorder.new { blob_projects(es_blob_search) }.count
projects = create_list :project, 3, :repository, :public
projects.each { |project| project.repository.index_commits_and_blobs }
Gitlab::Elastic::Helper.refresh_index
# So we can access it outside the following block
result_projects = nil
expect { result_projects = blob_projects(es_blob_search) }.not_to exceed_query_limit(control_count)
expect(result_projects).to match_array(projects)
end
end
describe '#search_entries_info_template' do
let(:com_value) { true }
let(:flag_enabled) { true }
......
# frozen_string_literal: true
require 'spec_helper'
describe Elastic::Latest::GitClassProxy do
let_it_be(:project) { create(:project, :repository) }
let(:included_class) { Elastic::Latest::RepositoryClassProxy }
subject { included_class.new(project.repository) }
describe '#elastic_search_as_found_blob', :elastic do
before do
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
Gitlab::Elastic::Indexer.new(project).run
Gitlab::Elastic::Helper.refresh_index
end
it 'returns FoundBlob', :sidekiq_inline do
results = subject.elastic_search_as_found_blob('def popen')
expect(results).not_to be_empty
expect(results).to all(be_a(Gitlab::Search::FoundBlob))
result = results.first
expect(result.ref).to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
expect(result.path).to eq('files/ruby/popen.rb')
expect(result.startline).to eq(2)
expect(result.data).to include('Popen')
expect(result.project).to eq(project)
end
end
end
......@@ -51,6 +51,33 @@ describe Elastic::Latest::GitInstanceProxy do
end
end
describe '#elastic_search_as_found_blob' do
let(:params) do
{
page: 2,
per: 30,
options: { foo: :bar }
}
end
it 'provides repository_id if not provided' do
expected_params = params.deep_dup
expected_params[:options][:repository_id] = project.id
expect(subject.class).to receive(:elastic_search_as_found_blob).with('foo', expected_params)
subject.elastic_search_as_found_blob('foo', params)
end
it 'uses provided repository_id' do
params[:options][:repository_id] = 42
expect(subject.class).to receive(:elastic_search_as_found_blob).with('foo', params)
subject.elastic_search_as_found_blob('foo', params)
end
end
describe '#delete_index_for_commits_and_blobs' do
let(:write_targets) { [double(:write_target_1), double(:write_target_2)] }
let(:read_target) { double(:read_target) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Elastic::Latest::ProjectWikiClassProxy do
let_it_be(:project) { create(:project, :wiki_repo) }
subject { described_class.new(project.wiki.repository) }
describe '#elastic_search_as_wiki_page', :elastic do
let_it_be(:page) { create(:wiki_page, wiki: project.wiki) }
before do
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
Gitlab::Elastic::Indexer.new(project, wiki: true).run
Gitlab::Elastic::Helper.refresh_index
end
it 'returns FoundWikiPage', :sidekiq_inline do
results = subject.elastic_search_as_wiki_page('*')
expect(results.size).to eq(1)
expect(results).to all(be_a(Gitlab::Search::FoundWikiPage))
result = results.first
expect(result.path).to eq(page.path)
expect(result.startline).to eq(1)
expect(result.data).to include(page.content)
expect(result.project).to eq(project)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Elastic::Latest::ProjectWikiInstanceProxy do
let_it_be(:project) { create(:project, :wiki_repo) }
subject { described_class.new(project.wiki) }
describe '#elastic_search_as_wiki_page' do
let(:params) do
{
page: 2,
per: 30,
options: { foo: :bar }
}
end
it 'provides repository_id if not provided' do
expected_params = params.deep_dup
expected_params[:options][:repository_id] = "wiki_#{project.id}"
expect(subject.class).to receive(:elastic_search_as_wiki_page).with('foo', expected_params)
subject.elastic_search_as_wiki_page('foo', params)
end
it 'uses provided repository_id' do
params[:options][:repository_id] = "wiki_63"
expect(subject.class).to receive(:elastic_search_as_wiki_page).with('foo', params)
subject.elastic_search_as_wiki_page('foo', params)
end
end
end
......@@ -67,6 +67,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
end
describe 'parse_search_result' do
let(:project) { double(:project) }
let(:blob) do
{
'blob' => {
......@@ -78,11 +79,12 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
end
it 'returns an unhighlighted blob when no highlight data is present' do
parsed = described_class.parse_search_result('_source' => blob)
parsed = described_class.parse_search_result({ '_source' => blob }, project)
expect(parsed).to be_kind_of(::Gitlab::Search::FoundBlob)
expect(parsed).to have_attributes(
startline: 1,
project: project,
data: "foo\n"
)
end
......@@ -95,7 +97,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
}
}
parsed = described_class.parse_search_result(result)
parsed = described_class.parse_search_result(result, project)
expect(parsed).to be_kind_of(::Gitlab::Search::FoundBlob)
expect(parsed).to have_attributes(
......@@ -104,6 +106,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
basename: 'path/file',
ref: 'sha',
startline: 2,
project: project,
data: "bar\n"
)
end
......@@ -519,11 +522,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
end
def search_for(term)
blobs = described_class.new(user, term, [project_1.id]).objects('blobs')
blobs.map do |blob|
blob['_source']['blob']['path']
end
described_class.new(user, term, [project_1.id]).objects('blobs').map(&:path)
end
it_behaves_like 'a paginated object', 'blobs'
......@@ -532,7 +531,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
results = described_class.new(user, 'def', limit_project_ids)
blobs = results.objects('blobs')
expect(blobs.first['_source']['blob']['content']).to include('def')
expect(blobs.first.data).to include('def')
expect(results.blobs_count).to eq 7
end
......@@ -544,7 +543,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
results = described_class.new(user, 'def', [project_1.id])
expect(results.blobs_count).to eq 7
result_project_ids = results.objects('blobs').map { |r| r.dig('_source', 'project_id') }
result_project_ids = results.objects('blobs').map(&:project_id)
expect(result_project_ids.uniq).to eq([project_1.id])
results = described_class.new(user, 'def', [project_1.id, project_2.id])
......@@ -656,7 +655,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
it 'finds wiki blobs' do
blobs = results.objects('wiki_blobs')
expect(blobs.first['_source']['blob']['content']).to include("term")
expect(blobs.first.data).to include('term')
expect(results.wiki_blobs_count).to eq 1
end
......@@ -664,7 +663,7 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
project_1.add_guest(user)
blobs = results.objects('wiki_blobs')
expect(blobs.first['_source']['blob']['content']).to include("term")
expect(blobs.first.data).to include('term')
expect(results.wiki_blobs_count).to eq 1
end
......@@ -989,14 +988,14 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
results = described_class.new(user, 'term', limit_project_ids)
blobs = results.objects('wiki_blobs')
expect(blobs.map { |blob| blob.join_field.parent }).to match_array [internal_project.es_id, private_project2.es_id, public_project.es_id]
expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project]
expect(results.wiki_blobs_count).to eq 3
# Unauthenticated search
results = described_class.new(nil, 'term', [])
blobs = results.objects('wiki_blobs')
expect(blobs.first.join_field.parent).to eq public_project.es_id
expect(blobs.first.project).to eq public_project
expect(results.wiki_blobs_count).to eq 1
end
end
......@@ -1053,14 +1052,14 @@ describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need_inlin
results = described_class.new(user, 'tesla', limit_project_ids)
blobs = results.objects('blobs')
expect(blobs.map { |blob| blob.join_field.parent }).to match_array [internal_project.es_id, private_project2.es_id, public_project.es_id]
expect(blobs.map(&:project)).to match_array [internal_project, private_project2, public_project]
expect(results.blobs_count).to eq 3
# Unauthenticated search
results = described_class.new(nil, 'tesla', [])
blobs = results.objects('blobs')
expect(blobs.first.join_field.parent).to eq public_project.es_id
expect(blobs.first.project).to eq public_project
expect(results.blobs_count).to eq 1
end
end
......
......@@ -4,6 +4,77 @@ require 'spec_helper'
describe SearchService do
describe '#search_objects' do
context 'redacting search results (repository)', :elastic, :sidekiq_inline do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
subject(:search_service) { described_class.new(user, search: '*', scope: scope, page: 1) }
shared_examples 'it redacts incorrect results' do
before do
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
Gitlab::Elastic::Indexer.new(project).run
Gitlab::Elastic::Helper.refresh_index
# disable permission to test redaction
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, ability, a_kind_of(model_class)).and_return(allowed)
end
context 'when allowed' do
let(:allowed) { true }
it 'does nothing' do
results = subject.search_objects
expect(results).not_to be_empty
expect(results).to all(be_an(model_class))
end
end
context 'when disallowed' do
let(:allowed) { false }
it 'redacts results' do
results = subject.search_objects
expect(results).to be_empty
end
end
end
context 'commits' do
let(:scope) { 'commits' }
let(:model_class) { Commit }
let(:ability) { :read_commit }
it_behaves_like 'it redacts incorrect results'
end
context 'blobs' do
let(:scope) { 'blobs' }
let(:model_class) { Gitlab::Search::FoundBlob }
let(:ability) { :read_blob }
it_behaves_like 'it redacts incorrect results'
end
context 'wiki blobs' do
let(:project) { create(:project, :wiki_repo) }
let(:scope) { 'wiki_blobs' }
let(:model_class) { Gitlab::Search::FoundWikiPage }
let(:ability) { :read_wiki_page }
it_behaves_like 'it redacts incorrect results' do
before do
create(:wiki_page, wiki: project.wiki)
Gitlab::Elastic::Indexer.new(project, wiki: true).run
Gitlab::Elastic::Helper.refresh_index
end
end
end
end
context 'redacting search results' do
let(:user) { create(:user) }
......@@ -21,8 +92,6 @@ describe SearchService do
let(:note_on_unauthorized_issue) { create(:note, project: unauthorized_project, noteable: issue1_in_unauthorized_project) }
let(:merge_request_in_unauthorized_project) { create(:merge_request_with_diffs, target_project: unauthorized_project, source_project: unauthorized_project) }
let(:milestone_in_unauthorized_project) { create(:milestone, project: unauthorized_project) }
let(:wiki_page) { WikiPages::CreateService.new(unauthorized_project, user, { title: "foo", content: "wiki_blobs" }).execute }
let(:commit) { unauthorized_project.repository.commit(SeedRepo::FirstCommit::ID) }
let(:search_service) { described_class.new(user, search: 'some-search-string', page: 1) }
let(:mock_global_service) { instance_double(Search::GlobalService, scope: 'some-scope') }
......@@ -147,55 +216,6 @@ describe SearchService do
expect(subject).to be_kind_of(Kaminari::PaginatableArray)
expect(subject).to contain_exactly(note_on_issue_in_project)
end
it 'redacts commits the user does not have access to' do
allow(mock_results).to receive(:objects)
.and_return(
Kaminari.paginate_array(
[
commit
],
total_count: 1,
limit: 1,
offset: 0
)
)
expect(subject).to be_kind_of(Kaminari::PaginatableArray)
expect(subject).to be_empty
end
it 'redacts blobs the user does not have access to' do
blob = unauthorized_project.repository.blob_at(SeedRepo::FirstCommit::ID, 'README.md')
response = Elasticsearch::Model::Response::Response.new Blob, double(:search)
allow(response).to receive_messages(
results: [blob],
total_count: 1,
limit_value: 10,
offset_value: 0
)
allow(mock_results).to receive(:objects).and_return(response)
expect(subject).to be_kind_of(Kaminari::PaginatableArray)
expect(subject).to be_empty
end
it 'redacts wikis the user does not have access to' do
wiki_page = create(:wiki_page, wiki: unauthorized_project.wiki)
response = Elasticsearch::Model::Response::Response.new WikiPage, double(:search)
allow(response).to receive_messages(
results: [wiki_page],
total_count: 1,
limit_value: 10,
offset_value: 0
)
allow(mock_results).to receive(:objects).and_return(response)
expect(subject).to be_kind_of(Kaminari::PaginatableArray)
expect(subject).to be_empty
end
end
end
end
......@@ -32,10 +32,6 @@ module API
results = SearchService.new(current_user, search_params).search_objects
process_results(results)
end
def process_results(results)
paginate(results)
end
......
......@@ -7,6 +7,7 @@ module Gitlab
include Presentable
include BlobLanguageFromGitAttributes
include Gitlab::Utils::StrongMemoize
include BlobActiveModel
attr_reader :project, :content_match, :blob_path
......
# frozen_string_literal: true
# - rendering by using data purely from Elasticsearch and does not trigger Gitaly calls.
# - allows policy check
module Gitlab
module Search
class FoundWikiPage < SimpleDelegator
attr_reader :wiki
def self.declarative_policy_class
'WikiPagePolicy'
end
# @param found_blob [Gitlab::Search::FoundBlob]
def initialize(found_blob)
super
@wiki = found_blob.project.wiki
end
def to_ability_name
'wiki_page'
end
end
end
end
......@@ -156,4 +156,14 @@ describe Gitlab::Search::FoundBlob do
end
end
end
describe 'policy' do
let(:project) { build(:project, :repository) }
subject { described_class.new(project: project) }
it 'works with policy' do
expect(Ability.allowed?(project.creator, :read_blob, subject)).to be_truthy
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Search::FoundWikiPage do
let(:project) { create(:project, :public, :repository) }
describe 'policy' do
let(:project) { build(:project, :repository) }
let(:found_blob) { Gitlab::Search::FoundBlob.new(project: project) }
subject { described_class.new(found_blob) }
it 'works with policy' do
expect(Ability.allowed?(project.creator, :read_wiki_page, subject)).to be_truthy
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment