# frozen_string_literal: true RSpec.shared_examples 'snippet visibility' do using RSpec::Parameterized::TableSyntax let_it_be(:author) { create(:user) } let_it_be(:member) { create(:user) } let_it_be(:external) { create(:user, :external) } let_it_be(:non_member) { create(:user) } let_it_be(:project, reload: true) do create(:project).tap do |project| project.add_developer(author) project.add_developer(member) end end context "For project snippets" do let!(:users) do { unauthenticated: nil, external: external, non_member: non_member, member: member, author: author } end where(:project_type, :feature_visibility, :user_type, :snippet_type, :outcome) do [ # Public projects [:public, ProjectFeature::ENABLED, :unauthenticated, Snippet::PUBLIC, true], [:public, ProjectFeature::ENABLED, :unauthenticated, Snippet::INTERNAL, false], [:public, ProjectFeature::ENABLED, :unauthenticated, Snippet::PRIVATE, false], [:public, ProjectFeature::ENABLED, :external, Snippet::PUBLIC, true], [:public, ProjectFeature::ENABLED, :external, Snippet::INTERNAL, false], [:public, ProjectFeature::ENABLED, :external, Snippet::PRIVATE, false], [:public, ProjectFeature::ENABLED, :non_member, Snippet::PUBLIC, true], [:public, ProjectFeature::ENABLED, :non_member, Snippet::INTERNAL, true], [:public, ProjectFeature::ENABLED, :non_member, Snippet::PRIVATE, false], [:public, ProjectFeature::ENABLED, :member, Snippet::PUBLIC, true], [:public, ProjectFeature::ENABLED, :member, Snippet::INTERNAL, true], [:public, ProjectFeature::ENABLED, :member, Snippet::PRIVATE, true], [:public, ProjectFeature::ENABLED, :author, Snippet::PUBLIC, true], [:public, ProjectFeature::ENABLED, :author, Snippet::INTERNAL, true], [:public, ProjectFeature::ENABLED, :author, Snippet::PRIVATE, true], [:public, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PUBLIC, false], [:public, ProjectFeature::PRIVATE, :unauthenticated, Snippet::INTERNAL, false], [:public, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PRIVATE, false], [:public, ProjectFeature::PRIVATE, :external, Snippet::PUBLIC, false], [:public, ProjectFeature::PRIVATE, :external, Snippet::INTERNAL, false], [:public, ProjectFeature::PRIVATE, :external, Snippet::PRIVATE, false], [:public, ProjectFeature::PRIVATE, :non_member, Snippet::PUBLIC, false], [:public, ProjectFeature::PRIVATE, :non_member, Snippet::INTERNAL, false], [:public, ProjectFeature::PRIVATE, :non_member, Snippet::PRIVATE, false], [:public, ProjectFeature::PRIVATE, :member, Snippet::PUBLIC, true], [:public, ProjectFeature::PRIVATE, :member, Snippet::INTERNAL, true], [:public, ProjectFeature::PRIVATE, :member, Snippet::PRIVATE, true], [:public, ProjectFeature::PRIVATE, :author, Snippet::PUBLIC, true], [:public, ProjectFeature::PRIVATE, :author, Snippet::INTERNAL, true], [:public, ProjectFeature::PRIVATE, :author, Snippet::PRIVATE, true], [:public, ProjectFeature::DISABLED, :unauthenticated, Snippet::PUBLIC, false], [:public, ProjectFeature::DISABLED, :unauthenticated, Snippet::INTERNAL, false], [:public, ProjectFeature::DISABLED, :unauthenticated, Snippet::PRIVATE, false], [:public, ProjectFeature::DISABLED, :external, Snippet::PUBLIC, false], [:public, ProjectFeature::DISABLED, :external, Snippet::INTERNAL, false], [:public, ProjectFeature::DISABLED, :external, Snippet::PRIVATE, false], [:public, ProjectFeature::DISABLED, :non_member, Snippet::PUBLIC, false], [:public, ProjectFeature::DISABLED, :non_member, Snippet::INTERNAL, false], [:public, ProjectFeature::DISABLED, :non_member, Snippet::PRIVATE, false], [:public, ProjectFeature::DISABLED, :member, Snippet::PUBLIC, false], [:public, ProjectFeature::DISABLED, :member, Snippet::INTERNAL, false], [:public, ProjectFeature::DISABLED, :member, Snippet::PRIVATE, false], [:public, ProjectFeature::DISABLED, :author, Snippet::PUBLIC, false], [:public, ProjectFeature::DISABLED, :author, Snippet::INTERNAL, false], [:public, ProjectFeature::DISABLED, :author, Snippet::PRIVATE, false], # Internal projects [:internal, ProjectFeature::ENABLED, :unauthenticated, Snippet::PUBLIC, false], [:internal, ProjectFeature::ENABLED, :unauthenticated, Snippet::INTERNAL, false], [:internal, ProjectFeature::ENABLED, :unauthenticated, Snippet::PRIVATE, false], [:internal, ProjectFeature::ENABLED, :external, Snippet::PUBLIC, false], [:internal, ProjectFeature::ENABLED, :external, Snippet::INTERNAL, false], [:internal, ProjectFeature::ENABLED, :external, Snippet::PRIVATE, false], [:internal, ProjectFeature::ENABLED, :non_member, Snippet::PUBLIC, true], [:internal, ProjectFeature::ENABLED, :non_member, Snippet::INTERNAL, true], [:internal, ProjectFeature::ENABLED, :non_member, Snippet::PRIVATE, false], [:internal, ProjectFeature::ENABLED, :member, Snippet::PUBLIC, true], [:internal, ProjectFeature::ENABLED, :member, Snippet::INTERNAL, true], [:internal, ProjectFeature::ENABLED, :member, Snippet::PRIVATE, true], [:internal, ProjectFeature::ENABLED, :author, Snippet::PUBLIC, true], [:internal, ProjectFeature::ENABLED, :author, Snippet::INTERNAL, true], [:internal, ProjectFeature::ENABLED, :author, Snippet::PRIVATE, true], [:internal, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PUBLIC, false], [:internal, ProjectFeature::PRIVATE, :unauthenticated, Snippet::INTERNAL, false], [:internal, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PRIVATE, false], [:internal, ProjectFeature::PRIVATE, :external, Snippet::PUBLIC, false], [:internal, ProjectFeature::PRIVATE, :external, Snippet::INTERNAL, false], [:internal, ProjectFeature::PRIVATE, :external, Snippet::PRIVATE, false], [:internal, ProjectFeature::PRIVATE, :non_member, Snippet::PUBLIC, false], [:internal, ProjectFeature::PRIVATE, :non_member, Snippet::INTERNAL, false], [:internal, ProjectFeature::PRIVATE, :non_member, Snippet::PRIVATE, false], [:internal, ProjectFeature::PRIVATE, :member, Snippet::PUBLIC, true], [:internal, ProjectFeature::PRIVATE, :member, Snippet::INTERNAL, true], [:internal, ProjectFeature::PRIVATE, :member, Snippet::PRIVATE, true], [:internal, ProjectFeature::PRIVATE, :author, Snippet::PUBLIC, true], [:internal, ProjectFeature::PRIVATE, :author, Snippet::INTERNAL, true], [:internal, ProjectFeature::PRIVATE, :author, Snippet::PRIVATE, true], [:internal, ProjectFeature::DISABLED, :unauthenticated, Snippet::PUBLIC, false], [:internal, ProjectFeature::DISABLED, :unauthenticated, Snippet::INTERNAL, false], [:internal, ProjectFeature::DISABLED, :unauthenticated, Snippet::PRIVATE, false], [:internal, ProjectFeature::DISABLED, :external, Snippet::PUBLIC, false], [:internal, ProjectFeature::DISABLED, :external, Snippet::INTERNAL, false], [:internal, ProjectFeature::DISABLED, :external, Snippet::PRIVATE, false], [:internal, ProjectFeature::DISABLED, :non_member, Snippet::PUBLIC, false], [:internal, ProjectFeature::DISABLED, :non_member, Snippet::INTERNAL, false], [:internal, ProjectFeature::DISABLED, :non_member, Snippet::PRIVATE, false], [:internal, ProjectFeature::DISABLED, :member, Snippet::PUBLIC, false], [:internal, ProjectFeature::DISABLED, :member, Snippet::INTERNAL, false], [:internal, ProjectFeature::DISABLED, :member, Snippet::PRIVATE, false], [:internal, ProjectFeature::DISABLED, :author, Snippet::PUBLIC, false], [:internal, ProjectFeature::DISABLED, :author, Snippet::INTERNAL, false], [:internal, ProjectFeature::DISABLED, :author, Snippet::PRIVATE, false], # Private projects [:private, ProjectFeature::ENABLED, :unauthenticated, Snippet::PUBLIC, false], [:private, ProjectFeature::ENABLED, :unauthenticated, Snippet::INTERNAL, false], [:private, ProjectFeature::ENABLED, :unauthenticated, Snippet::PRIVATE, false], [:private, ProjectFeature::ENABLED, :external, Snippet::PUBLIC, true], [:private, ProjectFeature::ENABLED, :external, Snippet::INTERNAL, true], [:private, ProjectFeature::ENABLED, :external, Snippet::PRIVATE, true], [:private, ProjectFeature::ENABLED, :non_member, Snippet::PUBLIC, false], [:private, ProjectFeature::ENABLED, :non_member, Snippet::INTERNAL, false], [:private, ProjectFeature::ENABLED, :non_member, Snippet::PRIVATE, false], [:private, ProjectFeature::ENABLED, :member, Snippet::PUBLIC, true], [:private, ProjectFeature::ENABLED, :member, Snippet::INTERNAL, true], [:private, ProjectFeature::ENABLED, :member, Snippet::PRIVATE, true], [:private, ProjectFeature::ENABLED, :author, Snippet::PUBLIC, true], [:private, ProjectFeature::ENABLED, :author, Snippet::INTERNAL, true], [:private, ProjectFeature::ENABLED, :author, Snippet::PRIVATE, true], [:private, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PUBLIC, false], [:private, ProjectFeature::PRIVATE, :unauthenticated, Snippet::INTERNAL, false], [:private, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PRIVATE, false], [:private, ProjectFeature::PRIVATE, :external, Snippet::PUBLIC, true], [:private, ProjectFeature::PRIVATE, :external, Snippet::INTERNAL, true], [:private, ProjectFeature::PRIVATE, :external, Snippet::PRIVATE, true], [:private, ProjectFeature::PRIVATE, :non_member, Snippet::PUBLIC, false], [:private, ProjectFeature::PRIVATE, :non_member, Snippet::INTERNAL, false], [:private, ProjectFeature::PRIVATE, :non_member, Snippet::PRIVATE, false], [:private, ProjectFeature::PRIVATE, :member, Snippet::PUBLIC, true], [:private, ProjectFeature::PRIVATE, :member, Snippet::INTERNAL, true], [:private, ProjectFeature::PRIVATE, :member, Snippet::PRIVATE, true], [:private, ProjectFeature::PRIVATE, :author, Snippet::PUBLIC, true], [:private, ProjectFeature::PRIVATE, :author, Snippet::INTERNAL, true], [:private, ProjectFeature::PRIVATE, :author, Snippet::PRIVATE, true], [:private, ProjectFeature::DISABLED, :unauthenticated, Snippet::PUBLIC, false], [:private, ProjectFeature::DISABLED, :unauthenticated, Snippet::INTERNAL, false], [:private, ProjectFeature::DISABLED, :unauthenticated, Snippet::PRIVATE, false], [:private, ProjectFeature::DISABLED, :external, Snippet::PUBLIC, false], [:private, ProjectFeature::DISABLED, :external, Snippet::INTERNAL, false], [:private, ProjectFeature::DISABLED, :external, Snippet::PRIVATE, false], [:private, ProjectFeature::DISABLED, :non_member, Snippet::PUBLIC, false], [:private, ProjectFeature::DISABLED, :non_member, Snippet::INTERNAL, false], [:private, ProjectFeature::DISABLED, :non_member, Snippet::PRIVATE, false], [:private, ProjectFeature::DISABLED, :member, Snippet::PUBLIC, false], [:private, ProjectFeature::DISABLED, :member, Snippet::INTERNAL, false], [:private, ProjectFeature::DISABLED, :member, Snippet::PRIVATE, false], [:private, ProjectFeature::DISABLED, :author, Snippet::PUBLIC, false], [:private, ProjectFeature::DISABLED, :author, Snippet::INTERNAL, false], [:private, ProjectFeature::DISABLED, :author, Snippet::PRIVATE, false] ] end with_them do let!(:project_visibility) { project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(project_type.to_s)) } let!(:project_feature) { project.project_feature.update_column(:snippets_access_level, feature_visibility) } let!(:user) { users[user_type] } let!(:snippet) { create(:project_snippet, visibility_level: snippet_type, project: project, author: author) } let!(:external_member) do member = project.project_member(external) if project.private? project.add_developer(external) unless member else member.delete if member end end context "For #{params[:project_type]} project and #{params[:user_type]} users" do it 'agrees with the read_snippet policy' do expect(can?(user, :read_snippet, snippet)).to eq(outcome) end it 'returns proper outcome' do results = described_class.new(user, project: project).execute expect(results.include?(snippet)).to eq(outcome) end end context "Without a given project and #{params[:user_type]} users" do it 'returns proper outcome' do results = described_class.new(user).execute expect(results.include?(snippet)).to eq(outcome) end it 'returns no snippets when the user cannot read cross project' do allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } snippets = described_class.new(user).execute expect(snippets).to be_empty end end end end context 'For personal snippets' do let!(:users) do { unauthenticated: nil, external: external, non_member: non_member, author: author } end where(:snippet_visibility, :user_type, :outcome) do [ [Snippet::PUBLIC, :unauthenticated, true], [Snippet::PUBLIC, :external, true], [Snippet::PUBLIC, :non_member, true], [Snippet::PUBLIC, :author, true], [Snippet::INTERNAL, :unauthenticated, false], [Snippet::INTERNAL, :external, false], [Snippet::INTERNAL, :non_member, true], [Snippet::INTERNAL, :author, true], [Snippet::PRIVATE, :unauthenticated, false], [Snippet::PRIVATE, :external, false], [Snippet::PRIVATE, :non_member, false], [Snippet::PRIVATE, :author, true] ] end with_them do let!(:user) { users[user_type] } let!(:snippet) { create(:personal_snippet, visibility_level: snippet_visibility, author: author) } context "For personal and #{params[:snippet_visibility]} snippets with #{params[:user_type]} user" do it 'agrees with read_snippet policy' do expect(can?(user, :read_snippet, snippet)).to eq(outcome) end it 'returns proper outcome' do results = described_class.new(user).execute expect(results.include?(snippet)).to eq(outcome) end it 'returns personal snippets when the user cannot read cross project' do allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } results = described_class.new(user).execute expect(results.include?(snippet)).to eq(outcome) end end end end end