diff options
6 files changed, 203 insertions, 14 deletions
| diff --git a/db/post_migrate/20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys.rb b/db/post_migrate/20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys.rb index 08c9ce1d3bb..01d56fbd490 100644 --- a/db/post_migrate/20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys.rb +++ b/db/post_migrate/20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys.rb @@ -5,6 +5,7 @@ class ScheduleCreateGpgKeySubkeysFromGpgKeys < ActiveRecord::Migration    disable_ddl_transaction!    DOWNTIME = false +  MIGRATION = 'CreateGpgKeySubkeysFromGpgKeys'    class GpgKey < ActiveRecord::Base      self.table_name = 'gpg_keys' @@ -15,7 +16,7 @@ class ScheduleCreateGpgKeySubkeysFromGpgKeys < ActiveRecord::Migration    def up      GpgKey.select(:id).each_batch do |gpg_keys|        jobs = gpg_keys.pluck(:id).map do |id| -        ['CreateGpgKeySubkeysFromGpgKeys', [id]] +        [MIGRATION, [id]]        end        BackgroundMigrationWorker.perform_bulk(jobs) diff --git a/spec/lib/gitlab/background_migration/create_gpg_key_subkeys_from_gpg_keys_spec.rb b/spec/lib/gitlab/background_migration/create_gpg_key_subkeys_from_gpg_keys_spec.rb new file mode 100644 index 00000000000..26d48cc8201 --- /dev/null +++ b/spec/lib/gitlab/background_migration/create_gpg_key_subkeys_from_gpg_keys_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::CreateGpgKeySubkeysFromGpgKeys, :migration, schema: 20171005130944 do +  context 'when GpgKey exists' do +    let!(:gpg_key) { create(:gpg_key, key: GpgHelpers::User3.public_key) } + +    before do +      GpgKeySubkey.destroy_all +    end + +    it 'generate the subkeys' do +      expect do +        described_class.new.perform(gpg_key.id) +      end.to change { gpg_key.subkeys.count }.from(0).to(2) +    end + +    it 'schedules the signature update worker' do +      expect(InvalidGpgSignatureUpdateWorker).to receive(:perform_async).with(gpg_key.id) + +      described_class.new.perform(gpg_key.id) +    end +  end + +  context 'when GpgKey does not exist' do +    it 'does not do anything' do +      expect(Gitlab::Gpg).not_to receive(:subkeys_from_key) +      expect(InvalidGpgSignatureUpdateWorker).not_to receive(:perform_async) + +      described_class.new.perform(123) +    end +  end +end diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index b9fd4d02156..d6000af0ecd 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -2,17 +2,16 @@ require 'rails_helper'  RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do    describe '#run' do -    let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } -    let!(:project) { create :project, :repository, path: 'sample-project' } +    let(:signature)       { [GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data] } +    let(:committer_email) { GpgHelpers::User1.emails.first } +    let!(:commit_sha)     { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } +    let!(:project)        { create :project, :repository, path: 'sample-project' }      let!(:raw_commit) do        raw_commit = double(          :raw_commit, -        signature: [ -          GpgHelpers::User1.signed_commit_signature, -          GpgHelpers::User1.signed_commit_base_data -        ], +        signature: signature,          sha: commit_sha, -        committer_email: GpgHelpers::User1.emails.first +        committer_email: committer_email        )        allow(raw_commit).to receive :save! @@ -29,12 +28,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do        allow(Rugged::Commit).to receive(:extract_signature)          .with(Rugged::Repository, commit_sha) -        .and_return( -          [ -            GpgHelpers::User1.signed_commit_signature, -            GpgHelpers::User1.signed_commit_base_data -          ] -        ) +        .and_return(signature)      end      context 'gpg signature did have an associated gpg key which was removed later' do @@ -183,5 +177,34 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do          )        end      end + +    context 'gpg signature did not have an associated gpg subkey' do +      let(:signature)       { [GpgHelpers::User3.signed_commit_signature, GpgHelpers::User3.signed_commit_base_data] } +      let(:committer_email) { GpgHelpers::User3.emails.first } +      let!(:user)           { create :user, email: GpgHelpers::User3.emails.first } + +      let!(:invalid_gpg_signature) do +        create :gpg_signature, +          project: project, +          commit_sha: commit_sha, +          gpg_key: nil, +          gpg_key_primary_keyid: GpgHelpers::User3.subkey_fingerprints.last[24..-1], +          verification_status: 'unknown_key' +      end + +      it 'updates the signature to being valid when the missing gpg key is added' do +        # InvalidGpgSignatureUpdater is called by the after_create hook +        gpg_key = create(:gpg_key, key: GpgHelpers::User3.public_key, user: user) +        subkey = gpg_key.subkeys.last + +        expect(invalid_gpg_signature.reload).to have_attributes( +          project: project, +          commit_sha: commit_sha, +          gpg_key_subkey_id: subkey.id, +          gpg_key_primary_keyid: subkey.keyid, +          verification_status: 'verified' +        ) +      end +    end    end  end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 11a2aea1915..ab9a166db00 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -28,6 +28,23 @@ describe Gitlab::Gpg do      end    end +  describe '.subkeys_from_key' do +    it 'returns the subkeys by primary key' do +      all_subkeys = described_class.subkeys_from_key(GpgHelpers::User1.public_key) +      subkeys = all_subkeys[GpgHelpers::User1.primary_keyid] + +      expect(subkeys).to be_present +      expect(subkeys.first[:keyid]).to be_present +      expect(subkeys.first[:fingerprint]).to be_present +    end + +    it 'returns an empty array when there are not subkeys' do +      all_subkeys = described_class.subkeys_from_key(GpgHelpers::User4.public_key) + +      expect(all_subkeys[GpgHelpers::User4.primary_keyid]).to be_empty +    end +  end +    describe '.user_infos_from_key' do      it 'returns the names and emails' do        user_infos = described_class.user_infos_from_key(GpgHelpers::User1.public_key) diff --git a/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb b/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb new file mode 100644 index 00000000000..0e884a7d910 --- /dev/null +++ b/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys') + +describe ScheduleCreateGpgKeySubkeysFromGpgKeys, :migration, :sidekiq do +  matcher :be_scheduled_migration do |*expected| +    match do |migration| +      BackgroundMigrationWorker.jobs.any? do |job| +        job['args'] == [migration, expected] +      end +    end + +    failure_message do |migration| +      "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!" +    end +  end + +  before do +    create(:gpg_key, id: 1, key: GpgHelpers::User1.public_key) +    create(:gpg_key, id: 2, key: GpgHelpers::User3.public_key) +    # Delete all subkeys so they can be recreated +    GpgKeySubkey.destroy_all +  end + +  it 'correctly schedules background migrations' do +    Sidekiq::Testing.fake! do +      migrate! + +      expect(described_class::MIGRATION).to be_scheduled_migration(1) +      expect(described_class::MIGRATION).to be_scheduled_migration(2) +      expect(BackgroundMigrationWorker.jobs.size).to eq(2) +    end +  end + +  it 'schedules background migrations' do +    Sidekiq::Testing.inline! do +      expect(GpgKeySubkey.count).to eq(0) + +      migrate! + +      expect(GpgKeySubkey.count).to eq(3) +    end +  end +end diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 4b1ca7ff9c8..3f7279a50e0 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -441,4 +441,77 @@ module GpgHelpers        ['john.doe@example.com']      end    end + +  # GPG Key containing just the main key +  module User4 +    extend self + +    def public_key +      <<~KEY.strip +        -----BEGIN PGP PUBLIC KEY BLOCK----- + +        mQENBFnWcesBCAC6Y8FXl9ZJ9HPa6dIYcgQrvjIQcwoQCUEsaXNRpc+206RPCIXK +        aIYr0nTD8GeovMuUONXTj+DdueQU2GAAqHHOqvDDVXqRrW3xfWnSwix7sTuhG1Ew +        PLHYmjLENqaTsdyliEo3N8VWy2k0QRbC3R6xvop4Ooa87D5vcATIl0gYFtSiHIL+ +        TervYvTG9Eq1qSLZHbe2x4IzeqX2luikPKokL7j8FTZaCmC5MezIUur1ulfyYY/j +        SkST/1aUFc5QXJJSZA0MYJWZX6x7Y3l7yl0dkHqmK8OTuo8RPWd3ybEiuvRsOL8K +        GAv/PmVJRGDAf7GGbwXXsE9MiZ5GzVPxHnexABEBAAG0G0pvaG4gRG9lIDxqb2hu +        QGV4YW1wbGUuY29tPokBTgQTAQgAOBYhBAh0izYM0lwuzJnVlAcBbPnhOj+bBQJZ +        1nHrAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEAcBbPnhOj+bkywH/i4w +        OwpDxoTjUQlPlqGAGuzvWaPzSJndawgmMTr68oRsD+wlQmQQTR5eqxCpUIyV4aYb +        D697RYzoqbT4mlU49ymzfKSAxFe88r1XQWdm81DcofHVPmw2GBrIqaX3Du4Z7xkI +        Q9/S43orwknh5FoVwU8Nau7qBuv9vbw2apSkuA1oBj3spQ8hqwLavACyQ+fQloAT +        hSDNqPiCZj6L0dwM1HYiqVoN3Q7qjgzzeBzlXzljJoWblhxllvMK20bVoa7H+uR2 +        lczFHfsX8VTIMjyTGP7R3oHN91DEahlQybVVNLmNSDKZM2P/0d28BRUmWxQJ4Ws3 +        J4hOWDKnLMed3VOIWzM= +        =xVuW +        -----END PGP PUBLIC KEY BLOCK----- +      KEY +    end + +    def secret_key +      <<~KEY.strip +        -----BEGIN PGP PRIVATE KEY BLOCK----- + +        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 +        =/37z +        -----END PGP PRIVATE KEY BLOCK----- +      KEY +    end + +    def primary_keyid +      fingerprint[-16..-1] +    end + +    def fingerprint +      '08748B360CD25C2ECC99D59407016CF9E13A3F9B' +    end +  end  end | 
