require 'railroader/options' module Railroader # Implements handling of running Railroader from the command line. class Commandline class << self # Main method to run Railroader from the command line. # # If no options are provided, ARGV will be parsed and used instead. # Otherwise, the options are expected to be a Hash like the one returned # after ARGV is parsed. def start options = nil, app_path = "." unless options options, app_path = parse_options ARGV end run options, app_path end # Runs everything: # # - `set_interrupt_handler` # - `early_exit_options` # - `set_options` # - `check_latest` # - `run_report` def run options, default_app_path = "." set_interrupt_handler options early_exit_options options set_options options, default_app_path check_latest if options[:ensure_latest] run_report options end # Check for the latest version. # # If the latest version is newer, quit with a message. def check_latest if error = Railroader.ensure_latest quit Railroader::Not_Latest_Version_Exit_Code, error end end # Runs a comparison report based on the options provided. def compare_results options require 'json' vulns = Railroader.compare options.merge(:quiet => options[:quiet]) if options[:comparison_output_file] File.open options[:comparison_output_file], "w" do |f| f.puts JSON.pretty_generate(vulns) end Railroader.notify "Comparison saved in '#{options[:comparison_output_file]}'" else puts JSON.pretty_generate(vulns) end if options[:exit_on_warn] && vulns[:new].count > 0 quit Railroader::Warnings_Found_Exit_Code end end # Handle options that exit without generating a report. def early_exit_options options if options[:list_checks] or options[:list_optional_checks] Railroader.list_checks options quit elsif options[:create_config] Railroader.dump_config options quit elsif options[:show_help] puts Railroader::Options.create_option_parser({}) quit elsif options[:show_version] require 'railroader/version' puts "railroader #{Railroader::Version}" quit end end # Parse ARGV-style array of options. # # Exits if options are invalid. # # Returns an option hash and the app_path. def parse_options argv begin options, _ = Railroader::Options.parse! argv rescue OptionParser::ParseError => e $stderr.puts e.message $stderr.puts "Please see `railroader --help` for valid options" quit(-1) end if argv[-1] app_path = argv[-1] else app_path = "." end return options, app_path end # Exits with the given exit code and prints out the message, if given. # # Override this method for different behavior. def quit exit_code = 0, message = nil warn message if message exit exit_code end # Runs a regular report based on the options provided. def regular_report options tracker = run_railroader options if tracker.options[:exit_on_warn] and not tracker.filtered_warnings.empty? quit Railroader::Warnings_Found_Exit_Code end if tracker.options[:exit_on_error] and tracker.errors.any? quit Railroader::Errors_Found_Exit_Code end end # Actually run Railroader. # # Returns a Tracker object. def run_railroader options Railroader.run options.merge(:print_report => true, :quiet => options[:quiet]) end # Run either a comparison or regular report based on options provided. def run_report options begin if options[:previous_results_json] compare_results options else regular_report options end rescue Railroader::NoApplication => e quit Railroader::No_App_Found_Exit_Code, e.message rescue Railroader::MissingChecksError => e quit Railroader::Missing_Checks_Exit_Code, e.message end end # Sets interrupt handler to gracefully handle Ctrl+C def set_interrupt_handler options trap("INT") do warn "\nInterrupted - exiting." if options[:debug] warn caller end exit! end end # Modifies options, including setting the app_path # if none is given in the options hash. def set_options options, default_app_path = "." unless options[:app_path] options[:app_path] = default_app_path end if options[:quiet].nil? options[:quiet] = :command_line end options end end end end