class DependencySpy::API

Public Class Methods

check(options) click to toggle source
# File lib/dependency_spy.rb, line 31
def self.check(options)
  verbose = options[:verbose]
  path = options[:path] || Dir.pwd
  files = options[:files]
  platform = options[:platform]
  database_path = options[:database_path] || YAVDB::Constants::DEFAULT_YAVDB_DATABASE_PATH
  offline = options[:offline] || false
  ignore = options[:ignore] || []

  if !File.exist?(database_path) && offline
    puts 'No local database found. Cannot obtain database since offline mode is enabled.'
    exit(10)
  elsif !offline
    puts 'Going to update the local vulnerability database.' if verbose
    YAVDB::API.download_database(false, YAVDB::Constants::DEFAULT_YAVDB_PATH)
  end

  path             = File.expand_path(path)
  package_managers = find_platform(platform)
  file_list        = if !files.nil?
                       files.split(',').map { |f| "#{path}/#{f}" }
                     elsif File.file?(path)
                       path = File.dirname(path)
                       [File.basename(path)]
                     else
                       Bibliothecary.load_file_info_list(path).map(&:full_path)
                     end
  manifests        = package_managers.map { |pm| pm.analyse(path, file_list) }.flatten.compact
  manifests.map do |manifest|
    package_manager   = manifest[:platform]
    manifest_filename = manifest[:path]
    manifest_kind     = manifest[:kind]

    dependency_vulns = manifest[:dependencies].map do |dependency|
      package_name = dependency[:name] || dependency['name']
      version      = dependency[:requirement] || dependency['version']
      type         = dependency[:type] || dependency['type']

      package_vulns = vulns(manifest[:platform], package_name, database_path)

      vulnerabilities = package_vulns.select do |vuln|
        vulnerable = vuln.vulnerable_versions ? vuln.vulnerable_versions.any? { |vv| DependencySpy::SemVer.intersects(vv, version) } : false
        unaffected = vuln.unaffected_versions ? vuln.unaffected_versions.any? { |vu| DependencySpy::SemVer.intersects(vu, version) } : false
        patched    = vuln.patched_versions ? vuln.patched_versions.any? { |vp| DependencySpy::SemVer.intersects(vp, version) } : false
        ignored    = ignore.include?(vuln.id)

        if unaffected || patched
          false
        elsif ignored
          puts "Skipping ignored vulnerability with #{vuln.id}." if verbose
          false
        else
          vulnerable
        end
      end

      Dependency.new(package_name, version, type, vulnerabilities.uniq)
    end

    Manifest.new(package_manager, manifest_filename, manifest_kind, dependency_vulns.uniq)
  end
end
update(vuln_repo_path = YAVDB::Constants::DEFAULT_YAVDB_PATH) click to toggle source
# File lib/dependency_spy.rb, line 94
def self.update(vuln_repo_path = YAVDB::Constants::DEFAULT_YAVDB_PATH)
  YAVDB::API.download_database(true, vuln_repo_path)
end

Private Class Methods

find_platform(platform) click to toggle source
# File lib/dependency_spy.rb, line 106
def find_platform(platform)
  if platform.nil?
    Bibliothecary.package_managers
  else
    Bibliothecary::Parsers.constants
      .select { |c| c.to_s.downcase.include?(platform) }
      .map { |c| Bibliothecary::Parsers.const_get(c) }
      .sort_by { |c| c.to_s.downcase }
  end
end
vulns(package_manager, package_name, vuln_database_path) click to toggle source
# File lib/dependency_spy.rb, line 102
def vulns(package_manager, package_name, vuln_database_path)
  YAVDB::API.list_vulnerabilities(package_manager, package_name, vuln_database_path)
end