Commit 1f4de299 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch '351603-auditor-project-level-events' into 'master'

Ensures audit events are visible to auditor at Project level

See merge request gitlab-org/gitlab!81497
parents 89339612 0afc1625
......@@ -43,6 +43,8 @@ class Projects::AuditEventsController < Projects::ApplicationController
end
def filter_by_author(params)
can?(current_user, :admin_project, project) ? params : params.merge(author_id: current_user.id)
return params if can?(current_user, :admin_project, project) || current_user.auditor?
params.merge(author_id: current_user.id)
end
end
......@@ -276,6 +276,7 @@ module EE
enable :read_environment
enable :read_deployment
enable :read_pages
enable :read_project_audit_events
end
rule { ~security_and_compliance_disabled & auditor }.policy do
......
......@@ -7,6 +7,7 @@ RSpec.describe Projects::AuditEventsController do
let_it_be(:user) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:auditor) { create(:user, auditor: true) }
let_it_be(:project) { create(:project, :private) }
let_it_be(:events) { create_list(:project_audit_event, 5, entity_id: project.id) }
......@@ -19,149 +20,179 @@ RSpec.describe Projects::AuditEventsController do
get :index, params: { project_id: project.to_param, namespace_id: project.namespace.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
end
context 'authorized' do
shared_context 'when audit_events feature is available' do
let(:level) { Gitlab::Audit::Levels::Project.new(project: project) }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', entity_type: '', entity_id: '', created_after: Date.current.beginning_of_month, created_before: Date.current.end_of_day).permit! }
before do
project.add_maintainer(maintainer)
sign_in(maintainer)
end
stub_licensed_features(audit_events: true)
context 'when audit_events feature is available' do
let(:level) { Gitlab::Audit::Levels::Project.new(project: project) }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', entity_type: '', entity_id: '', created_after: Date.current.beginning_of_month, created_before: Date.current.end_of_day).permit! }
allow(Gitlab::Audit::Levels::Project).to receive(:new).and_return(level)
allow(AuditLogFinder).to receive(:new).and_call_original
end
before do
stub_licensed_features(audit_events: true)
shared_examples 'AuditLogFinder params' do
it 'has the correct params' do
request
allow(Gitlab::Audit::Levels::Project).to receive(:new).and_return(level)
allow(AuditLogFinder).to receive(:new).and_call_original
expect(AuditLogFinder).to have_received(:new).with(
level: level, params: audit_logs_params
)
end
end
shared_examples 'AuditLogFinder params' do
it 'has the correct params' do
request
expect(AuditLogFinder).to have_received(:new).with(
level: level, params: audit_logs_params
)
end
end
it 'renders index with 200 status code' do
request
it 'renders index with 200 status code' do
request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
context 'invokes AuditLogFinder with correct arguments' do
it_behaves_like 'AuditLogFinder params'
end
context 'invokes AuditLogFinder with correct arguments' do
context 'author' do
context 'when no author entity type is specified' do
it_behaves_like 'AuditLogFinder params'
end
context 'author' do
context 'when no author entity type is specified' do
it_behaves_like 'AuditLogFinder params'
end
context 'when the author entity type is specified' do
let(:entity_type) { 'Author' }
let(:entity_id) { 1 }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', author_id: '1', created_after: Date.current.beginning_of_month, created_before: Date.current.end_of_day).permit! }
context 'when the author entity type is specified' do
let(:entity_type) { 'Author' }
let(:entity_id) { 1 }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', author_id: '1', created_after: Date.current.beginning_of_month, created_before: Date.current.end_of_day).permit! }
it_behaves_like 'AuditLogFinder params'
end
it_behaves_like 'AuditLogFinder params'
end
end
context 'ordering' do
shared_examples 'orders by id descending' do
it 'orders by id descending' do
request
context 'ordering' do
shared_examples 'orders by id descending' do
it 'orders by id descending' do
request
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id).reverse
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id).reverse
expect(actual_event_ids).to eq(expected_event_ids)
end
expect(actual_event_ids).to eq(expected_event_ids)
end
end
context 'when no sort order is specified' do
it_behaves_like 'orders by id descending'
end
context 'when no sort order is specified' do
it_behaves_like 'orders by id descending'
end
context 'when sorting by latest events first' do
let(:sort) { 'created_desc' }
context 'when sorting by latest events first' do
let(:sort) { 'created_desc' }
it_behaves_like 'orders by id descending'
end
it_behaves_like 'orders by id descending'
end
context 'when sorting by oldest events first' do
let(:sort) { 'created_asc' }
context 'when sorting by oldest events first' do
let(:sort) { 'created_asc' }
it 'orders by id ascending' do
request
it 'orders by id ascending' do
request
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id)
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id)
expect(actual_event_ids).to eq(expected_event_ids)
end
expect(actual_event_ids).to eq(expected_event_ids)
end
end
context 'when sorting by an unsupported sort order' do
let(:sort) { 'FOO' }
context 'when sorting by an unsupported sort order' do
let(:sort) { 'FOO' }
it_behaves_like 'orders by id descending'
end
it_behaves_like 'orders by id descending'
end
end
context 'when invalid date' do
where(:created_before, :created_after) do
'invalid-date' | nil
nil | true
'2021-13-10' | nil
nil | '2021-02-31'
'2021-03-31' | '2021-02-31'
end
context 'when invalid date' do
where(:created_before, :created_after) do
'invalid-date' | nil
nil | true
'2021-13-10' | nil
nil | '2021-02-31'
'2021-03-31' | '2021-02-31'
end
with_them do
it 'returns an error' do
get :index, params: { project_id: project.to_param, namespace_id: project.namespace.to_param, 'created_before': created_before, 'created_after': created_after }
with_them do
it 'returns an error' do
get :index, params: { project_id: project.to_param, namespace_id: project.namespace.to_param, 'created_before': created_before, 'created_after': created_after }
expect(response).to have_gitlab_http_status(:bad_request)
expect(flash[:alert]).to eq 'Invalid date format. Please use UTC format as YYYY-MM-DD'
end
expect(response).to have_gitlab_http_status(:bad_request)
expect(flash[:alert]).to eq 'Invalid date format. Please use UTC format as YYYY-MM-DD'
end
end
end
end
context 'pagination' do
it 'sets instance variables' do
request
shared_examples 'pagination' do
it 'sets instance variables' do
request
expect(assigns(:is_last_page)).to be(true)
end
expect(assigns(:is_last_page)).to be(true)
end
it 'paginates audit events, without casting a count query' do
serializer = instance_spy(AuditEventSerializer)
allow(AuditEventSerializer).to receive(:new).and_return(serializer)
it 'paginates audit events, without casting a count query' do
serializer = instance_spy(AuditEventSerializer)
allow(AuditEventSerializer).to receive(:new).and_return(serializer)
request
request
expect(serializer).to have_received(:represent).with(kind_of(Kaminari::PaginatableWithoutCount))
end
expect(serializer).to have_received(:represent).with(kind_of(Kaminari::PaginatableWithoutCount))
end
end
context 'when audit_events feature is not available' do
before do
stub_licensed_features(audit_events: false)
end
shared_context 'when audit_events feature is not available' do
before do
stub_licensed_features(audit_events: false)
end
it 'renders 404' do
request
it 'renders 404' do
request
expect(response).to have_gitlab_http_status(:not_found)
end
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when authorized as auditor' do
before do
sign_in(auditor)
end
it_behaves_like 'when audit_events feature is available'
it_behaves_like 'pagination'
it_behaves_like 'when audit_events feature is not available'
it 'tracks search event', :snowplow do
request
expect_snowplow_event(
category: 'Projects::AuditEventsController',
action: 'search_audit_event',
project: project,
user: auditor,
namespace: project.namespace
)
end
end
context 'when authorized as maintainer' do
before do
project.add_maintainer(maintainer)
sign_in(maintainer)
end
it_behaves_like 'when audit_events feature is available'
it_behaves_like 'pagination'
it_behaves_like 'when audit_events feature is not available'
it 'tracks search event', :snowplow do
request
......
......@@ -47,6 +47,7 @@ RSpec.describe ProjectPolicy do
read_software_license_policy
read_threat_monitoring read_merge_train
read_release
read_project_audit_events
]
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