class Bundler::Patch::AdvisoryConsolidator

Public Class Methods

new(options={}, all_ads=nil) click to toggle source
# File lib/bundler/patch/advisory_consolidator.rb, line 3
def initialize(options={}, all_ads=nil)
  @options = options
  @all_ads = all_ads || [].tap do |a|
    unless options[:skip_bundler_advise]
      if options[:ruby_advisory_db_path]
        a << Bundler::Advise::Advisories.new(dir: options[:ruby_advisory_db_path])
      else
        a << Bundler::Advise::Advisories.new # annoying
      end
    end
    a << Bundler::Advise::Advisories.new(dir: options[:advisory_db_path], repo: nil) if options[:advisory_db_path]
  end
end

Public Instance Methods

patch_gemfile_and_get_gem_specs_to_patch() click to toggle source
# File lib/bundler/patch/advisory_consolidator.rb, line 34
def patch_gemfile_and_get_gem_specs_to_patch
  gem_update_specs = vulnerable_gems
  locked = File.exist?(Bundler.default_lockfile) ?
    Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile)).specs : []

  gem_update_specs.map(&:update) # modify requirements in Gemfile if necessary

  gem_update_specs.map do |up_spec|
    old_version = locked.detect { |s| s.name == up_spec.gem_name }.version.to_s
    new_version = up_spec.calc_new_version(old_version)
    if new_version
      GemPatch.new(gem_name: up_spec.gem_name, old_version: old_version,
                   new_version: new_version, patched_versions: up_spec.patched_versions)
    else
      GemPatch.new(gem_name: up_spec.gem_name, old_version: old_version, patched_versions: up_spec.patched_versions)
    end
  end
end
vulnerable_gems() click to toggle source
# File lib/bundler/patch/advisory_consolidator.rb, line 17
def vulnerable_gems
  @all_ads.map do |ads|
    ads.update if ads.repo
    File.exist?(Bundler.default_lockfile) ? Bundler::Advise::GemAdviser.new(advisories: ads).scan_lockfile : []
  end.flatten.map do |advisory|
    patched = advisory.patched_versions.map do |pv|
      # this is a little stupid for compound requirements, but works itself out in consolidate_gemfiles
      pv.requirements.map { |_, v| v.to_s }
    end.flatten
    Gemfile.new(gem_name: advisory.gem, patched_versions: patched)
  end.group_by do |gemfile|
    gemfile.gem_name
  end.map do |_, gemfiles|
    consolidate_gemfiles(gemfiles)
  end.flatten
end

Private Instance Methods

consolidate_gemfiles(gemfiles) click to toggle source
# File lib/bundler/patch/advisory_consolidator.rb, line 55
def consolidate_gemfiles(gemfiles)
  gemfiles if gemfiles.length == 1
  all_gem_names = gemfiles.map(&:gem_name).uniq
  raise 'Must be all same gem name' unless all_gem_names.length == 1
  highest_minor_patched = gemfiles.map do |g|
    g.patched_versions
  end.flatten.group_by do |v|
    Gem::Version.new(v).segments[0..1].join('.')
  end.map do |_, all|
    all.sort.last
  end
  Gemfile.new(target_bundle: @options[:target] || TargetBundle.new,
              gem_name: all_gem_names.first, patched_versions: highest_minor_patched)
end