diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 00:07:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 00:07:54 +0300 |
commit | c4db541c1b2c97ab1eda354ea3899489fe5c33e5 (patch) | |
tree | 45d5d381232179082ea11136e3b53211b37349d5 /spec/lib | |
parent | 603c7d4cac5e28bc1c75e50c23ed2cbe56f1aafc (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/lib')
-rw-r--r-- | spec/lib/gitlab/database/migration_helpers_spec.rb | 44 | ||||
-rw-r--r-- | spec/lib/gitlab/x509/commit_spec.rb | 244 | ||||
-rw-r--r-- | spec/lib/gitlab/x509/signature_spec.rb | 232 |
3 files changed, 284 insertions, 236 deletions
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 1fd6157ce43..9ac2660908c 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1542,16 +1542,54 @@ describe Gitlab::Database::MigrationHelpers do end describe '#create_or_update_plan_limit' do - it 'creates or updates plan limits' do + class self::Plan < ActiveRecord::Base + self.table_name = 'plans' + end + + class self::PlanLimits < ActiveRecord::Base + self.table_name = 'plan_limits' + end + + it 'properly escapes names' do expect(model).to receive(:execute).with <<~SQL INSERT INTO plan_limits (plan_id, "project_hooks") - VALUES - ((SELECT id FROM plans WHERE name = 'free' LIMIT 1), '10') + SELECT id, '10' FROM plans WHERE name = 'free' LIMIT 1 ON CONFLICT (plan_id) DO UPDATE SET "project_hooks" = EXCLUDED."project_hooks"; SQL model.create_or_update_plan_limit('project_hooks', 'free', 10) end + + context 'when plan does not exist' do + it 'does not create any plan limits' do + expect { model.create_or_update_plan_limit('project_hooks', 'plan_name', 10) } + .not_to change { self.class::PlanLimits.count } + end + end + + context 'when plan does exist' do + let!(:plan) { self.class::Plan.create!(name: 'plan_name') } + + context 'when limit does not exist' do + it 'inserts a new plan limits' do + expect { model.create_or_update_plan_limit('project_hooks', 'plan_name', 10) } + .to change { self.class::PlanLimits.count }.by(1) + + expect(self.class::PlanLimits.pluck(:project_hooks)).to contain_exactly(10) + end + end + + context 'when limit does exist' do + let!(:plan_limit) { self.class::PlanLimits.create!(plan_id: plan.id) } + + it 'updates an existing plan limits' do + expect { model.create_or_update_plan_limit('project_hooks', 'plan_name', 999) } + .not_to change { self.class::PlanLimits.count } + + expect(plan_limit.reload.project_hooks).to eq(999) + end + end + end end describe '#with_lock_retries' do diff --git a/spec/lib/gitlab/x509/commit_spec.rb b/spec/lib/gitlab/x509/commit_spec.rb index 07d7eba6b9a..ac93609b467 100644 --- a/spec/lib/gitlab/x509/commit_spec.rb +++ b/spec/lib/gitlab/x509/commit_spec.rb @@ -5,252 +5,30 @@ describe Gitlab::X509::Commit do describe '#signature' do let(:signature) { described_class.new(commit).signature } - let(:user1_certificate_attributes) do - { - subject_key_identifier: X509Helpers::User1.certificate_subject_key_identifier, - subject: X509Helpers::User1.certificate_subject, - email: X509Helpers::User1.certificate_email, - serial_number: X509Helpers::User1.certificate_serial - } - end - - let(:user1_issuer_attributes) do - { - subject_key_identifier: X509Helpers::User1.issuer_subject_key_identifier, - subject: X509Helpers::User1.certificate_issuer, - crl_url: X509Helpers::User1.certificate_crl - } - end + context 'returns the cached signature' do + let(:commit_sha) { '189a6c924013fc3fe40d6f1ec1dc20214183bc97' } + let(:project) { create(:project, :public, :repository) } + let(:commit) { create(:commit, project: project, sha: commit_sha) } - shared_examples 'returns the cached signature on second call' do - it 'returns the cached signature on second call' do - x509_commit = described_class.new(commit) + it 'on second call' do + allow_any_instance_of(described_class).to receive(:new).and_call_original + expect_any_instance_of(described_class).to receive(:create_cached_signature!).and_call_original - expect(x509_commit).to receive(:create_cached_signature).and_call_original signature # consecutive call - expect(x509_commit).not_to receive(:create_cached_signature).and_call_original + expect(described_class).not_to receive(:create_cached_signature!).and_call_original signature end end - let!(:project) { create :project, :repository, path: X509Helpers::User1.path } - let!(:commit_sha) { X509Helpers::User1.commit } - context 'unsigned commit' do + let!(:project) { create :project, :repository, path: X509Helpers::User1.path } + let!(:commit_sha) { X509Helpers::User1.commit } let!(:commit) { create :commit, project: project, sha: commit_sha } it 'returns nil' do - expect(described_class.new(commit).signature).to be_nil - end - end - - context 'valid signature from known user' do - let!(:commit) { create :commit, project: project, sha: commit_sha, created_at: Time.utc(2019, 1, 1, 20, 15, 0), committer_email: X509Helpers::User1.emails.first } - - let!(:user) { create(:user, email: X509Helpers::User1.emails.first) } - - before do - allow(Gitlab::Git::Commit).to receive(:extract_signature_lazily) - .with(Gitlab::Git::Repository, commit_sha) - .and_return( - [ - X509Helpers::User1.signed_commit_signature, - X509Helpers::User1.signed_commit_base_data - ] - ) - end - - it 'returns an unverified signature' do - expect(signature).to have_attributes( - commit_sha: commit_sha, - project: project, - verification_status: 'unverified' - ) - expect(signature.x509_certificate).to have_attributes(user1_certificate_attributes) - expect(signature.x509_certificate.x509_issuer).to have_attributes(user1_issuer_attributes) - expect(signature.persisted?).to be_truthy - end - end - - context 'verified signature from known user' do - let!(:commit) { create :commit, project: project, sha: commit_sha, created_at: Time.utc(2019, 1, 1, 20, 15, 0), committer_email: X509Helpers::User1.emails.first } - - let!(:user) { create(:user, email: X509Helpers::User1.emails.first) } - - before do - allow(Gitlab::Git::Commit).to receive(:extract_signature_lazily) - .with(Gitlab::Git::Repository, commit_sha) - .and_return( - [ - X509Helpers::User1.signed_commit_signature, - X509Helpers::User1.signed_commit_base_data - ] - ) - end - - context 'with trusted certificate store' do - before do - store = OpenSSL::X509::Store.new - certificate = OpenSSL::X509::Certificate.new X509Helpers::User1.trust_cert - store.add_cert(certificate) - allow(OpenSSL::X509::Store).to receive(:new) - .and_return( - store - ) - end - - it 'returns a verified signature' do - expect(signature).to have_attributes( - commit_sha: commit_sha, - project: project, - verification_status: 'verified' - ) - expect(signature.x509_certificate).to have_attributes(user1_certificate_attributes) - expect(signature.x509_certificate.x509_issuer).to have_attributes(user1_issuer_attributes) - expect(signature.persisted?).to be_truthy - end - - context 'revoked certificate' do - let(:x509_issuer) { create(:x509_issuer, user1_issuer_attributes) } - let!(:x509_certificate) { create(:x509_certificate, user1_certificate_attributes.merge(x509_issuer_id: x509_issuer.id, certificate_status: :revoked)) } - - it 'returns an unverified signature' do - expect(signature).to have_attributes( - commit_sha: commit_sha, - project: project, - verification_status: 'unverified' - ) - expect(signature.x509_certificate).to have_attributes(user1_certificate_attributes) - expect(signature.x509_certificate.x509_issuer).to have_attributes(user1_issuer_attributes) - expect(signature.persisted?).to be_truthy - end - end - end - - context 'without trusted certificate within store' do - before do - store = OpenSSL::X509::Store.new - allow(OpenSSL::X509::Store).to receive(:new) - .and_return( - store - ) - end - - it 'returns an unverified signature' do - expect(signature).to have_attributes( - commit_sha: commit_sha, - project: project, - verification_status: 'unverified' - ) - expect(signature.x509_certificate).to have_attributes(user1_certificate_attributes) - expect(signature.x509_certificate.x509_issuer).to have_attributes(user1_issuer_attributes) - expect(signature.persisted?).to be_truthy - end - end - end - - context 'unverified signature from unknown user' do - let!(:commit) { create :commit, project: project, sha: commit_sha, created_at: Time.utc(2019, 1, 1, 20, 15, 0), committer_email: X509Helpers::User1.emails.first } - - before do - allow(Gitlab::Git::Commit).to receive(:extract_signature_lazily) - .with(Gitlab::Git::Repository, commit_sha) - .and_return( - [ - X509Helpers::User1.signed_commit_signature, - X509Helpers::User1.signed_commit_base_data - ] - ) - end - - it 'returns an unverified signature' do - expect(signature).to have_attributes( - commit_sha: commit_sha, - project: project, - verification_status: 'unverified' - ) - expect(signature.x509_certificate).to have_attributes(user1_certificate_attributes) - expect(signature.x509_certificate.x509_issuer).to have_attributes(user1_issuer_attributes) - expect(signature.persisted?).to be_truthy - end - end - - context 'invalid signature' do - let!(:commit) { create :commit, project: project, sha: commit_sha, committer_email: X509Helpers::User1.emails.first } - - let!(:user) { create(:user, email: X509Helpers::User1.emails.first) } - - before do - allow(Gitlab::Git::Commit).to receive(:extract_signature_lazily) - .with(Gitlab::Git::Repository, commit_sha) - .and_return( - [ - # Corrupt the key - X509Helpers::User1.signed_commit_signature.tr('A', 'B'), - X509Helpers::User1.signed_commit_base_data - ] - ) - end - - it 'returns nil' do - expect(described_class.new(commit).signature).to be_nil - end - end - - context 'invalid commit message' do - let!(:commit) { create :commit, project: project, sha: commit_sha, committer_email: X509Helpers::User1.emails.first } - - let!(:user) { create(:user, email: X509Helpers::User1.emails.first) } - - before do - allow(Gitlab::Git::Commit).to receive(:extract_signature_lazily) - .with(Gitlab::Git::Repository, commit_sha) - .and_return( - [ - X509Helpers::User1.signed_commit_signature, - # Corrupt the commit message - 'x' - ] - ) - end - - it 'returns nil' do - expect(described_class.new(commit).signature).to be_nil - end - end - - context 'certificate_crl' do - let!(:commit) { create :commit, project: project, sha: commit_sha, created_at: Time.utc(2019, 1, 1, 20, 15, 0), committer_email: X509Helpers::User1.emails.first } - let(:signed_commit) { described_class.new(commit) } - - describe 'valid crlDistributionPoints' do - before do - allow(signed_commit).to receive(:get_certificate_extension).and_call_original - - allow(signed_commit).to receive(:get_certificate_extension) - .with('crlDistributionPoints') - .and_return("\nFull Name:\n URI:http://ch.siemens.com/pki?ZZZZZZA2.crl\n URI:ldap://cl.siemens.net/CN=ZZZZZZA2,L=PKI?certificateRevocationList\n URI:ldap://cl.siemens.com/CN=ZZZZZZA2,o=Trustcenter?certificateRevocationList\n") - end - - it 'returns an unverified signature' do - expect(signed_commit.signature.x509_certificate.x509_issuer).to have_attributes(user1_issuer_attributes) - end - end - - describe 'valid crlDistributionPoints providing multiple http URIs' do - before do - allow(signed_commit).to receive(:get_certificate_extension).and_call_original - - allow(signed_commit).to receive(:get_certificate_extension) - .with('crlDistributionPoints') - .and_return("\nFull Name:\n URI:http://cdp1.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl\n\nFull Name:\n URI:http://cdp2.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl\n") - end - - it 'extracts the first URI' do - expect(signed_commit.signature.x509_certificate.x509_issuer.crl_url).to eq("http://cdp1.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl") - end + expect(signature).to be_nil end end end diff --git a/spec/lib/gitlab/x509/signature_spec.rb b/spec/lib/gitlab/x509/signature_spec.rb new file mode 100644 index 00000000000..6c585acd5cd --- /dev/null +++ b/spec/lib/gitlab/x509/signature_spec.rb @@ -0,0 +1,232 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::X509::Signature do + let(:issuer_attributes) do + { + subject_key_identifier: X509Helpers::User1.issuer_subject_key_identifier, + subject: X509Helpers::User1.certificate_issuer, + crl_url: X509Helpers::User1.certificate_crl + } + end + + context 'commit signature' do + let(:certificate_attributes) do + { + subject_key_identifier: X509Helpers::User1.certificate_subject_key_identifier, + subject: X509Helpers::User1.certificate_subject, + email: X509Helpers::User1.certificate_email, + serial_number: X509Helpers::User1.certificate_serial + } + end + + context 'verified signature' do + context 'with trusted certificate store' do + before do + store = OpenSSL::X509::Store.new + certificate = OpenSSL::X509::Certificate.new(X509Helpers::User1.trust_cert) + store.add_cert(certificate) + allow(OpenSSL::X509::Store).to receive(:new).and_return(store) + end + + it 'returns a verified signature if email does match' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate).to have_attributes(certificate_attributes) + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) + expect(signature.verified_signature).to be_truthy + expect(signature.verification_status).to eq(:verified) + end + + it 'returns an unverified signature if email does not match' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + "gitlab@example.com", + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate).to have_attributes(certificate_attributes) + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) + expect(signature.verified_signature).to be_truthy + expect(signature.verification_status).to eq(:unverified) + end + + it 'returns an unverified signature if email does match and time is wrong' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + Time.new(2020, 2, 22) + ) + + expect(signature.x509_certificate).to have_attributes(certificate_attributes) + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) + expect(signature.verified_signature).to be_falsey + expect(signature.verification_status).to eq(:unverified) + end + + it 'returns an unverified signature if certificate is revoked' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + + expect(signature.verification_status).to eq(:verified) + + signature.x509_certificate.revoked! + + expect(signature.verification_status).to eq(:unverified) + end + end + + context 'without trusted certificate within store' do + before do + store = OpenSSL::X509::Store.new + allow(OpenSSL::X509::Store).to receive(:new) + .and_return( + store + ) + end + + it 'returns an unverified signature' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate).to have_attributes(certificate_attributes) + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) + expect(signature.verified_signature).to be_falsey + expect(signature.verification_status).to eq(:unverified) + end + end + end + + context 'invalid signature' do + it 'returns nil' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature.tr('A', 'B'), + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + expect(signature.x509_certificate).to be_nil + expect(signature.verified_signature).to be_falsey + expect(signature.verification_status).to eq(:unverified) + end + end + + context 'invalid commit message' do + it 'returns nil' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + 'x', + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + expect(signature.x509_certificate).to be_nil + expect(signature.verified_signature).to be_falsey + expect(signature.verification_status).to eq(:unverified) + end + end + end + + context 'certificate_crl' do + describe 'valid crlDistributionPoints' do + before do + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original + + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension) + .with('crlDistributionPoints') + .and_return("\nFull Name:\n URI:http://ch.siemens.com/pki?ZZZZZZA2.crl\n URI:ldap://cl.siemens.net/CN=ZZZZZZA2,L=PKI?certificateRevocationList\n URI:ldap://cl.siemens.com/CN=ZZZZZZA2,o=Trustcenter?certificateRevocationList\n") + end + + it 'creates an issuer' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) + end + end + + describe 'valid crlDistributionPoints providing multiple http URIs' do + before do + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original + + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension) + .with('crlDistributionPoints') + .and_return("\nFull Name:\n URI:http://cdp1.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl\n\nFull Name:\n URI:http://cdp2.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl\n") + end + + it 'extracts the first URI' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + X509Helpers::User1.certificate_email, + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate.x509_issuer.crl_url).to eq("http://cdp1.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl") + end + end + end + + context 'email' do + describe 'subjectAltName with email, othername' do + before do + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original + + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension) + .with('subjectAltName') + .and_return("email:gitlab@example.com, othername:<unsupported>") + end + + it 'extracts email' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + 'gitlab@example.com', + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate.email).to eq("gitlab@example.com") + end + end + + describe 'subjectAltName with othername, email' do + before do + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original + + allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension) + .with('subjectAltName') + .and_return("othername:<unsupported>, email:gitlab@example.com") + end + + it 'extracts email' do + signature = described_class.new( + X509Helpers::User1.signed_commit_signature, + X509Helpers::User1.signed_commit_base_data, + 'gitlab@example.com', + X509Helpers::User1.signed_commit_time + ) + + expect(signature.x509_certificate.email).to eq("gitlab@example.com") + end + end + end +end |