Commit d7f10c29 authored by Mayra Cabrera's avatar Mayra Cabrera Committed by Stan Hu

Do not blindly expose public project statistics

Add the missing check on GraphQL API for project statistics
parent ad722a4e
...@@ -4,6 +4,8 @@ module Types ...@@ -4,6 +4,8 @@ module Types
class ProjectStatisticsType < BaseObject class ProjectStatisticsType < BaseObject
graphql_name 'ProjectStatistics' graphql_name 'ProjectStatistics'
authorize :read_statistics
field :commit_count, GraphQL::INT_TYPE, null: false field :commit_count, GraphQL::INT_TYPE, null: false
field :storage_size, GraphQL::INT_TYPE, null: false field :storage_size, GraphQL::INT_TYPE, null: false
......
...@@ -70,7 +70,7 @@ module Types ...@@ -70,7 +70,7 @@ module Types
field :group, Types::GroupType, null: true field :group, Types::GroupType, null: true
field :statistics, Types::ProjectStatisticsType, field :statistics, Types::ProjectStatisticsType,
null: false, null: true,
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find } resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find }
field :repository, Types::RepositoryType, null: false field :repository, Types::RepositoryType, null: false
......
# frozen_string_literal: true
class ProjectStatisticsPolicy < BasePolicy
delegate { @subject.project }
end
# 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 ...@@ -34,10 +34,10 @@ describe 'rendering namespace statistics' do
context 'when the project is public' do context 'when the project is public' do
let(:project) { create(:project, :public) } 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) 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 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