Skip to content

Commit

Permalink
Don’t allow publishing new versions of an archived gem
Browse files Browse the repository at this point in the history
  • Loading branch information
colby-swandale committed Aug 15, 2024
1 parent 28e0b41 commit b41ec50
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 1 deletion.
8 changes: 7 additions & 1 deletion app/models/pusher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def initialize(api_key, body, request: nil)

def process
trace("gemcutter.pusher.process", tags: { "gemcutter.api_key.owner" => owner.to_gid }) do
pull_spec && find && authorize && verify_gem_scope && verify_mfa_requirement && validate && save
pull_spec && find && authorize && verify_gem_scope && verify_not_archived && verify_mfa_requirement && validate && save
end
end

Expand All @@ -32,6 +32,12 @@ def verify_gem_scope
notify("This API key cannot perform the specified action on this gem.", 403)
end

def verify_not_archived
return true unless rubygem.archived?

notify("This gem has been archived, and is in a read-only state.", 401)
end

def verify_mfa_requirement
(!api_key.user? || owner.mfa_enabled?) || !(version_mfa_required? || rubygem.metadata_mfa_required?) ||
notify("Rubygem requires owners to enable MFA. You must enable MFA before pushing new version.", 403)
Expand Down
6 changes: 6 additions & 0 deletions test/factories/rubygem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

name

trait :archived do
archived_at { Time.current }
archived { true }
archived_by { 1 }
end

after(:build) do |rubygem, evaluator|
if evaluator.linkset
rubygem.linkset = evaluator.linkset
Expand Down
20 changes: 20 additions & 0 deletions test/models/pusher_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class PusherTest < ActiveSupport::TestCase
@cutter.stubs(:authorize).returns true
@cutter.stubs(:verify_mfa_requirement).returns true
@cutter.stubs(:verify_gem_scope).returns true
@cutter.stubs(:verify_not_archived).returns true
@cutter.stubs(:validate).returns true
@cutter.stubs(:save)

Expand Down Expand Up @@ -104,6 +105,7 @@ class PusherTest < ActiveSupport::TestCase
@cutter.stubs(:authorize).returns true
@cutter.stubs(:verify_gem_scope).returns true
@cutter.stubs(:verify_mfa_requirement).returns false
@cutter.stubs(:verify_not_archived).returns true
@cutter.stubs(:validate).never
@cutter.stubs(:save).never

Expand All @@ -116,6 +118,7 @@ class PusherTest < ActiveSupport::TestCase
@cutter.stubs(:authorize).returns true
@cutter.stubs(:verify_gem_scope).returns true
@cutter.stubs(:verify_mfa_requirement).returns true
@cutter.stubs(:verify_not_archived).returns true
@cutter.stubs(:validate).returns false
@cutter.stubs(:save).never

Expand Down Expand Up @@ -844,4 +847,21 @@ def two_cert_chain(signing_key:, root_not_before: Time.current, cert_not_before:
RubygemFs.mock!
end
end

context "the gem has been archived" do
setup do
@rubygem = create(:rubygem, :archived, name: "test")

Gem::Specification.any_instance.stubs(:authors).returns(["[email protected]"])

@gem = gem_file("test-1.0.0.gem")
@cutter = Pusher.new(@api_key, @gem)
end

should "not not process the gem" do
refute @cutter.process
assert_equal "This gem has been archived, and is in a read-only state.", @cutter.message
assert_equal 401, @cutter.code
end
end
end

0 comments on commit b41ec50

Please sign in to comment.