class Bundler::Audit::Scanner

Constants

INTERNAL_SUBNETS

List of internal IP address ranges.

@see tools.ietf.org/html/rfc1918#section-3 @see tools.ietf.org/html/rfc4193#section-8

InsecureSource

Represents a plain-text source

UnpatchedGem

Represents a gem that is covered by an Advisory

Attributes

database[R]

The advisory database

@return [Database]

lockfile[R]

The parsed `Gemfile.lock` from the project

@return [Bundler::LockfileParser]

root[R]

Project root directory

Public Class Methods

new(root=Dir.pwd,gemfile_lock='Gemfile.lock') click to toggle source

Initializes a scanner.

@param [String] root

The path to the project root.

@param [String] gemfile_lock

Alternative name for the `Gemfile.lock` file.
# File lib/bundler/audit/scanner.rb, line 42
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

Public Instance Methods

scan(options={},&block) click to toggle source

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.

@yieldparam [InsecureSource, UnpatchedGem] result

A result from the scan.

@return [Enumerator]

If no block is given, an Enumerator will be returned.
# File lib/bundler/audit/scanner.rb, line 68
def scan(options={},&block)
  return enum_for(__method__,options) unless block

  ignore = Set[]
  ignore += options[:ignore] if options[:ignore]

  scan_sources(options,&block)
  scan_specs(options,&block)

  return self
end
scan_sources(options={}) { |insecure_source| ... } click to toggle source

Scans the gem sources in the lockfile.

@param [Hash] options

Additional options.

@yield [result]

The given block will be passed the results of the scan.

@yieldparam [InsecureSource] result

A result from the scan.

@return [Enumerator]

If no block is given, an Enumerator will be returned.

@api semipublic

@since 0.4.0

# File lib/bundler/audit/scanner.rb, line 99
def scan_sources(options={})
  return enum_for(__method__,options) unless block_given?

  @lockfile.sources.map do |source|
    case source
    when Source::Git
      case source.uri
      when /^git:/, /^http:/
        unless internal_source?(source.uri)
          yield InsecureSource.new(source.uri)
        end
      end
    when Source::Rubygems
      source.remotes.each do |uri|
        if (uri.scheme == 'http' && !internal_source?(uri))
          yield InsecureSource.new(uri.to_s)
        end
      end
    end
  end
end
scan_specs(options={}) { |unpatched_gem| ... } click to toggle source

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

# File lib/bundler/audit/scanner.rb, line 143
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|
      is_ignored = ignore.intersect?(advisory.identifiers.to_set)
      next if is_ignored

      yield UnpatchedGem.new(gem,advisory)
    end
  end
end

Private Instance Methods

internal_host?(host) click to toggle source

Determines whether a host is internal.

@param [String] host

The hostname.

@return [Boolean]

# File lib/bundler/audit/scanner.rb, line 183
def internal_host?(host)
  Resolv.getaddresses(host).all? { |ip| internal_ip?(ip) }
rescue URI::Error
  false
end
internal_ip?(ip) click to toggle source

Determines whether an IP is internal.

@param [String] ip

The IPv4/IPv6 address.

@return [Boolean]

# File lib/bundler/audit/scanner.rb, line 208
def internal_ip?(ip)
  INTERNAL_SUBNETS.any? { |subnet| subnet.include?(ip) }
end
internal_source?(uri) click to toggle source

Determines whether a source is internal.

@param [URI, String] uri

The URI.

@return [Boolean]

# File lib/bundler/audit/scanner.rb, line 169
def internal_source?(uri)
  uri = URI(uri)

  internal_host?(uri.host) if uri.host
end