Commit 53869dc2 authored by Mark Chao's avatar Mark Chao

ES: update permission spec table

Remove impossible cases due to private project's features can only be
private or disabled.

Fix spec due to sidekiq indexing not triggered.

Update guest use cases: some features has additional constraint that
"Guest users are able to perform action on public/internal projects,
but not private ones."
parent 4a525497
......@@ -18,16 +18,16 @@ describe Search::GlobalService do
let(:service) { described_class.new(user, params) }
end
context 'visibility', :elastic do
context 'visibility', :elastic, :sidekiq_inline do
include_context 'ProjectPolicyTable context'
set(:group) { create(:group) }
let(:project) { create(:project, project_level, namespace: group) }
let(:project2) { create(:project, project_level) }
let(:user) { create_user_from_membership(project, membership) }
context 'merge request' do
let!(:merge_request) { create :merge_request, target_project: project, source_project: project }
let!(:note) { create :note, project: project, noteable: merge_request }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_reporter_feature_access
......@@ -35,41 +35,118 @@ describe Search::GlobalService do
with_them do
it "respects visibility" do
[project, project2].each do |project|
update_feature_access_level(project, feature_access_level)
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'merge_requests', expected_count: expected_count) do |user|
expect_search_results(user, 'merge_requests', expected_count: expected_count, pending: pending?) do |user|
described_class.new(user, search: merge_request.title).execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(user, search: note.note).execute
end
end
end
end
context 'code' do
let!(:project) { create(:project, project_level, :repository, namespace: group ) }
let!(:project2) { create(:project, project_level, :repository) }
let!(:note) { create :note_on_commit, project: project }
let(:pendings) do
[
{ project_level: :public, feature_access_level: :private, membership: :guest, expected_count: 1 },
{ project_level: :internal, feature_access_level: :private, membership: :guest, expected_count: 1 }
]
end
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
permission_table_for_guest_feature_access_and_non_private_project_only
end
with_them do
it "respects visibility" do
[project, project2].each do |project|
update_feature_access_level(project, feature_access_level)
ElasticCommitIndexerWorker.new.perform(project.id)
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'commits', expected_count: expected_count) do |user|
expect_search_results(user, 'commits', expected_count: expected_count, pending: pending?) do |user|
described_class.new(user, search: 'initial').execute
end
expect_search_results(user, 'blobs', expected_count: expected_count) do |user|
described_class.new(user, search: '.gitmodules').execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(user, search: note.note).execute
end
end
end
end
context 'issue' do
let!(:issue) { create :issue, project: project }
let!(:note) { create :note, project: project, noteable: issue }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
update_feature_access_level(project, feature_access_level)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'issues', expected_count: expected_count) do |user|
described_class.new(user, search: issue.title).execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(user, search: note.note).execute
end
end
end
end
context 'wiki' do
let!(:project) { create(:project, project_level, :wiki_repo) }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
project.wiki.create_page('test.md', '# term')
project.wiki.index_wiki_blobs
update_feature_access_level(project, feature_access_level)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'wiki_blobs', expected_count: expected_count) do |user|
described_class.new(user, search: 'term').execute
end
end
end
end
context 'milestone' do
let!(:milestone) { create :milestone, project: project }
where(:project_level, :issues_access_level, :merge_requests_access_level, :membership, :expected_count) do
permission_table_for_milestone_access
end
with_them do
it "respects visibility" do
project.update!(
'issues_access_level' => issues_access_level,
'merge_requests_access_level' => merge_requests_access_level
)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'milestones', expected_count: expected_count) do |user|
described_class.new(user, search: milestone.title).execute
end
end
end
end
......
......@@ -67,7 +67,7 @@ describe Search::GroupService, :elastic do
end
end
context 'visibility' do
context 'visibility', :sidekiq_inline do
include_context 'ProjectPolicyTable context'
set(:group) { create(:group) }
......@@ -78,7 +78,14 @@ describe Search::GroupService, :elastic do
context 'merge request' do
let!(:merge_request) { create :merge_request, target_project: project, source_project: project }
let!(:merge_request2) { create :merge_request, target_project: project2, source_project: project2, title: merge_request.title }
let!(:note) { create :note, project: project, noteable: merge_request }
let!(:note2) { create :note, project: project2, noteable: merge_request2, note: note.note }
let(:pendings) do
[
{ project_level: :public, feature_access_level: :enabled, membership: :guest, expected_count: 1 },
{ project_level: :internal, feature_access_level: :enabled, membership: :guest, expected_count: 1 }
]
end
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_reporter_feature_access
end
......@@ -90,18 +97,31 @@ describe Search::GroupService, :elastic do
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'merge_requests', expected_count: expected_count) do |user|
expect_search_results(user, 'merge_requests', expected_count: expected_count, pending: pending?) do |user|
described_class.new(user, group, search: merge_request.title).execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(user, group, search: note.note).execute
end
end
end
end
context 'code' do
let!(:project) { create(:project, project_level, :repository, namespace: group ) }
let!(:note) { create :note_on_commit, project: project }
let(:pendings) do
[
{ project_level: :public, feature_access_level: :enabled, membership: :guest, expected_count: 1 },
{ project_level: :public, feature_access_level: :private, membership: :guest, expected_count: 1 },
{ project_level: :internal, feature_access_level: :enabled, membership: :guest, expected_count: 1 },
{ project_level: :internal, feature_access_level: :private, membership: :guest, expected_count: 1 }
]
end
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
permission_table_for_guest_feature_access_and_non_private_project_only
end
with_them do
......@@ -113,13 +133,88 @@ describe Search::GroupService, :elastic do
ElasticCommitIndexerWorker.new.perform(project.id)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'commits', expected_count: expected_count) do |user|
expect_search_results(user, 'commits', expected_count: expected_count, pending: pending?) do |user|
described_class.new(user, group, search: 'initial').execute
end
expect_search_results(user, 'blobs', expected_count: expected_count) do |user|
expect_search_results(user, 'blobs', expected_count: expected_count, pending: pending?) do |user|
described_class.new(user, group, search: '.gitmodules').execute
end
expect_search_results(user, 'notes', expected_count: expected_count, pending: pending?) do |user|
described_class.new(user, group, search: note.note).execute
end
end
end
end
context 'issue' do
let!(:issue) { create :issue, project: project }
let!(:issue2) { create :issue, project: project2, title: issue.title }
let!(:note) { create :note, project: project, noteable: issue }
let!(:note2) { create :note, project: project2, noteable: issue2, note: note.note }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
[project, project2].each do |project|
update_feature_access_level(project, feature_access_level)
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'issues', expected_count: expected_count) do |user|
described_class.new(user, group, search: issue.title).execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(user, group, search: note.note).execute
end
end
end
end
context 'wiki' do
let!(:project) { create(:project, project_level, :wiki_repo) }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
project.wiki.create_page('test.md', '# term')
project.wiki.index_wiki_blobs
update_feature_access_level(project, feature_access_level)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'wiki_blobs', expected_count: expected_count) do |user|
described_class.new(user, project.namespace, search: 'term').execute
end
end
end
end
context 'milestone' do
let!(:milestone) { create :milestone, project: project }
where(:project_level, :issues_access_level, :merge_requests_access_level, :membership, :expected_count) do
permission_table_for_milestone_access
end
with_them do
it "respects visibility" do
project.update!(
'issues_access_level' => issues_access_level,
'merge_requests_access_level' => merge_requests_access_level
)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'milestones', expected_count: expected_count) do |user|
described_class.new(user, group, search: milestone.title).execute
end
end
end
end
......
......@@ -17,7 +17,7 @@ describe Search::ProjectService do
let(:service) { described_class.new(scope, user, params) }
end
context 'visibility', :elastic do
context 'visibility', :elastic, :sidekiq_inline do
include_context 'ProjectPolicyTable context'
set(:group) { create(:group) }
......@@ -28,6 +28,14 @@ describe Search::ProjectService do
context 'merge request' do
let!(:merge_request) { create :merge_request, target_project: project, source_project: project }
let!(:merge_request2) { create :merge_request, target_project: project2, source_project: project2, title: merge_request.title }
let!(:note) { create :note, project: project, noteable: merge_request }
let!(:note2) { create :note, project: project2, noteable: merge_request2, note: note.note }
let(:pendings) do
[
{ project_level: :public, feature_access_level: :enabled, membership: :guest, expected_count: 1 },
{ project_level: :internal, feature_access_level: :enabled, membership: :guest, expected_count: 1 }
]
end
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_reporter_feature_access
......@@ -40,9 +48,13 @@ describe Search::ProjectService do
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'merge_requests', expected_count: expected_count) do |user|
expect_search_results(user, 'merge_requests', expected_count: expected_count, pending: pending?) do |user|
described_class.new(project, user, search: merge_request.title).execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(project, user, search: note.note).execute
end
end
end
end
......@@ -50,9 +62,11 @@ describe Search::ProjectService do
context 'code' do
let!(:project) { create(:project, project_level, :repository, namespace: group ) }
let!(:project2) { create(:project, project_level, :repository) }
let!(:note) { create :note_on_commit, project: project }
let!(:note2) { create :note_on_commit, project: project2, note: note.note }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
permission_table_for_guest_feature_access_and_non_private_project_only
end
with_them do
......@@ -63,13 +77,88 @@ describe Search::ProjectService do
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'commits', expected_count: expected_count) do |user|
expect_search_results(user, 'commits', expected_count: expected_count, pending: pending?) do |user|
described_class.new(project, user, search: 'initial').execute
end
expect_search_results(user, 'blobs', expected_count: expected_count) do |user|
described_class.new(project, user, search: '.gitmodules').execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(project, user, search: note.note).execute
end
end
end
end
context 'issue' do
let!(:issue) { create :issue, project: project }
let!(:issue2) { create :issue, project: project2, title: issue.title }
let!(:note) { create :note, project: project, noteable: issue }
let!(:note2) { create :note, project: project2, noteable: issue2, note: note.note }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
[project, project2].each do |project|
update_feature_access_level(project, feature_access_level)
end
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'issues', expected_count: expected_count) do |user|
described_class.new(project, user, search: issue.title).execute
end
expect_search_results(user, 'notes', expected_count: expected_count) do |user|
described_class.new(project, user, search: note.note).execute
end
end
end
end
context 'wiki' do
let!(:project) { create(:project, project_level, :wiki_repo) }
where(:project_level, :feature_access_level, :membership, :expected_count) do
permission_table_for_guest_feature_access
end
with_them do
it "respects visibility" do
project.wiki.create_page('test.md', '# term')
project.wiki.index_wiki_blobs
update_feature_access_level(project, feature_access_level)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'wiki_blobs', expected_count: expected_count) do |user|
described_class.new(project, user, search: 'term').execute
end
end
end
end
context 'milestone' do
let!(:milestone) { create :milestone, project: project }
where(:project_level, :issues_access_level, :merge_requests_access_level, :membership, :expected_count) do
permission_table_for_milestone_access
end
with_them do
it "respects visibility" do
project.update!(
'issues_access_level' => issues_access_level,
'merge_requests_access_level' => merge_requests_access_level
)
Gitlab::Elastic::Helper.refresh_index
expect_search_results(user, 'milestones', expected_count: expected_count) do |user|
described_class.new(project, user, search: milestone.title).execute
end
end
end
end
......
......@@ -2,9 +2,9 @@
module SearchResultHelpers
# @param target [Symbol] search target, e.g. "merge_requests", "blobs"
def expect_search_results(users, target, expected_count: nil, expected_objects: nil)
def expect_search_results(users, target, expected_count: nil, expected_objects: nil, pending: false)
# TODO: https://gitlab.com/gitlab-org/gitlab/issues/32645
return if expected_count && expected_count > 0
pending("https://gitlab.com/gitlab-org/gitlab/issues/32645") if pending
users = Array(users)
target = target.to_s
......@@ -17,7 +17,7 @@ module SearchResultHelpers
if expected_count
actual_count = results.public_send("#{target}_count")
expect(actual_count).to eq(expected_count), "expected count to be #{expected_count} for #{user_name}, got #{actual_count}"
expect(actual_count).to eq(expected_count), "#{target} expected count to be #{expected_count} for #{user_name}, got #{actual_count}"
end
if expected_objects
......
......@@ -16,10 +16,10 @@ module ProjectHelpers
end
def update_feature_access_level(project, access_level)
project.update!(
repository_access_level: access_level,
merge_requests_access_level: access_level,
builds_access_level: access_level
)
features = ProjectFeature::FEATURES.dup
features.delete(:pages)
params = features.each_with_object({}) { |feature, h| h["#{feature}_access_level"] = access_level }
project.update!(params)
end
end
......@@ -3,7 +3,20 @@
RSpec.shared_context 'ProjectPolicyTable context' do
using RSpec::Parameterized::TableSyntax
let(:pendings) { {} }
let(:pending?) do
pendings.include?(
{
project_level: project_level,
feature_access_level: feature_access_level,
membership: membership,
expected_count: expected_count
}
)
end
# rubocop:disable Metrics/AbcSize
# project_level, :feature_access_level, :membership, :expected_count
def permission_table_for_reporter_feature_access
:public | :enabled | :reporter | 1
:public | :enabled | :guest | 1
......@@ -35,11 +48,6 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:internal | :disabled | :non_member | 0
:internal | :disabled | :anonymous | 0
:private | :enabled | :reporter | 1
:private | :enabled | :guest | 1
:private | :enabled | :non_member | 0
:private | :enabled | :anonymous | 0
:private | :private | :reporter | 1
:private | :private | :guest | 0
:private | :private | :non_member | 0
......@@ -51,6 +59,7 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:private | :disabled | :anonymous | 0
end
# project_level, :feature_access_level, :membership, :expected_count
def permission_table_for_guest_feature_access
:public | :enabled | :reporter | 1
:public | :enabled | :guest | 1
......@@ -82,11 +91,6 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:internal | :disabled | :non_member | 0
:internal | :disabled | :anonymous | 0
:private | :enabled | :reporter | 1
:private | :enabled | :guest | 1
:private | :enabled | :non_member | 0
:private | :enabled | :anonymous | 0
:private | :private | :reporter | 1
:private | :private | :guest | 1
:private | :private | :non_member | 0
......@@ -98,6 +102,172 @@ RSpec.shared_context 'ProjectPolicyTable context' do
:private | :disabled | :anonymous | 0
end
# This table is based on permission_table_for_guest_feature_access,
# but with a slight twist.
# Some features can be hidden away to GUEST, when project is private.
# (see ProjectFeature::PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT)
# This is the table for such features.
#
# e.g. `repository` feature has minimum requirement of GUEST,
# but a GUEST are prohibited from reading code if project is private.
#
# project_level, :feature_access_level, :membership, :expected_count
def permission_table_for_guest_feature_access_and_non_private_project_only
:public | :enabled | :reporter | 1
:public | :enabled | :guest | 1
:public | :enabled | :non_member | 1
:public | :enabled | :anonymous | 1
:public | :private | :reporter | 1
:public | :private | :guest | 1
:public | :private | :non_member | 0
:public | :private | :anonymous | 0
:public | :disabled | :reporter | 0
:public | :disabled | :guest | 0
:public | :disabled | :non_member | 0
:public | :disabled | :anonymous | 0
:internal | :enabled | :reporter | 1
:internal | :enabled | :guest | 1
:internal | :enabled | :non_member | 1
:internal | :enabled | :anonymous | 0
:internal | :private | :reporter | 1
:internal | :private | :guest | 1
:internal | :private | :non_member | 0
:internal | :private | :anonymous | 0
:internal | :disabled | :reporter | 0
:internal | :disabled | :guest | 0
:internal | :disabled | :non_member | 0
:internal | :disabled | :anonymous | 0
:private | :private | :reporter | 1
:private | :private | :guest | 0
:private | :private | :non_member | 0
:private | :private | :anonymous | 0
:private | :disabled | :reporter | 0
:private | :disabled | :guest | 0
:private | :disabled | :non_member | 0
:private | :disabled | :anonymous | 0
end
# :project_level, :issues_access_level, :merge_requests_access_level, :membership, :expected_count
def permission_table_for_milestone_access
:public | :enabled | :enabled | :reporter | 1
:public | :enabled | :enabled | :guest | 1
:public | :enabled | :enabled | :non_member | 1
:public | :enabled | :enabled | :anonymous | 1
:public | :enabled | :private | :reporter | 1
:public | :enabled | :private | :guest | 1
:public | :enabled | :private | :non_member | 1
:public | :enabled | :private | :anonymous | 1
:public | :enabled | :disabled | :reporter | 1
:public | :enabled | :disabled | :guest | 1
:public | :enabled | :disabled | :non_member | 1
:public | :enabled | :disabled | :anonymous | 1
:public | :private | :enabled | :reporter | 1
:public | :private | :enabled | :guest | 1
:public | :private | :enabled | :non_member | 1
:public | :private | :enabled | :anonymous | 1
:public | :private | :private | :reporter | 1
:public | :private | :private | :guest | 1
:public | :private | :private | :non_member | 0
:public | :private | :private | :anonymous | 0
:public | :private | :disabled | :reporter | 1
:public | :private | :disabled | :guest | 1
:public | :private | :disabled | :non_member | 0
:public | :private | :disabled | :anonymous | 0
:public | :disabled | :enabled | :reporter | 1
:public | :disabled | :enabled | :guest | 1
:public | :disabled | :enabled | :non_member | 1
:public | :disabled | :enabled | :anonymous | 1
:public | :disabled | :private | :reporter | 1
:public | :disabled | :private | :guest | 0
:public | :disabled | :private | :non_member | 0
:public | :disabled | :private | :anonymous | 0
:public | :disabled | :disabled | :reporter | 0
:public | :disabled | :disabled | :guest | 0
:public | :disabled | :disabled | :non_member | 0
:public | :disabled | :disabled | :anonymous | 0
:internal | :enabled | :enabled | :reporter | 1
:internal | :enabled | :enabled | :guest | 1
:internal | :enabled | :enabled | :non_member | 1
:internal | :enabled | :enabled | :anonymous | 0
:internal | :enabled | :private | :reporter | 1
:internal | :enabled | :private | :guest | 1
:internal | :enabled | :private | :non_member | 1
:internal | :enabled | :private | :anonymous | 0
:internal | :enabled | :disabled | :reporter | 1
:internal | :enabled | :disabled | :guest | 1
:internal | :enabled | :disabled | :non_member | 1
:internal | :enabled | :disabled | :anonymous | 0
:internal | :private | :enabled | :reporter | 1
:internal | :private | :enabled | :guest | 1
:internal | :private | :enabled | :non_member | 1
:internal | :private | :enabled | :anonymous | 0
:internal | :private | :private | :reporter | 1
:internal | :private | :private | :guest | 1
:internal | :private | :private | :non_member | 0
:internal | :private | :private | :anonymous | 0
:internal | :private | :disabled | :reporter | 1
:internal | :private | :disabled | :guest | 1
:internal | :private | :disabled | :non_member | 0
:internal | :private | :disabled | :anonymous | 0
:internal | :disabled | :enabled | :reporter | 1
:internal | :disabled | :enabled | :guest | 1
:internal | :disabled | :enabled | :non_member | 1
:internal | :disabled | :enabled | :anonymous | 0
:internal | :disabled | :private | :reporter | 1
:internal | :disabled | :private | :guest | 0
:internal | :disabled | :private | :non_member | 0
:internal | :disabled | :private | :anonymous | 0
:internal | :disabled | :disabled | :reporter | 0
:internal | :disabled | :disabled | :guest | 0
:internal | :disabled | :disabled | :non_member | 0
:internal | :disabled | :disabled | :anonymous | 0
:private | :private | :private | :reporter | 1
:private | :private | :private | :guest | 1
:private | :private | :private | :non_member | 0
:private | :private | :private | :anonymous | 0
:private | :private | :disabled | :reporter | 1
:private | :private | :disabled | :guest | 1
:private | :private | :disabled | :non_member | 0
:private | :private | :disabled | :anonymous | 0
:private | :disabled | :private | :reporter | 1
:private | :disabled | :private | :guest | 0
:private | :disabled | :private | :non_member | 0
:private | :disabled | :private | :anonymous | 0
:private | :disabled | :disabled | :reporter | 0
:private | :disabled | :disabled | :guest | 0
:private | :disabled | :disabled | :non_member | 0
:private | :disabled | :disabled | :anonymous | 0
end
# :project_level, :membership, :expected_count
def permission_table_for_project_access
:public | :reporter | 1
:public | :guest | 1
......
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