lib/bundler/plumber/scanner.rb
#
# Copyright (c) 2019 Ombulabs (hello at ombulabs.com)
# Copyright (c) 2013-2016 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# bundler-leak is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# bundler-leak is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with bundler-leak. If not, see <http://www.gnu.org/licenses/>.
#
require 'bundler'
require 'bundler/plumber/database'
require 'bundler/lockfile_parser'
require 'ipaddr'
require 'resolv'
require 'set'
require 'uri'
module Bundler
module Plumber
class Scanner
# Represents a gem that is covered by an Advisory
UnpatchedGem = Struct.new(:gem, :advisory)
# The advisory database
#
# @return [Database]
attr_reader :database
# Project root directory
attr_reader :root
# The parsed `Gemfile.lock` from the project
#
# @return [Bundler::LockfileParser]
attr_reader :lockfile
#
# Initializes a scanner.
#
# @param [String] root
# The path to the project root.
#
# @param [String] gemfile_lock
# Alternative name for the `Gemfile.lock` file.
#
def initialize(root=Dir.pwd,gemfile_lock='Gemfile.lock')
@root = File.expand_path(root)
@database = Database.new
@lockfile = LockfileParser.new(
File.read(File.join(@root,gemfile_lock))
)
end
#
# Scans the project for issues.
#
# @param [Hash] options
# Additional options.
#
# @option options [Array<String>] :ignore
# The advisories to ignore.
#
# @yield [result]
# The given block will be passed the results of the scan.
#
# @return [Enumerator]
# If no block is given, an Enumerator will be returned.
#
def scan(options={},&block)
return enum_for(__method__, options) unless block
scan_specs(options, &block)
return self
end
#
# Scans the gem sources in the lockfile.
#
# @param [Hash] options
# Additional options.
#
# @option options [Array<String>] :ignore
# The advisories to ignore.
#
# @yield [result]
# The given block will be passed the results of the scan.
#
# @yieldparam [UnpatchedGem] result
# A result from the scan.
#
# @return [Enumerator]
# If no block is given, an Enumerator will be returned.
#
# @api semipublic
#
# @since 0.4.0
#
def scan_specs(options={})
return enum_for(__method__, options) unless block_given?
ignore = Set[]
ignore += options[:ignore] if options[:ignore]
@lockfile.specs.each do |gem|
@database.check_gem(gem) do |advisory|
gem_and_id = "#{advisory.gem}-#{advisory.id}"
yield UnpatchedGem.new(gem,advisory) unless ignore.include?(gem_and_id)
end
end
end
end
end
end