diff --git a/app/models/concerns/rubygem_searchable.rb b/app/models/concerns/rubygem_searchable.rb index 27eee6ad34f..98613692a99 100644 --- a/app/models/concerns/rubygem_searchable.rb +++ b/app/models/concerns/rubygem_searchable.rb @@ -25,7 +25,8 @@ module RubygemSearchable suggest: { type: "completion", contexts: { name: "yanked", type: "category" } }, yanked: { type: "boolean" }, downloads: { type: "long" }, - updated: { type: "date" } + updated: { type: "date" }, + trusted_publisher: { type: "boolean" } } } scope :search_import, -> { includes(:linkset, :gem_download, :most_recent_version, :versions, :latest_version) } @@ -43,6 +44,7 @@ def search_data # rubocop:disable Metrics/MethodLength version_downloads: latest_version&.downloads_count, platform: latest_version&.platform, authors: latest_version&.authors, + trusted_publisher: latest_version&.pushed_by_trusted_publisher?, info: latest_version&.info, licenses: latest_version&.licenses, metadata: latest_version&.metadata, diff --git a/app/models/version.rb b/app/models/version.rb index f3aa3e75413..ff29c6300a5 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -411,6 +411,10 @@ def gem_file_name "#{full_name}.gem" end + def pushed_by_trusted_publisher? + pusher_api_key&.trusted_publisher? ? true : false + end + private def update_prerelease diff --git a/app/views/searches/advanced.html.erb b/app/views/searches/advanced.html.erb index 0a5ccd43042..6085cb65500 100644 --- a/app/views/searches/advanced.html.erb +++ b/app/views/searches/advanced.html.erb @@ -32,5 +32,8 @@
<%= label_tag :updated, t(".updated"), class: "form__label" %>
<%= text_field_tag :updated, "", placeholder: ">#{1.week.ago.strftime('%F')}", class: "form__input", pattern: "\\s*(<=?|>=?)?[\\d-]+\\s*", data: { search_target: "attribute", action: "input->search#input keydown.enter->search#submit" } %>
+ +
<%= label_tag :trusted_publisher, t(".trusted_publisher"), class: "form__label" %>
+
<%= text_field_tag :trusted_publisher, "", placeholder: "true", class: "form__input", pattern: "true|false", data: { search_target: "attribute", action: "input->search#input keydown.enter->search#submit" } %>
diff --git a/config/locales/de.yml b/config/locales/de.yml index 66e603971e6..302772e6db7 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -844,6 +844,7 @@ de: summary: description: downloads: + trusted_publisher: updated: yanked: show: diff --git a/config/locales/en.yml b/config/locales/en.yml index d88cefe17e9..2d9d17fd4fc 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -757,6 +757,7 @@ en: summary: Summary description: Description downloads: Downloads + trusted_publisher: Trusted Publisher updated: Updated yanked: Yanked show: diff --git a/config/locales/es.yml b/config/locales/es.yml index ee7e6a0d528..5564afbd1f6 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -870,6 +870,7 @@ es: summary: Resumen description: Descripción downloads: Descargas + trusted_publisher: updated: Actualizada yanked: Borrada show: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 612d974d890..8970c73643c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -794,6 +794,7 @@ fr: summary: Sommaire description: Description downloads: Téléchargements + trusted_publisher: updated: Mis à jour yanked: show: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 017c949cf28..8fab744e313 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -755,6 +755,7 @@ ja: summary: 概要 description: 説明 downloads: ダウンロード数 + trusted_publisher: updated: 更新日 yanked: ヤンク済み show: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index e290c8869b8..218dc016fa8 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -748,6 +748,7 @@ nl: summary: description: downloads: + trusted_publisher: updated: yanked: show: diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index ce8a03c68ae..8604738e87a 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -772,6 +772,7 @@ pt-BR: summary: description: downloads: + trusted_publisher: updated: yanked: show: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 0e707dafd0c..5a9842cf09c 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -760,6 +760,7 @@ zh-CN: summary: 概要 description: 描述 downloads: 下载数 + trusted_publisher: updated: 更新 yanked: 撤回 show: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index c0962e266f1..6557b8f50a0 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -750,6 +750,7 @@ zh-TW: summary: 摘要 description: 描述 downloads: 下載數 + trusted_publisher: updated: 更新於 yanked: 移除於 show: diff --git a/test/factories/version.rb b/test/factories/version.rb index 520cdb82c8e..0eea3aa68fb 100644 --- a/test/factories/version.rb +++ b/test/factories/version.rb @@ -28,6 +28,14 @@ metadata { { "rubygems_mfa_required" => "true" } } end + trait :has_trusted_publisher do + pusher_api_key { association(:api_key, :trusted_publisher, key: SecureRandom.hex(24)) } + end + + trait :has_untrusted_publisher do + pusher_api_key { association(:api_key, key: SecureRandom.hex(24)) } + end + after(:create) do |version| if version.info_checksum.blank? checksum = GemInfo.new(version.rubygem.name).info_checksum diff --git a/test/integration/search_test.rb b/test/integration/search_test.rb index ad5c2c91b6f..44c2e09543c 100644 --- a/test/integration/search_test.rb +++ b/test/integration/search_test.rb @@ -115,4 +115,20 @@ class SearchTest < SystemTest refute page.has_content? "Search reverse dependencies Gems…" assert page.has_content? "This gem has no reverse dependencies" end + + test "filtering by trusted publishers" do + rubygem1 = create(:rubygem, name: "LDAP", number: "1.0.0") + rubygem2 = create(:rubygem, name: "LDAP-Shady-Gem", number: "1.0.0") + create(:version, :has_trusted_publisher, rubygem: rubygem1, indexed: false) + create(:version, :has_untrusted_publisher, rubygem: rubygem2, indexed: false) + import_and_refresh + + visit search_path + + fill_in "query", with: "LDAP&trusted_publisher=true" + click_button "search_submit" + + assert page.has_content? "LDAP" + assert page.has_no_content? "LDAP-Shady-Gem" + end end diff --git a/test/models/pusher_test.rb b/test/models/pusher_test.rb index 14fd53443cd..757913c03d4 100644 --- a/test/models/pusher_test.rb +++ b/test/models/pusher_test.rb @@ -636,6 +636,7 @@ def two_cert_chain(signing_key:, root_not_before: Time.current, cert_not_before: "version_downloads" => 0, "platform" => "ruby", "authors" => "Joe User", + "trusted_publisher" => false, "info" => "Some awesome gem", "licenses" => "MIT", "metadata" => { "foo" => "bar" }, diff --git a/test/models/version_test.rb b/test/models/version_test.rb index 98b9194785c..d0deb9f1f31 100644 --- a/test/models/version_test.rb +++ b/test/models/version_test.rb @@ -117,6 +117,38 @@ class VersionTest < ActiveSupport::TestCase end end + context "#pushed_by_trusted_publisher?" do + context "with a trusted publisher api key association" do + setup do + @version = build(:version, :has_trusted_publisher) + end + + should "return true" do + assert_predicate @version, :pushed_by_trusted_publisher? + end + end + + context "with an untrusted publisher api key association" do + setup do + @version = build(:version, :has_untrusted_publisher) + end + + should "return false" do + refute_predicate @version, :pushed_by_trusted_publisher? + end + end + + context "with no api key association" do + setup do + @version = build(:version) + end + + should "return false" do + refute_predicate @version, :pushed_by_trusted_publisher? + end + end + end + context "updated gems" do setup do @existing_gem = create(:rubygem) diff --git a/test/system/advanced_search_test.rb b/test/system/advanced_search_test.rb index 95775a32a6f..79d576cce26 100644 --- a/test/system/advanced_search_test.rb +++ b/test/system/advanced_search_test.rb @@ -39,7 +39,8 @@ class AdvancedSearchTest < ApplicationSystemTestCase fill_in "description", with: "foo" fill_in "downloads", with: ">69" fill_in "updated", with: ">2021-05-05" + fill_in "trusted_publisher", with: "true" - assert has_field? "Search Gems…", with: "name: hello summary: world description: foo downloads: >69 updated: >2021-05-05" + assert has_field? "Search Gems…", with: "name: hello summary: world description: foo downloads: >69 updated: >2021-05-05 trusted_publisher: true" end end