class RubygemsCheckReplacementVulnerability::CLI

Public Instance Methods

compare_file?(unpacked_file, repo_file) click to toggle source
# File lib/rubygems_check_replacement_vulnerability/cli.rb, line 124
def compare_file?(unpacked_file, repo_file)
  unless repo_file.exist?
    puts "Not found #{unpacked_file} in repository"
    return false
  end

  unless unpacked_file.size == repo_file.size
    puts "Expect #{unpacked_file} is #{unpacked_file.size} bytes, but actual #{repo_file.size} bytes!"
    return false
  end

  unless unpacked_file.read == repo_file.read
    puts "#{unpacked_file} is not match between gem file and repository!"
    return false
  end

  true
end
failure_exit() click to toggle source
# File lib/rubygems_check_replacement_vulnerability/cli.rb, line 143
def failure_exit
  exit(1)
end
verify?(repository:, rubygems:, version:, prefix:) click to toggle source

@param repository [RubygemsCheckReplacementVulnerability::Repository] @param rubygems [RubygemsCheckReplacementVulnerability::Rubygems] @param version [String] @param prefix [String]

# File lib/rubygems_check_replacement_vulnerability/cli.rb, line 102
def verify?(repository:, rubygems:, version:, prefix:)
  safe = true

  Dir.mktmpdir("gem-") do |gem_dir|
    gem_path = rubygems.download_gem(version, gem_dir)
    gem_basename = File.basename(gem_path, ".gem")

    run_command("gem unpack #{gem_path} --target=#{gem_dir} --quiet")

    Dir.chdir(File.join(gem_dir, gem_basename)) do
      unpacked_file = Pathname.glob("**/**").select(&:file?)
      unpacked_file.each do |unpacked_file|
        repo_file = repository.find_file(unpacked_file, prefix)
        result = compare_file?(unpacked_file, repo_file)
        safe = result unless result
      end
    end
  end

  safe
end
verify_gem() click to toggle source
# File lib/rubygems_check_replacement_vulnerability/cli.rb, line 58
def verify_gem
  rubygems = Rubygems.new(options[:name])

  versions =
    if options[:version]
      Array(options[:version])
    else
      rubygems.vulnerable_versions
    end

  unsafe_count = 0
  Dir.mktmpdir("repo-") do |work_dir|
    repository = Repository.new(options[:repo_url], work_dir)
    repository.git_clone

    versions.each do |version|
      git_tag = repository.find_version_tag(version)

      unless git_tag
        puts "[Warn] Not found version tag #{version} in repository"
        next
      end

      repository.checkout(git_tag)

      safe = verify?(repository: repository, rubygems: rubygems, version: version, prefix: options[:prefix])

      if safe
        puts "[Info] #{rubygems.gem_name} #{version} is safe!"
      else
        puts "[Warn] #{rubygems.gem_name} #{version} is not safe!"
        unsafe_count += 1
      end
    end
  end

  failure_exit if unsafe_count > 0
end
version() click to toggle source
# File lib/rubygems_check_replacement_vulnerability/cli.rb, line 13
def version
  puts RubygemsCheckReplacementVulnerability::VERSION
end
vulnerable_gems() click to toggle source
# File lib/rubygems_check_replacement_vulnerability/cli.rb, line 20
def vulnerable_gems
  gems = Rubygems.owner_gems(options[:username]).select { |gem| gem.include?("-") }.sort

  vulnerable_gems =
    gems.each_with_object({}) do |gem, result|
      rubygems = Rubygems.new(gem)
      versions = rubygems.vulnerable_versions
      result[gem] = versions unless versions.empty?
    end

  case options[:format]
  when "plain"
    puts "#{options[:username]}'s vulnerable gems"

    if vulnerable_gems.empty?
      puts "Nothing!"
    else
      vulnerable_gems.each do |gem, versions|
        puts "- #{gem} : #{versions.join(", ")}"
      end
    end

  when "yaml"
    puts YAML.dump(vulnerable_gems)

  when "json"
    puts JSON.dump(vulnerable_gems)

  else
    raise "Unknown format: #{options[:format]}"
  end
end