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