class Chelsea::Gems

Class to collect and audit packages from a Gemfile.lock

Attributes

deps[RW]

Public Class Methods

new(file:, verbose:, options: { format: 'text' }) click to toggle source
# File lib/chelsea/gems.rb, line 36
def initialize(file:, verbose:, options: { format: 'text' }) # rubocop:disable Metrics/MethodLength
  @verbose = verbose
  raise 'Gemfile.lock not found, check --file path' unless File.file?(file) || file.nil?

  _silence_stderr unless @verbose

  @pastel = Pastel.new
  @formatter = FormatterFactory.new.get_formatter(
    format: options[:format],
    verbose: verbose
  )
  @client = Chelsea.client(options)
  @deps = Chelsea::Deps.new(path: Pathname.new(file))
  @spinner = Chelsea::Spinner.new
end

Public Instance Methods

audit() click to toggle source

Runs through auditing algorithm, raising exceptions on REST calls made by @deps.get_vulns

# File lib/chelsea/gems.rb, line 77
def audit # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  # This spinner management is out of control
  # we should wrap a block with start and stop messages,
  # or use a stack to ensure all spinners stop.
  spin = @spinner.spin_msg 'Parsing dependencies'

  begin
    dependencies = @deps.dependencies
    spin.success('...done.')
  rescue StandardError
    spin.stop
    _print_err "Parsing dependency line #{gem} failed."
  end

  reverse_dependencies = @deps.reverse_dependencies

  spin = @spinner.spin_msg 'Parsing Versions'
  coordinates = @deps.coordinates
  spin.success('...done.')
  spin = @spinner.spin_msg 'Making request to OSS Index server'
  spin.stop

  begin
    server_response = @client.get_vulns(coordinates)
    spin.success('...done.')
  rescue SocketError
    spin.stop('...request failed.')
    _print_err 'Socket error getting data from OSS Index server.'
  rescue RestClient::RequestFailed => e
    spin.stop('...request failed.')
    _print_err "Error getting data from OSS Index server:#{e.response}."
  rescue RestClient::ResourceNotFound
    spin.stop('...request failed.')
    _print_err 'Error getting data from OSS Index server. Resource not found.'
  rescue Errno::ECONNREFUSED
    spin.stop('...request failed.')
    _print_err 'Error getting data from OSS Index server. Connection refused.'
  end
  [server_response, dependencies, reverse_dependencies]
end
collect_iq() click to toggle source
# File lib/chelsea/gems.rb, line 71
def collect_iq
  @deps.dependencies
end
execute() click to toggle source

Audits depenencies using deps library and prints results using formatter library

# File lib/chelsea/gems.rb, line 55
def execute # rubocop:disable Metrics/MethodLength
  server_response, dependencies, reverse_dependencies = audit
  if dependencies.nil?
    _print_err 'No dependencies retrieved. Exiting.'
    return
  end
  if server_response.nil?
    _print_success 'No vulnerability data retrieved from server. Exiting.'
    return
  end
  results = @formatter.fetch_results(server_response, reverse_dependencies)
  @formatter.do_print(results)

  server_response.map { |r| r['vulnerabilities'].length.positive? }.any?
end

Protected Instance Methods

_print_err(msg) click to toggle source
# File lib/chelsea/gems.rb, line 124
def _print_err(msg)
  puts @pastel.red.bold(msg)
end
_print_success(msg) click to toggle source
# File lib/chelsea/gems.rb, line 128
def _print_success(msg)
  puts @pastel.green.bold(msg)
end
_silence_stderr() click to toggle source
# File lib/chelsea/gems.rb, line 120
def _silence_stderr
  $stderr.reopen('/dev/null', 'w')
end