lib/bundler/audit/cli.rb in bundler-audit-0.7.0.1 vs lib/bundler/audit/cli.rb in bundler-audit-0.8.0.rc1
- old
+ new
@@ -15,60 +15,118 @@
# along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
#
require 'bundler/audit/scanner'
require 'bundler/audit/version'
+require 'bundler/audit/cli/formats'
require 'thor'
require 'bundler'
-require 'bundler/vendored_thor'
module Bundler
module Audit
class CLI < ::Thor
default_task :check
map '--version' => :version
- desc 'check', 'Checks the Gemfile.lock for insecure dependencies'
+ desc 'check [DIR]', 'Checks the Gemfile.lock for insecure dependencies'
method_option :quiet, :type => :boolean, :aliases => '-q'
method_option :verbose, :type => :boolean, :aliases => '-v'
method_option :ignore, :type => :array, :aliases => '-i'
method_option :update, :type => :boolean, :aliases => '-u'
+ method_option :database, :type => :string, :aliases => '-D', :default => Database::USER_PATH
+ method_option :format, :type => :string, :default => 'text',
+ :aliases => '-F'
+ method_option :gemfile_lock, :type => :string, :aliases => '-G', :default => 'Gemfile.lock'
+ method_option :output, :type => :string, :aliases => '-o'
- def check
- update if options[:update]
+ def check(dir=Dir.pwd)
+ unless File.directory?(dir)
+ say "No such file or directory: #{dir}", :red
+ exit 1
+ end
- scanner = Scanner.new
- vulnerable = false
+ begin
+ extend Formats.load(options[:format])
+ rescue Formats::FormatNotFound
+ say "Unknown format: #{options[:format]}", :red
+ exit 1
+ end
- scanner.scan(:ignore => options.ignore) do |result|
- vulnerable = true
+ if !Database.exists?
+ download(options[:database])
+ elsif options[:update]
+ update(options[:database])
+ end
- case result
- when Scanner::InsecureSource
- print_warning "Insecure Source URI found: #{result.source}"
- when Scanner::UnpatchedGem
- print_advisory result.gem, result.advisory
- end
+ database = Database.new(options[:database])
+ scanner = begin
+ Scanner.new(dir,options[:gemfile_lock],database)
+ rescue Bundler::GemfileLockNotFound => exception
+ say exception.message, :red
+ exit 1
+ end
+ report = scanner.report(:ignore => options.ignore)
+
+ output = if options[:output] then File.new(options[:output],'w')
+ else $stdout
+ end
+
+ print_report(report,output)
+
+ output.close if options[:output]
+
+ exit(1) if report.vulnerable?
+ end
+
+ desc 'stats', 'Prints ruby-advisory-db stats'
+ method_option :quiet, :type => :boolean, :aliases => '-q'
+
+ def stats(path=Database.path)
+ database = Database.new(path)
+
+ puts "ruby-advisory-db:"
+ puts " advisories:\t#{database.size} advisories"
+ puts " last updated:\t#{database.last_updated_at}"
+ end
+
+ desc 'download', 'Downloads ruby-advisory-db'
+ method_option :quiet, :type => :boolean, :aliases => '-q'
+
+ def download(path=Database.path)
+ if Database.exists?(path)
+ say "Database already exists", :yellow
+ return
end
- if vulnerable
- say "Vulnerabilities found!", :red
+ say("Download ruby-advisory-db ...") unless options.quiet?
+
+ begin
+ Database.download(path: path, quiet: options.quiet?)
+ rescue Database::DownloadFailed => error
+ say error.message, :red
exit 1
- else
- say("No vulnerabilities found", :green) unless options.quiet?
end
+
+ stats(path) unless options.quiet?
end
desc 'update', 'Updates the ruby-advisory-db'
method_option :quiet, :type => :boolean, :aliases => '-q'
- def update
+ def update(path=Database.path)
+ unless Database.exists?(path)
+ download(path)
+ return
+ end
+
say("Updating ruby-advisory-db ...") unless options.quiet?
- case Database.update!(quiet: options.quiet?)
+ database = Database.new(path)
+
+ case database.update!(quiet: options.quiet?)
when true
say("Updated ruby-advisory-db", :green) unless options.quiet?
when false
say "Failed updating ruby-advisory-db!", :red
exit 1
@@ -78,13 +136,11 @@
exit 1
end
say "Skipping update", :yellow
end
- unless options.quiet?
- puts("ruby-advisory-db: #{Database.new.size} advisories")
- end
+ stats(path) unless options.quiet?
end
desc 'version', 'Prints the bundler-audit version'
def version
database = Database.new
@@ -92,69 +148,19 @@
puts "#{File.basename($0)} #{VERSION} (advisories: #{database.size})"
end
protected
+ #
+ # @abstract
+ #
+ def print_report(report)
+ raise(NotImplementedError,"#{self.class}##{__method__} not defined")
+ end
+
def say(message="", color=nil)
color = nil unless $stdout.tty?
super(message.to_s, color)
- end
-
- def print_warning(message)
- say message, :yellow
- end
-
- def print_advisory(gem, advisory)
- say "Name: ", :red
- say gem.name
-
- say "Version: ", :red
- say gem.version
-
- say "Advisory: ", :red
-
- if advisory.cve
- say advisory.cve_id
- elsif advisory.osvdb
- say advisory.osvdb_id
- elsif advisory.ghsa
- say advisory.ghsa_id
- end
-
- say "Criticality: ", :red
- case advisory.criticality
- when :none then say "None"
- when :low then say "Low"
- when :medium then say "Medium", :yellow
- when :high then say "High", [:red, :bold]
- when :critical then say "Critical", [:red, :bold]
- else say "Unknown"
- end
-
- say "URL: ", :red
- say advisory.url
-
- if options.verbose?
- say "Description:", :red
- say
-
- print_wrapped advisory.description, :indent => 2
- say
- else
-
- say "Title: ", :red
- say advisory.title
- end
-
- unless advisory.patched_versions.empty?
- say "Solution: upgrade to ", :red
- say advisory.patched_versions.join(', ')
- else
- say "Solution: ", :red
- say "remove or disable this gem until a patch is available!", [:red, :bold]
- end
-
- say
end
end
end
end