Don't treat anonymous users as owners when group has pending invites

The `members` table can have entries where `user_id: nil`, because people can
invite group members by email. We never want to include those as members,
because it might cause confusion with the anonymous (logged out) user.
This commit is contained in:
Sean McGivern 2017-07-24 11:35:54 +01:00
parent f81ed493e1
commit ccac2abeba
6 changed files with 37 additions and 6 deletions

View file

@ -167,10 +167,14 @@ class Group < Namespace
end
def has_owner?(user)
return false unless user
members_with_parents.owners.where(user_id: user).any?
end
def has_master?(user)
return false unless user
members_with_parents.masters.where(user_id: user).any?
end
@ -212,7 +216,7 @@ class Group < Namespace
end
def members_with_parents
GroupMember.non_request.where(source_id: ancestors.pluck(:id).push(id))
GroupMember.active.where(source_id: ancestors.pluck(:id).push(id)).where.not(user_id: nil)
end
def users_with_parents

View file

@ -10,7 +10,8 @@ class ProjectPolicy < BasePolicy
desc "User is a project owner"
condition :owner do
@user && project.owner == @user || (project.group && project.group.has_owner?(@user))
(project.owner.present? && project.owner == @user) ||
project.group&.has_owner?(@user)
end
desc "Project has public builds enabled"

View file

@ -0,0 +1,4 @@
---
title: Fix anonymous access to public projects in groups with pending invites
merge_request:
author:

View file

@ -98,7 +98,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
expect(project).to receive(:owner).twice.and_return(user1)
expect(project).to receive(:owner).at_least(:once).and_return(user1)
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@ -109,7 +109,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
expect(project.team).to receive(:members).twice.and_return([user1])
expect(project.team).to receive(:members).at_least(:once).and_return([user1])
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@ -140,7 +140,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
expect(project).to receive(:owner).twice.and_return(user1)
expect(project).to receive(:owner).at_least(:once).and_return(user1)
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@ -151,7 +151,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
expect(project.team).to receive(:members).twice.and_return([user1])
expect(project.team).to receive(:members).at_least(:once).and_return([user1])
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])

View file

@ -236,6 +236,7 @@ describe Group, models: true do
describe '#has_owner?' do
before do
@members = setup_group_members(group)
create(:group_member, :invited, :owner, group: group)
end
it { expect(group.has_owner?(@members[:owner])).to be_truthy }
@ -244,11 +245,13 @@ describe Group, models: true do
it { expect(group.has_owner?(@members[:reporter])).to be_falsey }
it { expect(group.has_owner?(@members[:guest])).to be_falsey }
it { expect(group.has_owner?(@members[:requester])).to be_falsey }
it { expect(group.has_owner?(nil)).to be_falsey }
end
describe '#has_master?' do
before do
@members = setup_group_members(group)
create(:group_member, :invited, :master, group: group)
end
it { expect(group.has_master?(@members[:owner])).to be_falsey }
@ -257,6 +260,7 @@ describe Group, models: true do
it { expect(group.has_master?(@members[:reporter])).to be_falsey }
it { expect(group.has_master?(@members[:guest])).to be_falsey }
it { expect(group.has_master?(@members[:requester])).to be_falsey }
it { expect(group.has_master?(nil)).to be_falsey }
end
describe '#lfs_enabled?' do

View file

@ -127,6 +127,24 @@ describe ProjectPolicy, models: true do
end
end
context 'when a project has pending invites, and the current user is anonymous' do
let(:group) { create(:group, :public) }
let(:project) { create(:empty_project, :public, namespace: group) }
let(:user_permissions) { [:create_project, :create_issue, :create_note, :upload_file] }
let(:anonymous_permissions) { guest_permissions - user_permissions }
subject { described_class.new(nil, project) }
before do
create(:group_member, :invited, group: group)
end
it 'does not grant owner access' do
expect_allowed(*anonymous_permissions)
expect_disallowed(*user_permissions)
end
end
context 'abilities for non-public projects' do
let(:project) { create(:empty_project, namespace: owner.namespace) }