require ‘open-uri’ require ‘zip’ require ‘yaml’ require ‘bundler’ require ‘rubygems’

DATABASE_FILE = ‘github.com/rubysec/ruby-advisory-db/archive/master.zip’ TEMP_DIR = ‘tmp/check_advisory_db’ TEMP_FILE = “#{TEMP_DIR}/master.zip”

namespace :advisory_db do

desc 'Check the Gems for advisories.'
task :check => :environment do
  global_result = true

  # Download the database
  FileUtils::mkdir_p TEMP_DIR
  File.open(TEMP_FILE, 'wb') do |file|
    file.write open(DATABASE_FILE).read
  end

  # Extract all the advisory YAML files for each Gem
  Zip::File.open("#{TEMP_DIR}/master.zip") do |zipfile|
    zipfile.each do |file|
      if /^ruby-advisory-db-master\/gems\/.*\.yml$/ =~ file.name
        file_path = "#{TEMP_DIR}/#{file.name.gsub(/ruby-advisory-db-master\/gems\//, '')}"
        FileUtils.mkdir_p File.dirname(file_path)
        zipfile.extract(file, file_path)
      end
    end
  end
  FileUtils.remove(TEMP_FILE)

  # Check all Gem versions for advisories and output them
  Bundler.load.specs.each do |spec|
    spec_dir = "#{TEMP_DIR}/#{spec.name}"

    if File.directory?(spec_dir)
      Dir["#{spec_dir}/*.yml"].each do |advisory_file|
        result        = false
        good_versions = []
        advisory      =  YAML.load_file(advisory_file)
        advisory['unaffected_versions'].each {|i| good_versions << i} if advisory['unaffected_versions']
        advisory['patched_versions'].each    {|i| good_versions << i} if advisory['patched_versions']

        good_versions.each do |version|
          result |= Gem::Dependency.new('', version).match?('', spec.version) rescue result |= false
        end

        unless result
          global_result = false

          puts '------------------------------------------------------------------------'
          puts "#{spec.name} - #{advisory['title']}"
          puts "See: #{advisory['url']}"
          puts ''
          puts advisory['description']
          puts '------------------------------------------------------------------------'
          puts ''
        end
      end
    end
  end

  # clean the temp files and fail if there was an advisory
  FileUtils.rm_rf(TEMP_DIR)
  fail('One or more Gems have an advisory!') unless global_result
end

end