diff options
Diffstat (limited to 'spec/lib/gitlab/audit')
-rw-r--r-- | spec/lib/gitlab/audit/auditor_spec.rb | 258 | ||||
-rw-r--r-- | spec/lib/gitlab/audit/ci_runner_token_author_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/audit/deploy_key_author_spec.rb | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/audit/null_author_spec.rb | 9 | ||||
-rw-r--r-- | spec/lib/gitlab/audit/null_target_spec.rb | 25 | ||||
-rw-r--r-- | spec/lib/gitlab/audit/target_spec.rb | 47 |
6 files changed, 357 insertions, 1 deletions
diff --git a/spec/lib/gitlab/audit/auditor_spec.rb b/spec/lib/gitlab/audit/auditor_spec.rb new file mode 100644 index 00000000000..fc5917ca583 --- /dev/null +++ b/spec/lib/gitlab/audit/auditor_spec.rb @@ -0,0 +1,258 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Audit::Auditor do + let(:name) { 'audit_operation' } + let(:author) { create(:user) } + let(:group) { create(:group) } + let(:provider) { 'standard' } + let(:context) do + { name: name, + author: author, + scope: group, + target: group, + authentication_event: true, + authentication_provider: provider, + message: "Signed in using standard authentication" } + end + + let(:logger) { instance_spy(Gitlab::AuditJsonLogger) } + + subject(:auditor) { described_class } + + describe '.audit' do + context 'when authentication event' do + let(:audit!) { auditor.audit(context) } + + it 'creates an authentication event' do + expect(AuthenticationEvent).to receive(:new).with( + { + user: author, + user_name: author.name, + ip_address: author.current_sign_in_ip, + result: AuthenticationEvent.results[:success], + provider: provider + } + ).and_call_original + + audit! + end + + it 'logs audit events to database', :aggregate_failures do + freeze_time do + audit! + + audit_event = AuditEvent.last + + expect(audit_event.author_id).to eq(author.id) + expect(audit_event.entity_id).to eq(group.id) + expect(audit_event.entity_type).to eq(group.class.name) + expect(audit_event.created_at).to eq(Time.zone.now) + expect(audit_event.details[:target_id]).to eq(group.id) + expect(audit_event.details[:target_type]).to eq(group.class.name) + end + end + + it 'logs audit events to file' do + expect(::Gitlab::AuditJsonLogger).to receive(:build).and_return(logger) + + audit! + + expect(logger).to have_received(:info).with( + hash_including( + 'author_id' => author.id, + 'author_name' => author.name, + 'entity_id' => group.id, + 'entity_type' => group.class.name, + 'details' => kind_of(Hash) + ) + ) + end + + context 'when overriding the create datetime' do + let(:context) do + { name: name, + author: author, + scope: group, + target: group, + created_at: 3.weeks.ago, + authentication_event: true, + authentication_provider: provider, + message: "Signed in using standard authentication" } + end + + it 'logs audit events to database', :aggregate_failures do + freeze_time do + audit! + + audit_event = AuditEvent.last + + expect(audit_event.author_id).to eq(author.id) + expect(audit_event.entity_id).to eq(group.id) + expect(audit_event.entity_type).to eq(group.class.name) + expect(audit_event.created_at).to eq(3.weeks.ago) + expect(audit_event.details[:target_id]).to eq(group.id) + expect(audit_event.details[:target_type]).to eq(group.class.name) + end + end + + it 'logs audit events to file' do + freeze_time do + expect(::Gitlab::AuditJsonLogger).to receive(:build).and_return(logger) + + audit! + + expect(logger).to have_received(:info).with( + hash_including( + 'author_id' => author.id, + 'author_name' => author.name, + 'entity_id' => group.id, + 'entity_type' => group.class.name, + 'details' => kind_of(Hash), + 'created_at' => 3.weeks.ago.iso8601(3) + ) + ) + end + end + end + + context 'when overriding the additional_details' do + additional_details = { action: :custom, from: false, to: true } + let(:context) do + { name: name, + author: author, + scope: group, + target: group, + created_at: Time.zone.now, + additional_details: additional_details, + authentication_event: true, + authentication_provider: provider, + message: "Signed in using standard authentication" } + end + + it 'logs audit events to database' do + freeze_time do + audit! + + expect(AuditEvent.last.details).to include(additional_details) + end + end + + it 'logs audit events to file' do + freeze_time do + expect(::Gitlab::AuditJsonLogger).to receive(:build).and_return(logger) + + audit! + + expect(logger).to have_received(:info).with( + hash_including( + 'details' => hash_including('action' => 'custom', 'from' => 'false', 'to' => 'true'), + 'action' => 'custom', + 'from' => 'false', + 'to' => 'true' + ) + ) + end + end + end + + context 'when overriding the target_details' do + target_details = "this is my target details" + let(:context) do + { + name: name, + author: author, + scope: group, + target: group, + created_at: Time.zone.now, + target_details: target_details, + authentication_event: true, + authentication_provider: provider, + message: "Signed in using standard authentication" + } + end + + it 'logs audit events to database' do + freeze_time do + audit! + + audit_event = AuditEvent.last + expect(audit_event.details).to include({ target_details: target_details }) + expect(audit_event.target_details).to eq(target_details) + end + end + + it 'logs audit events to file' do + freeze_time do + expect(::Gitlab::AuditJsonLogger).to receive(:build).and_return(logger) + + audit! + + expect(logger).to have_received(:info).with( + hash_including( + 'details' => hash_including('target_details' => target_details), + 'target_details' => target_details + ) + ) + end + end + end + end + + context 'when authentication event is false' do + let(:context) do + { name: name, author: author, scope: group, + target: group, authentication_event: false, message: "sample message" } + end + + it 'does not create an authentication event' do + expect { auditor.audit(context) }.not_to change(AuthenticationEvent, :count) + end + end + + context 'when authentication event is invalid' do + let(:audit!) { auditor.audit(context) } + + before do + allow(AuthenticationEvent).to receive(:new).and_raise(ActiveRecord::RecordInvalid) + allow(Gitlab::ErrorTracking).to receive(:track_exception) + end + + it 'tracks error' do + audit! + + expect(Gitlab::ErrorTracking).to have_received(:track_exception).with( + kind_of(ActiveRecord::RecordInvalid), + { audit_operation: name } + ) + end + + it 'does not throw exception' do + expect { auditor.audit(context) }.not_to raise_exception + end + end + + context 'when audit events are invalid' do + let(:audit!) { auditor.audit(context) } + + before do + allow(AuditEvent).to receive(:bulk_insert!).and_raise(ActiveRecord::RecordInvalid) + allow(Gitlab::ErrorTracking).to receive(:track_exception) + end + + it 'tracks error' do + audit! + + expect(Gitlab::ErrorTracking).to have_received(:track_exception).with( + kind_of(ActiveRecord::RecordInvalid), + { audit_operation: name } + ) + end + + it 'does not throw exception' do + expect { auditor.audit(context) }.not_to raise_exception + end + end + end +end diff --git a/spec/lib/gitlab/audit/ci_runner_token_author_spec.rb b/spec/lib/gitlab/audit/ci_runner_token_author_spec.rb index f55e1b44936..89664c57084 100644 --- a/spec/lib/gitlab/audit/ci_runner_token_author_spec.rb +++ b/spec/lib/gitlab/audit/ci_runner_token_author_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Gitlab::Audit::CiRunnerTokenAuthor do describe '.initialize' do subject { described_class.new(audit_event) } - let(:details) { } + let(:details) {} let(:audit_event) { instance_double(AuditEvent, details: details, entity_type: 'Project', entity_path: 'd/e') } context 'with runner_authentication_token' do diff --git a/spec/lib/gitlab/audit/deploy_key_author_spec.rb b/spec/lib/gitlab/audit/deploy_key_author_spec.rb new file mode 100644 index 00000000000..72444f77c91 --- /dev/null +++ b/spec/lib/gitlab/audit/deploy_key_author_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Audit::DeployKeyAuthor do + describe '#initialize' do + it 'sets correct attributes' do + expect(described_class.new(name: 'Lorem deploy key')) + .to have_attributes(id: -3, name: 'Lorem deploy key') + end + + it 'sets default name when it is not provided' do + expect(described_class.new) + .to have_attributes(id: -3, name: 'Deploy Key') + end + end +end diff --git a/spec/lib/gitlab/audit/null_author_spec.rb b/spec/lib/gitlab/audit/null_author_spec.rb index 2045139a5f7..e2f71a34534 100644 --- a/spec/lib/gitlab/audit/null_author_spec.rb +++ b/spec/lib/gitlab/audit/null_author_spec.rb @@ -57,6 +57,15 @@ RSpec.describe Gitlab::Audit::NullAuthor do expect(subject.for(-2, audit_event)).to be_a(Gitlab::Audit::DeployTokenAuthor) expect(subject.for(-2, audit_event)).to have_attributes(id: -2, name: 'Test deploy token') end + + it 'returns DeployKeyAuthor when id equals -3', :aggregate_failures do + allow(audit_event).to receive(:[]).with(:author_name).and_return('Test deploy key') + allow(audit_event).to receive(:details).and_return({}) + allow(audit_event).to receive(:target_type) + + expect(subject.for(-3, audit_event)).to be_a(Gitlab::Audit::DeployKeyAuthor) + expect(subject.for(-3, audit_event)).to have_attributes(id: -3, name: 'Test deploy key') + end end describe '#current_sign_in_ip' do diff --git a/spec/lib/gitlab/audit/null_target_spec.rb b/spec/lib/gitlab/audit/null_target_spec.rb new file mode 100644 index 00000000000..f192e0cd8db --- /dev/null +++ b/spec/lib/gitlab/audit/null_target_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Audit::NullTarget do + subject { described_class.new } + + describe '#id' do + it 'returns nil' do + expect(subject.id).to eq(nil) + end + end + + describe '#type' do + it 'returns nil' do + expect(subject.type).to eq(nil) + end + end + + describe '#details' do + it 'returns nil' do + expect(subject.details).to eq(nil) + end + end +end diff --git a/spec/lib/gitlab/audit/target_spec.rb b/spec/lib/gitlab/audit/target_spec.rb new file mode 100644 index 00000000000..5c06cd117a9 --- /dev/null +++ b/spec/lib/gitlab/audit/target_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Audit::Target do + let(:object) { double('object') } # rubocop:disable RSpec/VerifiedDoubles + + subject { described_class.new(object) } + + describe '#id' do + it 'returns object id' do + allow(object).to receive(:id).and_return(object_id) + + expect(subject.id).to eq(object_id) + end + end + + describe '#type' do + it 'returns object class name' do + allow(object).to receive_message_chain(:class, :name).and_return('User') + + expect(subject.type).to eq('User') + end + end + + describe '#details' do + using RSpec::Parameterized::TableSyntax + + where(:name, :audit_details, :details) do + 'jackie' | 'wanderer' | 'jackie' + 'jackie' | nil | 'jackie' + nil | 'wanderer' | 'wanderer' + nil | nil | 'unknown' + end + + before do + allow(object).to receive(:name).and_return(name) if name + allow(object).to receive(:audit_details).and_return(audit_details) if audit_details + end + + with_them do + it 'returns details' do + expect(subject.details).to eq(details) + end + end + end +end |