Do not blindly expose public project statistics
Add the missing check on GraphQL API for project statistics
This commit is contained in:
parent
ad722a4e1f
commit
d7f10c2949
5 changed files with 93 additions and 3 deletions
|
@ -4,6 +4,8 @@ module Types
|
|||
class ProjectStatisticsType < BaseObject
|
||||
graphql_name 'ProjectStatistics'
|
||||
|
||||
authorize :read_statistics
|
||||
|
||||
field :commit_count, GraphQL::INT_TYPE, null: false
|
||||
|
||||
field :storage_size, GraphQL::INT_TYPE, null: false
|
||||
|
|
|
@ -70,7 +70,7 @@ module Types
|
|||
field :group, Types::GroupType, null: true
|
||||
|
||||
field :statistics, Types::ProjectStatisticsType,
|
||||
null: false,
|
||||
null: true,
|
||||
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find }
|
||||
|
||||
field :repository, Types::RepositoryType, null: false
|
||||
|
|
5
app/policies/project_statistics_policy.rb
Normal file
5
app/policies/project_statistics_policy.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectStatisticsPolicy < BasePolicy
|
||||
delegate { @subject.project }
|
||||
end
|
83
spec/policies/project_statistics_policy_spec.rb
Normal file
83
spec/policies/project_statistics_policy_spec.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ProjectStatisticsPolicy do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
describe '#rules' do
|
||||
let(:external) { create(:user, :external) }
|
||||
let(:guest) { create(:user) }
|
||||
let(:reporter) { create(:user) }
|
||||
let(:developer) { create(:user) }
|
||||
let(:maintainer) { create(:user) }
|
||||
|
||||
let(:users) do
|
||||
{
|
||||
unauthenticated: nil,
|
||||
non_member: create(:user),
|
||||
guest: guest,
|
||||
reporter: reporter,
|
||||
developer: developer,
|
||||
maintainer: maintainer
|
||||
}
|
||||
end
|
||||
|
||||
where(:project_type, :user_type, :outcome) do
|
||||
[
|
||||
# Public projects
|
||||
[:public, :unauthenticated, false],
|
||||
[:public, :non_member, false],
|
||||
[:public, :guest, false],
|
||||
[:public, :reporter, true],
|
||||
[:public, :developer, true],
|
||||
[:public, :maintainer, true],
|
||||
|
||||
# Private project
|
||||
[:private, :unauthenticated, false],
|
||||
[:private, :non_member, false],
|
||||
[:private, :guest, false],
|
||||
[:private, :reporter, true],
|
||||
[:private, :developer, true],
|
||||
[:private, :maintainer, true],
|
||||
|
||||
# Internal projects
|
||||
[:internal, :unauthenticated, false],
|
||||
[:internal, :non_member, false],
|
||||
[:internal, :guest, false],
|
||||
[:internal, :reporter, true],
|
||||
[:internal, :developer, true],
|
||||
[:internal, :maintainer, true]
|
||||
]
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:user) { users[user_type] }
|
||||
let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel.level_value(project_type.to_s)) }
|
||||
let(:project_statistics) { create(:project_statistics, project: project) }
|
||||
|
||||
subject { Ability.allowed?(user, :read_statistics, project_statistics) }
|
||||
|
||||
before do
|
||||
project.add_guest(guest)
|
||||
project.add_reporter(reporter)
|
||||
project.add_developer(developer)
|
||||
project.add_maintainer(maintainer)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(outcome) }
|
||||
|
||||
context 'when the user is external' do
|
||||
let(:user) { external }
|
||||
|
||||
before do
|
||||
unless [:unauthenticated, :non_member].include?(user_type)
|
||||
project.add_user(external, user_type)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to eq(outcome) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,10 +34,10 @@ describe 'rendering namespace statistics' do
|
|||
context 'when the project is public' do
|
||||
let(:project) { create(:project, :public) }
|
||||
|
||||
it 'includes the statistics regardless of the user' do
|
||||
it 'hides statistics for unauthenticated requests' do
|
||||
post_graphql(query, current_user: nil)
|
||||
|
||||
expect(graphql_data['project']['statistics']).to be_present
|
||||
expect(graphql_data['project']['statistics']).to be_blank
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue