From 9b4990a4d71b057f0fec14399cd1f2a421901963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 27 Sep 2017 19:45:19 -0500 Subject: [PATCH] Associate GgpSignature with GpgKeySubkey if comes from a subkey Additionally we're delegating missing method calls on GpgKeySubkey to GpgKey since most of the info required when verifying a signature is found on GpgKey which is the parent of GpgKeySubkey --- app/models/gpg_key.rb | 11 ----------- app/models/gpg_key_subkey.rb | 15 +++++++++++++++ app/models/gpg_signature.rb | 16 ++++++++++++++++ ...58_add_gpg_key_subkey_id_to_gpg_signatures.rb | 10 ++++++++++ db/schema.rb | 3 +++ lib/gitlab/gpg/commit.rb | 14 ++++++++++++-- 6 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 6d3537b6fcf..ed09b44027c 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -40,17 +40,6 @@ class GpgKey < ActiveRecord::Base after_commit :update_invalid_gpg_signatures, on: :create after_create :generate_subkeys - def self.find_with_subkeys(fingerprint) - keys_table = arel_table - subkeys_table = GpgKeySubkey.arel_table - - condition = keys_table[:primary_keyid].eq(fingerprint).or( - subkeys_table[:keyid].eq(fingerprint) - ) - - joins(:subkeys).where(condition).first - end - def primary_keyid super&.upcase end diff --git a/app/models/gpg_key_subkey.rb b/app/models/gpg_key_subkey.rb index 4f967f1e47c..8222e5606aa 100644 --- a/app/models/gpg_key_subkey.rb +++ b/app/models/gpg_key_subkey.rb @@ -1,3 +1,18 @@ class GpgKeySubkey < ActiveRecord::Base + include ShaAttribute + + sha_attribute :keyid + sha_attribute :fingerprint + belongs_to :gpg_key + + def method_missing(m, *a, &b) + return super unless gpg_key.respond_to?(m) + + gpg_key.public_send(m, *a, &b) # rubocop:disable GitlabSecurity/PublicSend + end + + def respond_to_missing?(method, include_private = false) + gpg_key.respond_to?(method, include_private) || super + end end diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 1f047a32c84..c7f75288407 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -15,11 +15,27 @@ class GpgSignature < ActiveRecord::Base belongs_to :project belongs_to :gpg_key + belongs_to :gpg_key_subkey validates :commit_sha, presence: true validates :project_id, presence: true validates :gpg_key_primary_keyid, presence: true + def gpg_key=(model) + case model + when GpgKey then super + when GpgKeySubkey then write_attribute(:gpg_key_subkey_id, model.id) + end + end + + def gpg_key + if gpg_key_id + super + elsif gpg_key_subkey_id + gpg_key_subkey + end + end + def gpg_key_primary_keyid super&.upcase end diff --git a/db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.rb b/db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.rb new file mode 100644 index 00000000000..74b43d732d5 --- /dev/null +++ b/db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.rb @@ -0,0 +1,10 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddGpgKeySubkeyIdToGpgSignatures < ActiveRecord::Migration + DOWNTIME = false + + def change + add_reference(:gpg_signatures, :gpg_key_subkey, index: true, foreign_key: { on_delete: :nullify }) + end +end diff --git a/db/schema.rb b/db/schema.rb index 0d02e584d0c..0beebc16cbb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -610,11 +610,13 @@ ActiveRecord::Schema.define(version: 20171004121444) do t.text "gpg_key_user_name" t.text "gpg_key_user_email" t.integer "verification_status", limit: 2, default: 0, null: false + t.integer "gpg_key_subkey_id" end add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", unique: true, using: :btree add_index "gpg_signatures", ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree add_index "gpg_signatures", ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree + add_index "gpg_signatures", ["gpg_key_subkey_id"], name: "index_gpg_signatures_on_gpg_key_subkey_id", using: :btree add_index "gpg_signatures", ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree create_table "identities", force: :cascade do |t| @@ -1736,6 +1738,7 @@ ActiveRecord::Schema.define(version: 20171004121444) do add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade add_foreign_key "gpg_key_subkeys", "gpg_keys", on_delete: :cascade add_foreign_key "gpg_keys", "users", on_delete: :cascade + add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify add_foreign_key "gpg_signatures", "gpg_keys", on_delete: :nullify add_foreign_key "gpg_signatures", "projects", on_delete: :cascade add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 40274e13918..5cbc836314f 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -43,7 +43,7 @@ module Gitlab # key belonging to the keyid. # This way we can add the key to the temporary keychain and extract # the proper signature. - gpg_key = GpgKey.find_with_subkeys(verified_signature.fingerprint) + gpg_key = find_gpg_key(verified_signature.fingerprint) if gpg_key Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) @@ -74,7 +74,7 @@ module Gitlab commit_sha: @commit.sha, project: @commit.project, gpg_key: gpg_key, - gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature.fingerprint, + gpg_key_primary_keyid: gpg_keyid(gpg_key) || verified_signature.fingerprint, gpg_key_user_name: user_infos[:name], gpg_key_user_email: user_infos[:email], verification_status: verification_status @@ -98,6 +98,16 @@ module Gitlab def user_infos(gpg_key) gpg_key&.verified_user_infos&.first || gpg_key&.user_infos&.first || {} end + + def gpg_keyid(gpg_key) + return nil unless gpg_key + + gpg_key.is_a?(GpgKey) ? gpg_key.primary_keyid : gpg_key.keyid + end + + def find_gpg_key(keyid) + GpgKey.find_by(primary_keyid: keyid) || GpgKeySubkey.find_by(keyid: keyid) + end end end end -- GitLab