class RuboCop::Cop::Gemspec::RequireMFA

Requires a gemspec to have ‘rubygems_mfa_required` metadata set.

This setting tells RubyGems that MFA (Multi-Factor Authentication) is required for accounts to be able perform privileged operations, such as (see RubyGems’ documentation for the full list of privileged operations):

This helps make your gem more secure, as users can be more confident that gem updates were pushed by maintainers.

@example

# bad
Gem::Specification.new do |spec|
  # no `rubygems_mfa_required` metadata specified
end

# good
Gem::Specification.new do |spec|
  spec.metadata = {
    'rubygems_mfa_required' => 'true'
  }
end

# good
Gem::Specification.new do |spec|
  spec.metadata['rubygems_mfa_required'] = 'true'
end

# bad
Gem::Specification.new do |spec|
  spec.metadata = {
    'rubygems_mfa_required' => 'false'
  }
end

# good
Gem::Specification.new do |spec|
  spec.metadata = {
    'rubygems_mfa_required' => 'true'
  }
end

# bad
Gem::Specification.new do |spec|
  spec.metadata['rubygems_mfa_required'] = 'false'
end

# good
Gem::Specification.new do |spec|
  spec.metadata['rubygems_mfa_required'] = 'true'
end

Constants

MSG

Public Instance Methods

on_block(node) click to toggle source
# File lib/rubocop/cop/gemspec/require_mfa.rb, line 87
def on_block(node) # rubocop:disable Metrics/MethodLength, InternalAffairs/NumblockHandler
  gem_specification(node) do |block_var|
    metadata_value = metadata(node)
    mfa_value = mfa_value(metadata_value)

    if mfa_value
      unless true_string?(mfa_value)
        add_offense(mfa_value) do |corrector|
          change_value(corrector, mfa_value)
        end
      end
    else
      add_offense(node) do |corrector|
        autocorrect(corrector, node, block_var, metadata_value)
      end
    end
  end
end

Private Instance Methods

autocorrect(corrector, node, block_var, metadata) click to toggle source
# File lib/rubocop/cop/gemspec/require_mfa.rb, line 115
def autocorrect(corrector, node, block_var, metadata)
  if metadata
    return unless metadata.hash_type?

    correct_metadata(corrector, metadata)
  else
    insert_mfa_required(corrector, node, block_var)
  end
end
change_value(corrector, value) click to toggle source
# File lib/rubocop/cop/gemspec/require_mfa.rb, line 139
def change_value(corrector, value)
  corrector.replace(value, "'true'")
end
correct_metadata(corrector, metadata) click to toggle source
# File lib/rubocop/cop/gemspec/require_mfa.rb, line 125
def correct_metadata(corrector, metadata)
  if metadata.pairs.any?
    corrector.insert_after(metadata.pairs.last, ",\n'rubygems_mfa_required' => 'true'")
  else
    corrector.insert_before(metadata.loc.end, "'rubygems_mfa_required' => 'true'")
  end
end
insert_mfa_required(corrector, node, block_var) click to toggle source
# File lib/rubocop/cop/gemspec/require_mfa.rb, line 133
        def insert_mfa_required(corrector, node, block_var)
          corrector.insert_before(node.loc.end, <<~RUBY)
            #{block_var}.metadata['rubygems_mfa_required'] = 'true'
          RUBY
        end
mfa_value(metadata_value) click to toggle source
# File lib/rubocop/cop/gemspec/require_mfa.rb, line 108
def mfa_value(metadata_value)
  return unless metadata_value
  return metadata_value if metadata_value.str_type?

  rubygems_mfa_required(metadata_value).first
end