class Sectest
Public Class Methods
load_manifest(sectest_name)
click to toggle source
Loads a manifest file depending on the command rubocop:disable Style/GuardClause
# File lib/norad_cli/cli/sectest.rb, line 35 def self.load_manifest(sectest_name) @@sectest_manifest = {} # Set defaults just in case no manifest.yml to overwrite @@sectest_manifest['registry'] = 'norad-registry.cisco.com:5000' @@sectest_manifest['version'] = 'latest' # Dynamically add options and description based on the needs of the sectest container if %w[build build:all build:image build:specs execute].include?(ARGV[1]) && sectest_name && !sectest_name.start_with?('-', '--') # Read in the program arguments if File.exist?("sectests/#{sectest_name}/manifest.yml") @@sectest_manifest = YAML.safe_load(File.read("sectests/#{sectest_name}/manifest.yml")) # Precautionary, remove all leading and trailing whitespace @@sectest_manifest['registry'].strip! @@sectest_manifest['version'].strip! else puts Rainbow("Error: #{sectest_name} sectest does not exist or it is missing sectests/#{sectest_name}/manifest.yml").red puts Rainbow('Exiting...').red exit(1) end end end
new(*args)
click to toggle source
rubocop:enable Style/GuardClause
Calls superclass method
# File lib/norad_cli/cli/sectest.rb, line 60 def initialize(*args) super # Check if the command is being run from the repository root (all commands must be) root_dir? end
source_root()
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 29 def self.source_root File.join(File.dirname(File.expand_path(__FILE__)), '../templates/') end
Public Instance Methods
build()
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 118 def build # Error check to ensure this is a plugin directory Dir.glob('sectests/*').select do |f| # Skip if the entry is not a directory next if !File.directory? f # Grab the name of the sectest sectest_name = f.split('/')[-1] # Load the manifest for the sectest Sectest.load_manifest(sectest_name) # Build all for the sectest send('build:all', sectest_name) end end
dockerfile?(img_dir)
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 308 def dockerfile?(img_dir) # Ensure the Dockerfile exists for the new tool File.file?("#{img_dir}/Dockerfile") end
execute(sectest_name)
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 222 def execute(sectest_name) # Warn users if debugging is enabled say('Warning: Debug enabled: containers must be removed manually', :yellow) && sleep(2) if options['debug'] # Ensure the results server is built by building the images specs (code reuse) send('build:specs', sectest_name) # Build the sectest image if necessary send('build:image', sectest_name) # Allocate an instance of the sectest sectest_instance = NoradCli::SecTestContainer.new(ARGV[2], @@sectest_manifest['registry'], @@sectest_manifest['version'], options) # Start the test sectest_instance.start # Print any debugging sectest_instance.output(options[:target]) if options[:debug] # Get the results results = sectest_instance.results say('Results are:', :green) formatted_results = options[:format] ? JSON.pretty_generate(JSON.parse(results)) : results puts formatted_results # Cleanup the sectest container sectest_instance.shutdown # Warn users if debugging is enabled say('Warning: Debug enabled: containers must be removed manually', :yellow) if options['debug'] end
extract_base_img(img_dir)
click to toggle source
Check for a base image
# File lib/norad_cli/cli/sectest.rb, line 314 def extract_base_img(img_dir) from_line = File.readlines("#{img_dir}/Dockerfile").select { |line| line =~ /^FROM/ } # Detect missing FROM lines if from_line.length.zero? puts Rainbow("Error: #{img_dir}/Dockerfile missing a FROM line!").red exit(1) else from_line_arr = from_line[0].split(' ') end from_image = from_line[0][%r{\AFROM\s+(.*?\/)?(.*?)(:.*?)?\Z}i, 2] || raise('bad from') [from_image, from_line_arr[1]] end
root_dir?()
click to toggle source
Ensure commands are run from the root dir
# File lib/norad_cli/cli/sectest.rb, line 328 def root_dir? %w[base spec sectests].each do |dirrepo_name| if !File.exist?(dirrepo_name) say("Commands must be run from the root of the test repository\nExiting....", :red) exit(1) end end end
run_specs(*specs, **opts)
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 339 def run_specs(*specs, **opts) thor_options = opts.fetch(:thor_options, {}) # Set environment variables if thor_options[:verbose] ENV['ENABLE_LOGS'] = 'true' end if thor_options[:debug] ENV['ENABLE_NORAD_DEBUG'] = 'true' end ENV['SCAN_ASSESSMENT'] = 'true' ENV['TEST_RESULTS_SERVER_IMAGE'] = 'docker-images-test-results-server' ENV['UBUNTU_SSH_SERVER_IMAGE'] = 'docker-images-test-ubuntu-ssh-server' codes = specs.map do |spec| # Run the tests if File.exist?("spec/#{spec}/#{spec}_spec.rb") RSpec.clear_examples say("Testing spec/#{spec}/#{spec}_spec.rb") RSpec::Core::Runner.run(["spec/#{spec}/#{spec}_spec.rb"], $stderr, $stdout) else say("Warning: spec/#{spec}/#{spec}_spec.rb does not exist!\n", :yellow) say("Warning: No tests will be run for #{spec}\n", :yellow) 0 # always return 0 if the spec doesn't exist end end exit(codes.detect(-> { 0 }, &:nonzero?)) end
run_validations(*files)
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 369 def run_validations(*files) codes = files.map do |file| ENV['sectest_name'] = file # Validate the readme file say("Validating README for #{file}") RSpec.clear_examples RSpec::Core::Runner.run(["#{File.dirname(File.expand_path(__FILE__))}/../support/readme_spec.rb"], $stderr, $stdout) # Validate the manifest file say("Validating manifest.yml for #{file}") RSpec.clear_examples RSpec::Core::Runner.run(["#{File.dirname(File.expand_path(__FILE__))}/../support/manifest_spec.rb"], $stderr, $stdout) end exit(codes.detect(-> { 0 }, &:nonzero?)) end
scaffold(sectest_name)
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 80 def scaffold(sectest_name) # Grab the current directory repo_dir = Dir.pwd # Check for valid test types if !%w[authenticated web_application brute_force ssl_crypto ssh_crypto whole_host].include?(options[:test_type]) say("#{options[:test_type]} is not a supported test type", :red) say('Exiting...', :red) exit(1) end # Set options for templates options[:name] = sectest_name options[:spec_class_name] = sectest_name.split('-').map { |t| t =~ /\d+/ ? t : t.capitalize! }.join # Error check to ensure this is a norad security test repository # Create the security tests standard files template('tool/Dockerfile.erb', "#{repo_dir}/sectests/#{sectest_name}/Dockerfile") template('tool/README.md.erb', "#{repo_dir}/sectests/#{sectest_name}/README.md") template('tool/manifest.yml.erb', "#{repo_dir}/sectests/#{sectest_name}/manifest.yml") # Create a starter wrapper script template('tool/wrapper.rb.erb', "#{repo_dir}/sectests/#{sectest_name}/#{sectest_name}-wrapper.rb") # Create the spec files template('tool/tool_spec.rb.erb', "#{repo_dir}/spec/#{sectest_name}/#{sectest_name}_spec.rb") if options[:test_type] == 'authenticated' template('tool/Dockerfile.auth.target.erb', "#{repo_dir}/spec/#{sectest_name}/targets/Dockerfile.secure") template('tool/Dockerfile.auth.target.erb', "#{repo_dir}/spec/#{sectest_name}/targets/Dockerfile.vulnerable") else template('tool/Dockerfile.unauth.target.erb', "#{repo_dir}/spec/#{sectest_name}/targets/Dockerfile.secure") template('tool/Dockerfile.unauth.target.erb', "#{repo_dir}/spec/#{sectest_name}/targets/Dockerfile.vulnerable") end end
seed()
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 279 def seed # Generate the seed file SeedGenerator.process_manifests(options[:seedfile], options[:docsite]) end
spec()
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 266 def spec # Error check to ensure this is a plugin directory specs = Dir.glob('sectests/*').map do |f| if File.directory? f f.split('/')[-1] end end.compact run_specs(*specs, thor_options: options) end
validate()
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 297 def validate # Error check to ensure this is a plugin directory files = Dir.glob('sectests/*').map do |f| if File.directory? f f.split('/')[-1] end end.compact run_validations(*files) end
Private Instance Methods
parse_json(stream)
click to toggle source
# File lib/norad_cli/cli/sectest.rb, line 388 def parse_json(stream) stream.split(/\r\n/).each do |string| parsed = JSON.parse(string) $stdout.print(parsed['stream']) if parsed.is_a?(Hash) end rescue JSON::ParserError $stdout.print stream end