diff --git a/app/controllers/api/v1/deletions_controller.rb b/app/controllers/api/v1/deletions_controller.rb index b26ba803de2..79370afaff4 100644 --- a/app/controllers/api/v1/deletions_controller.rb +++ b/app/controllers/api/v1/deletions_controller.rb @@ -32,7 +32,7 @@ def validate_gem_and_version if !@rubygem.hosted? render plain: response_with_mfa_warning(t(:this_rubygem_could_not_be_found)), status: :not_found - elsif !@rubygem.owned_by?(@api_key.user) + elsif !can_delete_gem?(@api_key.user) render_forbidden response_with_mfa_warning("You do not have permission to delete this gem.") else begin @@ -45,4 +45,8 @@ def validate_gem_and_version end end end + + def can_delete_gem?(user) + GemPermissions.new(@rubygem, user).can_push? + end end diff --git a/app/models/gem_permissions.rb b/app/models/gem_permissions.rb new file mode 100644 index 00000000000..3969a3abb30 --- /dev/null +++ b/app/models/gem_permissions.rb @@ -0,0 +1,55 @@ +class GemPermissions + def initialize(rubygem, user) + @rubygem = rubygem + @user = user + end + + def can_push? + return false if user.blank? + + if rubygem.owned_by_organization? + org_member_in_role?(:maintainer) || user_in_role?(:maintainer) + else + user_in_role?(:maintainer) + end + end + + def can_manage_owners? + role_granted?(:owner) + end + + def can_perform_gem_admin? + role_granted?(:admin) + end + + private + + attr_reader :rubygem, :user + + def role_granted?(minimum_role) + return false if @user.blank? + + if rubygem.owned_by_organization? + org_member_in_role?(minimum_role) + else + user_in_role?(minimum_role) + end + end + + def org_member_in_role?(minimum_role) + case minimum_role + when :maintainer + rubygem.organization.user_is_member?(user) + when :admin + rubygem.organization.administered_by?(user) + when :owner + rubygem.organization.owned_by?(user) + else + false + end + end + + def user_in_role?(minimum_role) + rubygem.ownerships.user_with_minimum_role(user, minimum_role).exists? + end +end diff --git a/app/models/oidc/trusted_publisher/github_action.rb b/app/models/oidc/trusted_publisher/github_action.rb index f921c548a1d..9813a3459bc 100644 --- a/app/models/oidc/trusted_publisher/github_action.rb +++ b/app/models/oidc/trusted_publisher/github_action.rb @@ -147,7 +147,7 @@ def repository = "#{repository_owner}/#{repository_name}" def workflow_slug = ".github/workflows/#{workflow_filename}" - def owns_gem?(rubygem) = rubygem_trusted_publishers.exists?(rubygem: rubygem) + def can_push?(rubygem) = rubygem_trusted_publishers.exists?(rubygem: rubygem) private diff --git a/app/models/organization.rb b/app/models/organization.rb index 845d1768286..585bf502238 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -27,6 +27,14 @@ def user_is_member?(user) memberships.exists?(user: user) end + def owned_by?(user) + memberships.where(user: user).with_minimum_role(:owner).exists? + end + + def administered_by?(user) + memberships.where(user: user).with_minimum_role(:admin).exists? + end + def self.find_by_handle(handle) find_by("lower(handle) = lower(?)", handle) end diff --git a/app/models/pusher.rb b/app/models/pusher.rb index 66a25dabdba..1734d44d410 100644 --- a/app/models/pusher.rb +++ b/app/models/pusher.rb @@ -32,7 +32,7 @@ def process end def authorize - (rubygem.pushable? && (api_key.user? || find_pending_trusted_publisher)) || owner.owns_gem?(rubygem) || notify_unauthorized + (rubygem.pushable? && (api_key.user? || find_pending_trusted_publisher)) || owner.can_push?(rubygem) || notify_unauthorized end def verify_gem_scope @@ -266,7 +266,7 @@ def republish_notification(version) notify("It appears that #{version.full_name} did not finish pushing.\n" \ "Please contact support@rubygems.org for assistance if you pushed this gem more than a minute ago.", 409) else - different_owner = "pushed by a previous owner of this gem " unless owner.owns_gem?(version.rubygem) + different_owner = "pushed by a previous owner of this gem " unless owner.can_push?(version.rubygem) notify("A yanked version #{different_owner}already exists (#{version.full_name}).\n" \ "Repushing of gem versions is not allowed. Please use a new version and retry", 409) end diff --git a/app/models/rubygem.rb b/app/models/rubygem.rb index d654e1104bc..43d110edeb0 100644 --- a/app/models/rubygem.rb +++ b/app/models/rubygem.rb @@ -185,18 +185,6 @@ def indexed_versions? versions.indexed.any? end - def owned_by?(user) - return false unless user - ownerships.exists?(user_id: user.id) || (owned_by_organization? && user_authorized_for_organization?(user)) - end - - def owned_by_with_role?(user, minimum_required_role) - return false if user.blank? - ownerships.user_with_minimum_role(user, minimum_required_role).exists? - rescue KeyError - false - end - def unconfirmed_ownerships ownerships_including_unconfirmed.unconfirmed end diff --git a/app/models/rubygem_transfer.rb b/app/models/rubygem_transfer.rb index 549a2ec8c9d..1d69a1822ba 100644 --- a/app/models/rubygem_transfer.rb +++ b/app/models/rubygem_transfer.rb @@ -45,7 +45,12 @@ def approved_invites def available_rubygems return Rubygem.none if created_by.blank? - created_by.rubygems.where(organization_id: nil).order(:name) + created_by.rubygems + .joins(:ownerships) + .where(ownerships: { user: created_by, role: :owner }) + .where(organization_id: nil) + .distinct + .order(:name) end def selected_rubygems diff --git a/app/models/user.rb b/app/models/user.rb index ef68e58c6d8..a0710320289 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -275,8 +275,8 @@ def blocked? blocked_email.present? end - def owns_gem?(rubygem) - rubygem.owned_by?(self) + def can_push?(rubygem) + GemPermissions.new(rubygem, self).can_push? end def acknowledge_policies! diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index db9aa3e6f34..7d56a29c28f 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -35,18 +35,6 @@ def current_user?(record_user) user && user == record_user end - def rubygem_owned_by?(user) - rubygem.owned_by?(user) || - organization_member_with_role?(user, :maintainer) || - deny(t(:forbidden)) - end - - def rubygem_owned_by_with_role?(user, minimum_required_role:, minimum_required_org_role: :owner) - organization_member_with_role?(user, minimum_required_org_role) || - rubygem.owned_by_with_role?(user, minimum_required_role) || - deny(t(:forbidden)) - end - def organization_member_with_role?(user, minimum_role) return false unless respond_to?(:organization) && organization.present? organization.memberships.where(user: user).with_minimum_role(minimum_role).exists? diff --git a/app/policies/events/rubygem_event_policy.rb b/app/policies/events/rubygem_event_policy.rb index 3b6580ae817..df9d7bd3346 100644 --- a/app/policies/events/rubygem_event_policy.rb +++ b/app/policies/events/rubygem_event_policy.rb @@ -5,7 +5,7 @@ class Scope < ApplicationPolicy::Scope delegate :rubygem, to: :record def show? - rubygem.owned_by?(user) + GemPermissions.new(rubygem, user).can_push? end def create? diff --git a/app/policies/oidc/rubygem_trusted_publisher_policy.rb b/app/policies/oidc/rubygem_trusted_publisher_policy.rb index cbd7896e834..4cfa241df22 100644 --- a/app/policies/oidc/rubygem_trusted_publisher_policy.rb +++ b/app/policies/oidc/rubygem_trusted_publisher_policy.rb @@ -5,14 +5,20 @@ class Scope < ApplicationPolicy::Scope delegate :rubygem, to: :record def show? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner, minimum_required_org_role: :admin) + permissions.can_manage_owners? || deny end def create? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner, minimum_required_org_role: :admin) + permissions.can_manage_owners? || deny end def destroy? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner, minimum_required_org_role: :admin) + permissions.can_manage_owners? || deny + end + + private + + def permissions + GemPermissions.new(rubygem, user) end end diff --git a/app/policies/rubygem_policy.rb b/app/policies/rubygem_policy.rb index dee392dbc05..e46149ff691 100644 --- a/app/policies/rubygem_policy.rb +++ b/app/policies/rubygem_policy.rb @@ -13,34 +13,44 @@ def create? end def configure_oidc? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner, minimum_required_org_role: :admin) + gem_permissions.can_perform_gem_admin? || deny end def configure_trusted_publishers? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner, minimum_required_org_role: :admin) + gem_permissions.can_perform_gem_admin? || deny end def show_events? - rubygem_owned_by?(user) + gem_permissions.can_push? || deny + end + + def show_mfa_status? + gem_permissions.can_push? || deny end def show_unconfirmed_ownerships? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner, minimum_required_org_role: :admin) + gem_permissions.can_perform_gem_admin? || deny end def add_owner? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner) + gem_permissions.can_manage_owners? || deny end def update_owner? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner) + gem_permissions.can_manage_owners? || deny end def remove_owner? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner) + gem_permissions.can_manage_owners? || deny end def transfer_gem? - rubygem_owned_by_with_role?(user, minimum_required_role: :owner) + gem_permissions.can_manage_owners? || deny + end + + private + + def gem_permissions + GemPermissions.new(record, user) end end diff --git a/app/views/rubygems/_release_info.html.erb b/app/views/rubygems/_release_info.html.erb index 6841988f68a..2a2d3da9811 100644 --- a/app/views/rubygems/_release_info.html.erb +++ b/app/views/rubygems/_release_info.html.erb @@ -20,7 +20,7 @@ <%= links_to_owners(rubygem) %> - <% if rubygem.owned_by?(current_user) %> + <% if policy(rubygem).show_mfa_status? %> <% if rubygem.owners.without_mfa.present? %> <% if current_user.mfa_disabled? %> diff --git a/test/integration/push_test.rb b/test/integration/push_test.rb index 44aa5a9722f..dee5bacae51 100644 --- a/test/integration/push_test.rb +++ b/test/integration/push_test.rb @@ -189,7 +189,7 @@ class PushTest < ActionDispatch::IntegrationTest rubygem = Rubygem.find_by!(name: "sandworm") - assert rubygem.owned_by?(@user) + assert @user.can_push?(rubygem) assert rubygem.oidc_rubygem_trusted_publishers.exists?(trusted_publisher: pending_trusted_publisher.trusted_publisher) end @@ -213,7 +213,7 @@ class PushTest < ActionDispatch::IntegrationTest rubygem = Rubygem.find_by!(name: "sandworm") - assert rubygem.owned_by?(@user) + assert @user.can_push?(rubygem) assert rubygem.oidc_rubygem_trusted_publishers.exists?(trusted_publisher: pending_trusted_publisher.trusted_publisher) end diff --git a/test/models/gem_permissions_test.rb b/test/models/gem_permissions_test.rb new file mode 100644 index 00000000000..ea1502394d8 --- /dev/null +++ b/test/models/gem_permissions_test.rb @@ -0,0 +1,203 @@ +require "test_helper" + +class GemPermissionsTest < ActiveSupport::TestCase + setup do + @user = create(:user) + @other_user = create(:user) + end + + context "for organization-owned gems" do + setup do + @organization = create(:organization) + @rubygem = create(:rubygem, organization: @organization) + @permissions = GemPermissions.new(@rubygem, @user) + end + + context "#can_push?" do + should "return true when user is a member of the organization" do + create(:membership, organization: @organization, user: @user, role: :maintainer) + + assert_predicate @permissions, :can_push? + end + + should "return true when user is an admin of the organization" do + create(:membership, organization: @organization, user: @user, role: :admin) + + assert_predicate @permissions, :can_push? + end + + should "return true when user is an owner of the organization" do + create(:membership, organization: @organization, user: @user, role: :owner) + + assert_predicate @permissions, :can_push? + end + + should "return false when user is not a member of the organization" do + refute_predicate @permissions, :can_push? + end + + should "return false when user has unconfirmed membership" do + create(:membership, organization: @organization, user: @user, role: :maintainer, confirmed_at: nil) + + refute_predicate @permissions, :can_push? + end + + should "return false when user is nil" do + permissions = GemPermissions.new(@rubygem, nil) + + refute_predicate permissions, :can_push? + end + end + + context "#can_perform_gem_admin?" do + should "return false when user is a maintainer of the organization" do + create(:membership, organization: @organization, user: @user, role: :maintainer) + + refute_predicate @permissions, :can_perform_gem_admin? + end + + should "return true when user is an admin of the organization" do + create(:membership, organization: @organization, user: @user, role: :admin) + + assert_predicate @permissions, :can_perform_gem_admin? + end + + should "return true when user is an owner of the organization" do + create(:membership, organization: @organization, user: @user, role: :owner) + + assert_predicate @permissions, :can_perform_gem_admin? + end + + should "return false when user is not a member of the organization" do + refute_predicate @permissions, :can_perform_gem_admin? + end + + should "return false when user has unconfirmed admin membership" do + create(:membership, organization: @organization, user: @user, role: :admin, confirmed_at: nil) + + refute_predicate @permissions, :can_perform_gem_admin? + end + + should "return false when user is nil" do + permissions = GemPermissions.new(@rubygem, nil) + + refute_predicate permissions, :can_perform_gem_admin? + end + end + + context "#can_manage_owners?" do + should "return false when user is a maintainer of the organization" do + create(:membership, organization: @organization, user: @user, role: :maintainer) + + refute_predicate @permissions, :can_manage_owners? + end + + should "return false when user is an admin of the organization" do + create(:membership, organization: @organization, user: @user, role: :admin) + + refute_predicate @permissions, :can_manage_owners? + end + + should "return true when user is an owner of the organization" do + create(:membership, organization: @organization, user: @user, role: :owner) + + assert_predicate @permissions, :can_manage_owners? + end + + should "return false when user is not a member of the organization" do + refute_predicate @permissions, :can_manage_owners? + end + + should "return false when user has unconfirmed owner membership" do + create(:membership, organization: @organization, user: @user, role: :owner, confirmed_at: nil) + + refute_predicate @permissions, :can_manage_owners? + end + + should "return false when user is nil" do + permissions = GemPermissions.new(@rubygem, nil) + + refute_predicate permissions, :can_manage_owners? + end + end + end + + context "for individually-owned gems" do + setup do + @rubygem = create(:rubygem) + @permissions = GemPermissions.new(@rubygem, @user) + end + + context "#can_push?" do + should "return true when user has maintainer ownership" do + create(:ownership, user: @user, rubygem: @rubygem, role: :maintainer) + + assert_predicate @permissions, :can_push? + end + + should "return true when user has owner ownership" do + create(:ownership, user: @user, rubygem: @rubygem, role: :owner) + + assert_predicate @permissions, :can_push? + end + + should "return false when user has no ownership" do + refute_predicate @permissions, :can_push? + end + + should "return false when user is nil" do + permissions = GemPermissions.new(@rubygem, nil) + + refute_predicate permissions, :can_push? + end + end + + context "#can_perform_gem_admin?" do + should "return false when user has maintainer ownership" do + create(:ownership, user: @user, rubygem: @rubygem, role: :maintainer) + + refute_predicate @permissions, :can_perform_gem_admin? + end + + should "return true when user has owner ownership" do + create(:ownership, user: @user, rubygem: @rubygem, role: :owner) + + assert_predicate @permissions, :can_perform_gem_admin? + end + + should "return false when user has no ownership" do + refute_predicate @permissions, :can_perform_gem_admin? + end + + should "return false when user is nil" do + permissions = GemPermissions.new(@rubygem, nil) + + refute_predicate permissions, :can_perform_gem_admin? + end + end + + context "#can_manage_owners?" do + should "return false when user has maintainer ownership" do + create(:ownership, user: @user, rubygem: @rubygem, role: :maintainer) + + refute_predicate @permissions, :can_manage_owners? + end + + should "return true when user has owner ownership" do + create(:ownership, user: @user, rubygem: @rubygem, role: :owner) + + assert_predicate @permissions, :can_manage_owners? + end + + should "return false when user has no ownership" do + refute_predicate @permissions, :can_manage_owners? + end + + should "return false when user is nil" do + permissions = GemPermissions.new(@rubygem, nil) + + refute_predicate permissions, :can_manage_owners? + end + end + end +end diff --git a/test/models/oidc/trusted_publisher/github_action_test.rb b/test/models/oidc/trusted_publisher/github_action_test.rb index f9bbca5d9b8..6d975310ba1 100644 --- a/test/models/oidc/trusted_publisher/github_action_test.rb +++ b/test/models/oidc/trusted_publisher/github_action_test.rb @@ -111,15 +111,15 @@ class OIDC::TrustedPublisher::GitHubActionTest < ActiveSupport::TestCase assert_equal "GitHub Actions example/bar @ .github/workflows/push_gem.yml (test)", publisher.name end - test "#owns_gem?" do + test "#can_push?" do rubygem1 = create(:rubygem) rubygem2 = create(:rubygem) publisher = create(:oidc_trusted_publisher_github_action) create(:oidc_rubygem_trusted_publisher, trusted_publisher: publisher, rubygem: rubygem1) - assert publisher.owns_gem?(rubygem1) - refute publisher.owns_gem?(rubygem2) + assert publisher.can_push?(rubygem1) + refute publisher.can_push?(rubygem2) end test "#to_access_policy" do diff --git a/test/models/organization_test.rb b/test/models/organization_test.rb index 968b94db575..1d645dfcab7 100644 --- a/test/models/organization_test.rb +++ b/test/models/organization_test.rb @@ -86,4 +86,86 @@ class OrganizationTest < ActiveSupport::TestCase assert_equal "org:#{organization.handle}", organization.flipper_id end end + + context "#owned_by?" do + should "return true when user is an owner" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :owner) + + assert organization.owned_by?(user) + end + + should "return false when user is an admin" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :admin) + + refute organization.owned_by?(user) + end + + should "return false when user is a maintainer" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :maintainer) + + refute organization.owned_by?(user) + end + + should "return false when user is not a member" do + organization = create(:organization) + user = create(:user) + + refute organization.owned_by?(user) + end + + should "return false when user has unconfirmed owner membership" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :owner, confirmed_at: nil) + + refute organization.owned_by?(user) + end + end + + context "#administered_by?" do + should "return true when user is an owner" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :owner) + + assert organization.administered_by?(user) + end + + should "return true when user is an admin" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :admin) + + assert organization.administered_by?(user) + end + + should "return false when user is a maintainer" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :maintainer) + + refute organization.administered_by?(user) + end + + should "return false when user is not a member" do + organization = create(:organization) + user = create(:user) + + refute organization.administered_by?(user) + end + + should "return false when user has unconfirmed admin membership" do + organization = create(:organization) + user = create(:user) + create(:membership, organization: organization, user: user, role: :admin, confirmed_at: nil) + + refute organization.administered_by?(user) + end + end end diff --git a/test/models/pusher_test.rb b/test/models/pusher_test.rb index d89e50ffb59..b8b85edaae6 100644 --- a/test/models/pusher_test.rb +++ b/test/models/pusher_test.rb @@ -504,7 +504,7 @@ def two_cert_chain(signing_key:, root_not_before: Time.current, cert_not_before: owner = stub("owner", to_gid: nil) @api_key.update_columns(owner_id: 0, owner_type: "stub") @cutter.stubs(:owner).returns owner - owner.expects(:owns_gem?).with(@cutter.rubygem).returns(false) + owner.expects(:can_push?).with(@cutter.rubygem).returns(false) refute @cutter.authorize assert_equal "You are not allowed to push this gem.", @@ -541,7 +541,7 @@ def two_cert_chain(signing_key:, root_not_before: Time.current, cert_not_before: owner = stub("owner", to_gid: nil) @api_key.update_columns(owner_id: 0, owner_type: "stub") @cutter.stubs(:owner).returns owner - owner.expects(:owns_gem?).with(@rubygem).returns(false) + owner.expects(:can_push?).with(@rubygem).returns(false) refute @cutter.authorize assert_equal "You are not allowed to push this gem.", diff --git a/test/models/rubygem_test.rb b/test/models/rubygem_test.rb index 152f3f591ef..217acd9fee2 100644 --- a/test/models/rubygem_test.rb +++ b/test/models/rubygem_test.rb @@ -410,51 +410,6 @@ class RubygemTest < ActiveSupport::TestCase end end - context "with a user" do - setup do - @rubygem.save - @user = create(:user) - end - - should "be owned by a user in ownership" do - create(:ownership, user: @user, rubygem: @rubygem) - - assert @rubygem.owned_by?(@user) - refute_predicate @rubygem, :unowned? - end - - should "be not owned if no ownerships" do - assert_empty @rubygem.ownerships - refute @rubygem.owned_by?(@user) - assert_predicate @rubygem, :unowned? - end - - should "be not owned if no user" do - refute @rubygem.owned_by?(nil) - assert_predicate @rubygem, :unowned? - end - end - - context "with a user that belongs to an organization" do - setup do - @owner = create(:user) - @admin = create(:user) - @maintainer = create(:user) - @guest = create(:user) - - @organization = create(:organization, admins: [@admin], owners: [@owner], maintainers: [@maintainer], rubygems: [@rubygem]) - end - - should "be owned by organization user" do - assert @rubygem.owned_by?(@owner) - assert @rubygem.owned_by?(@admin) - assert @rubygem.owned_by?(@maintainer) - refute @rubygem.owned_by?(@guest) - - refute_predicate @rubygem, :unowned? - end - end - context "with subscribed users" do setup do @subscribed_user = create(:user) @@ -665,8 +620,8 @@ class RubygemTest < ActiveSupport::TestCase @rubygem_with_version.versions.first.update! indexed: false end - should "still be owned" do - assert @rubygem_with_version.owned_by?(@owner) + should "still have ownerships" do + assert_predicate @rubygem_with_version.ownerships.where(user: @owner), :exists? end should "no longer be indexed" do @@ -1182,63 +1137,4 @@ class RubygemTest < ActiveSupport::TestCase refute_predicate @version_three, :yanked? end end - - context "#owned_by_with_role?" do - setup do - @rubygem = create(:rubygem) - @owner = create(:user) - end - - context "when the user is not an owner of a gem" do - should "return false" do - refute @rubygem.owned_by_with_role?(@owner, :maintainer) - end - end - - context "when the user is an owner of a gem" do - setup do - @ownership = create(:ownership, user: @owner, rubygem: @rubygem) - end - - should "return true" do - assert @rubygem.owned_by_with_role?(@owner, :maintainer) - end - end - - context "when the role is less than the given value" do - setup do - @ownership = create(:ownership, user: @owner, rubygem: @rubygem, role: :maintainer) - end - - should "return false" do - refute @rubygem.owned_by_with_role?(@owner, :owner) - end - end - - context "when the role is more than the given value" do - setup do - @ownership = create(:ownership, user: @owner, rubygem: @rubygem, role: :owner) - end - - should "return true" do - assert @rubygem.owned_by_with_role?(@owner, :maintainer) - end - end - - context "when the role is equal to the given role" do - setup do - @ownership = create(:ownership, user: @owner, rubygem: @rubygem, role: :owner) - end - - should "return true" do - assert @rubygem.owned_by_with_role?(@owner, :owner) - end - end - - context "when the given role does not exist" do - should "not raise an argument" do - refute @rubygem.owned_by_with_role?(@owner, :nonexistent_role) - end - end - end end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index cbd6ac2796d..85e92f924e2 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -1028,4 +1028,23 @@ class UserTest < ActiveSupport::TestCase refute_predicate user, :policies_acknowledged? end end + + context "#can_push?" do + should "delegate to GemPermissions#can_push?" do + user = build(:user) + rubygem = build(:rubygem) + + gem_permissions = mock + gem_permissions.expects(:can_push?).returns(true) + GemPermissions.expects(:new).with(rubygem, user).returns(gem_permissions) + + assert user.can_push?(rubygem) + + gem_permissions = mock + gem_permissions.expects(:can_push?).returns(false) + GemPermissions.expects(:new).with(rubygem, user).returns(gem_permissions) + + refute user.can_push?(rubygem) + end + end end diff --git a/test/policies/rubygem_policy_test.rb b/test/policies/rubygem_policy_test.rb index e22f34fa4d7..eba97a1d9f3 100644 --- a/test/policies/rubygem_policy_test.rb +++ b/test/policies/rubygem_policy_test.rb @@ -48,12 +48,12 @@ def org_policy!(user) refute_authorized policy!(nil), :configure_oidc? end - should "only allow owners, org owners and admins" do + should "only allow org owners and admins when owned by an org" do assert_authorized org_policy!(@org_owner), :configure_oidc? assert_authorized org_policy!(@org_admin), :configure_oidc? - assert_authorized org_policy!(@owner), :configure_oidc? refute_authorized org_policy!(@org_maintainer), :configure_oidc? + refute_authorized org_policy!(@owner), :configure_oidc? refute_authorized org_policy!(@user), :configure_oidc? refute_authorized org_policy!(nil), :configure_oidc? end @@ -67,7 +67,7 @@ def org_policy!(user) refute_authorized policy!(nil), :show_events? end - should "only allow anyone with access to the gem" do + should "allow anyone with access to the gem when owned by an org" do assert_authorized org_policy!(@org_owner), :show_events? assert_authorized org_policy!(@org_admin), :show_events? assert_authorized org_policy!(@org_maintainer), :show_events? @@ -79,6 +79,25 @@ def org_policy!(user) end end + context "#show_mfa_status?" do + should "only allow the owner and maintainer" do + assert_authorized policy!(@owner), :show_mfa_status? + assert_authorized policy!(@maintainer), :show_mfa_status? + refute_authorized policy!(@user), :show_mfa_status? + refute_authorized policy!(nil), :show_mfa_status? + end + + should "allow anyone with access to the gem when owned by an org" do + assert_authorized org_policy!(@org_owner), :show_mfa_status? + assert_authorized org_policy!(@org_admin), :show_mfa_status? + assert_authorized org_policy!(@org_maintainer), :show_mfa_status? + assert_authorized org_policy!(@owner), :show_mfa_status? + assert_authorized org_policy!(@maintainer), :show_mfa_status? + + refute_authorized org_policy!(@user), :show_mfa_status? + refute_authorized org_policy!(nil), :show_mfa_status? + end + end context "#configure_trusted_publishers?" do should "only allow the owner" do assert_authorized policy!(@owner), :configure_trusted_publishers? @@ -87,12 +106,12 @@ def org_policy!(user) refute_authorized policy!(nil), :configure_trusted_publishers? end - should "only allow owners, org owners and admins" do + should "only allow org owners and admins when gem is owned by an org" do assert_authorized org_policy!(@org_owner), :configure_trusted_publishers? assert_authorized org_policy!(@org_admin), :configure_trusted_publishers? - assert_authorized org_policy!(@owner), :configure_trusted_publishers? refute_authorized org_policy!(@org_maintainer), :configure_trusted_publishers? + refute_authorized org_policy!(@owner), :configure_trusted_publishers? refute_authorized org_policy!(@maintainer), :configure_trusted_publishers? refute_authorized org_policy!(@user), :configure_trusted_publishers? refute_authorized org_policy!(nil), :configure_trusted_publishers? @@ -107,12 +126,12 @@ def org_policy!(user) refute_authorized policy!(nil), :show_unconfirmed_ownerships? end - should "only allow owners, org owners and admins" do + should "only allow org owners and admins when gem is owned by an org" do assert_authorized org_policy!(@org_owner), :show_unconfirmed_ownerships? assert_authorized org_policy!(@org_admin), :show_unconfirmed_ownerships? - assert_authorized org_policy!(@owner), :show_unconfirmed_ownerships? refute_authorized org_policy!(@org_maintainer), :show_unconfirmed_ownerships? + refute_authorized org_policy!(@owner), :show_unconfirmed_ownerships? refute_authorized org_policy!(@user), :show_unconfirmed_ownerships? refute_authorized org_policy!(nil), :show_unconfirmed_ownerships? end diff --git a/test/system/rubygem_transfer_test.rb b/test/system/rubygem_transfer_test.rb index 21a3c3dde3f..119b8a0a34f 100644 --- a/test/system/rubygem_transfer_test.rb +++ b/test/system/rubygem_transfer_test.rb @@ -19,6 +19,20 @@ def setup assert_no_link "Transfer" end + test "maintainers see no transferable gems" do + maintainer = create(:user) + create(:ownership, rubygem: @rubygem, user: maintainer, role: :maintainer) + maintainer_org = create(:organization, owners: [maintainer]) + + sign_in maintainer + visit organization_transfer_rubygems_path + + select maintainer_org.name, from: "Organization" + click_on "Continue" + + assert_text "Gems 0" # No gems available to transfer + end + test "transfer a rubygem to an organization" do sign_in @owner