Commit 6172b14a authored by Max Woolf's avatar Max Woolf

Merge branch '351602-auditor-group-level-events' into 'master'

Ensures audit events are visible to auditor at Group level

See merge request gitlab-org/gitlab!81267
parents 458ec608 662a01dc
......@@ -44,6 +44,8 @@ class Groups::AuditEventsController < Groups::ApplicationController
end
def filter_by_author(params)
can?(current_user, :admin_group, group) ? params : params.merge(author_id: current_user.id)
return params if can?(current_user, :admin_group, group) || current_user.auditor?
params.merge(author_id: current_user.id)
end
end
......@@ -270,6 +270,7 @@ module EE
rule { auditor }.policy do
enable :read_group
enable :read_group_security_dashboard
enable :read_group_audit_events
end
rule { group_saml_config_enabled & group_saml_available & (admin | owner) }.enable :admin_group_saml
......
......@@ -7,6 +7,7 @@ RSpec.describe Groups::AuditEventsController do
let_it_be(:user) { create(:user) }
let_it_be(:owner) { create(:user) }
let_it_be(:auditor) { create(:user, auditor: true) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:events) { create_list(:group_audit_event, 5, entity_id: group.id) }
......@@ -15,152 +16,177 @@ RSpec.describe Groups::AuditEventsController do
let(:entity_type) { nil }
let(:entity_id) { nil }
context 'authorized' do
shared_context 'when audit_events feature is available' do
let(:level) { Gitlab::Audit::Levels::Group.new(group: group) }
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
group.add_owner(owner)
sign_in(owner)
stub_licensed_features(audit_events: true)
allow(Gitlab::Audit::Levels::Group).to receive(:new).and_return(level)
allow(AuditLogFinder).to receive(:new).and_call_original
end
context do
let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
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
context 'when audit_events feature is available' do
let(:level) { Gitlab::Audit::Levels::Group.new(group: group) }
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! }
it 'renders index with 200 status code' do
request
before do
stub_licensed_features(audit_events: true)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
allow(Gitlab::Audit::Levels::Group).to receive(:new).and_return(level)
allow(AuditLogFinder).to receive(:new).and_call_original
end
context 'invokes AuditLogFinder with correct arguments' do
it_behaves_like 'AuditLogFinder params'
end
shared_examples 'AuditLogFinder params' do
it 'has the correct params' do
request
context 'author' do
context 'when no author entity type is specified' do
it_behaves_like 'AuditLogFinder params'
end
expect(AuditLogFinder).to have_received(:new).with(
level: level, params: audit_logs_params
)
end
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! }
it 'renders index with 200 status code' do
it_behaves_like 'AuditLogFinder params'
end
end
context 'ordering' do
shared_examples 'orders by id descending' do
it 'orders by id descending' do
request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id).reverse
context 'invokes AuditLogFinder with correct arguments' do
it_behaves_like 'AuditLogFinder params'
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 sorting by latest events first' do
let(:sort) { 'created_desc' }
context 'author' do
context 'when no author entity type is specified' do
it_behaves_like 'AuditLogFinder params'
end
it_behaves_like 'orders by id descending'
end
context 'when sorting by oldest events first' do
let(:sort) { 'created_asc' }
it 'orders by id ascending' do
request
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! }
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id)
it_behaves_like 'AuditLogFinder params'
end
expect(actual_event_ids).to eq(expected_event_ids)
end
end
context 'ordering' do
shared_examples 'orders by id descending' do
it 'orders by id descending' do
request
context 'when sorting by an unsupported sort order' do
let(:sort) { 'FOO' }
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id).reverse
it_behaves_like 'orders by id descending'
end
end
expect(actual_event_ids).to eq(expected_event_ids)
end
end
context 'pagination' do
it 'sets instance variables' do
request
context 'when no sort order is specified' do
it_behaves_like 'orders by id descending'
end
expect(assigns(:is_last_page)).to be(true)
end
context 'when sorting by latest events first' do
let(:sort) { 'created_desc' }
it 'paginates audit events, without casting a count query' do
serializer = instance_spy(AuditEventSerializer)
allow(AuditEventSerializer).to receive(:new).and_return(serializer)
it_behaves_like 'orders by id descending'
end
request
context 'when sorting by oldest events first' do
let(:sort) { 'created_asc' }
expect(serializer).to have_received(:represent).with(kind_of(Kaminari::PaginatableWithoutCount))
end
end
it 'orders by id ascending' do
request
it 'tracks search event', :snowplow do
request
actual_event_ids = assigns(:events).map { |event| event[:id] }
expected_event_ids = events.map(&:id)
expect_snowplow_event(
category: 'Groups::AuditEventsController',
action: 'search_audit_event',
user: client,
namespace: group
)
end
expect(actual_event_ids).to eq(expected_event_ids)
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 sorting by an unsupported sort order' do
let(:sort) { 'FOO' }
with_them do
it 'returns an error' do
get :index, params: { group_id: group.to_param, 'created_before': created_before, 'created_after': created_after }
it_behaves_like 'orders by id descending'
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
context 'when authorized owner' do
before do
group.add_owner(owner)
sign_in(owner)
end
expect(assigns(:is_last_page)).to be(true)
end
let(:client) { owner }
it 'paginates audit events, without casting a count query' do
serializer = instance_spy(AuditEventSerializer)
allow(AuditEventSerializer).to receive(:new).and_return(serializer)
context do
let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
end
request
it_behaves_like 'when audit_events feature is available'
end
expect(serializer).to have_received(:represent).with(kind_of(Kaminari::PaginatableWithoutCount))
end
end
it_behaves_like 'tracking unique visits', :index do
let(:request_params) { { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id } }
let(:target_id) { 'g_compliance_audit_events' }
end
end
it 'tracks search event', :snowplow do
request
context 'when authorized auditor' do
before do
sign_in(auditor)
end
expect_snowplow_event(
category: 'Groups::AuditEventsController',
action: 'search_audit_event',
user: owner,
namespace: group
)
end
let(:client) { auditor }
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: { group_id: group.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
end
end
context do
let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
end
it_behaves_like 'when audit_events feature is available'
end
it_behaves_like 'tracking unique visits', :index do
......
......@@ -610,6 +610,7 @@ RSpec.describe GroupPolicy do
it { is_expected.to be_allowed(:read_group) }
it { is_expected.to be_allowed(:read_milestone) }
it { is_expected.to be_allowed(:read_group_audit_events) }
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