mirror of
https://github.com/inspec/inspec
synced 2024-12-18 00:53:22 +00:00
ee62499fc0
without this, `inspec json PATH` does never contain rules != {}, because of the usage of the mock backend
187 lines
5.4 KiB
Ruby
Executable file
187 lines
5.4 KiB
Ruby
Executable file
#!/usr/bin/env ruby
|
|
# encoding: utf-8
|
|
# Copyright 2015 Dominik Richter. All rights reserved.
|
|
# author: Dominik Richter
|
|
# author: Christoph Hartmann
|
|
|
|
require 'thor'
|
|
require 'json'
|
|
require 'pp'
|
|
require_relative '../lib/inspec'
|
|
|
|
class InspecCLI < Thor # rubocop:disable Metrics/ClassLength
|
|
class_option :diagnose, type: :boolean,
|
|
desc: 'Show diagnostics (versions, configurations)'
|
|
|
|
def self.target_options
|
|
option :target, aliases: :t, type: :string,
|
|
desc: 'Simple targeting option using URIs, e.g. ssh://user:pass@host:port'
|
|
option :backend, aliases: :b, type: :string,
|
|
desc: 'Choose a backend: local, ssh, winrm, docker.'
|
|
option :host, type: :string,
|
|
desc: 'Specify a remote host which is tested.'
|
|
option :port, aliases: :p, type: :numeric,
|
|
desc: 'Specify the login port for a remote scan.'
|
|
option :user, type: :string,
|
|
desc: 'The login user for a remote scan.'
|
|
option :password, type: :string,
|
|
desc: 'Login password for a remote scan, if required.'
|
|
option :key_files, aliases: :i, type: :array,
|
|
desc: 'Login key or certificate file for a remote scan.'
|
|
option :path, type: :string,
|
|
desc: 'Login path to use when connecting to the target (WinRM).'
|
|
option :sudo, type: :boolean,
|
|
desc: 'Run scans with sudo. Only activates on Unix and non-root user.'
|
|
option :sudo_password, type: :string,
|
|
desc: 'Specify a sudo password, if it is required.'
|
|
option :sudo_options, type: :string,
|
|
desc: 'Additional sudo options for a remote scan.'
|
|
option :ssl, type: :boolean,
|
|
desc: 'Use SSL for transport layer encryption (WinRM).'
|
|
option :self_signed, type: :boolean,
|
|
desc: 'Allow remote scans with self-signed certificates (WinRM).'
|
|
option :json_config, type: :string,
|
|
desc: 'Read configuration from JSON file (`-` reads from stdin).'
|
|
end
|
|
|
|
desc 'json PATH', 'read all tests in PATH and generate a JSON summary'
|
|
option :id, type: :string,
|
|
desc: 'Attach a profile ID to all test results'
|
|
option :output, aliases: :o, type: :string,
|
|
desc: 'Save the created profile to a path'
|
|
def json(path)
|
|
diagnose
|
|
|
|
o = opts.dup
|
|
o[:ignore_supports] = true
|
|
profile = Inspec::Profile.from_path(path, o)
|
|
dst = o[:output].to_s
|
|
if dst.empty?
|
|
puts JSON.pretty_generate(profile.info)
|
|
else
|
|
if File.exist? dst
|
|
puts "----> updating #{dst}"
|
|
else
|
|
puts "----> creating #{dst}"
|
|
end
|
|
fdst = File.expand_path(dst)
|
|
File.write(fdst, JSON.dump(profile.info))
|
|
end
|
|
end
|
|
|
|
desc 'check PATH', 'verify all tests at the specified PATH'
|
|
def check(path)
|
|
diagnose
|
|
|
|
o = opts.dup
|
|
o[:logger] = Logger.new(STDOUT)
|
|
o[:ignore_supports] = true # we check for integrity only
|
|
profile = Inspec::Profile.from_path(path, o)
|
|
exit 1 unless profile.check
|
|
end
|
|
|
|
desc 'archive PATH', 'archive a profile to tar.gz (default) or zip'
|
|
option :zip, type: :boolean, default: false,
|
|
desc: 'Generates a zip archive.'
|
|
option :tar, type: :boolean, default: false,
|
|
desc: 'Generates a tar.gz archive.'
|
|
option :overwrite, type: :boolean, default: false,
|
|
desc: 'Overwrite existing archive.'
|
|
option :ignore_errors, type: :boolean, default: false,
|
|
desc: 'Ignore profile warnings.'
|
|
def archive(path)
|
|
diagnose
|
|
|
|
o = options.dup
|
|
o[:logger] = Logger.new(STDOUT)
|
|
profile = Inspec::Profile.from_path(path, o)
|
|
# generate archive
|
|
exit 1 unless profile.archive(opts)
|
|
end
|
|
|
|
desc 'exec PATHS', 'run all test files at the specified PATH.'
|
|
option :id, type: :string,
|
|
desc: 'Attach a profile ID to all test results'
|
|
target_options
|
|
option :format, type: :string
|
|
def exec(*tests)
|
|
diagnose
|
|
|
|
runner = Inspec::Runner.new(opts)
|
|
runner.add_tests(tests)
|
|
exit runner.run
|
|
rescue RuntimeError => e
|
|
puts e.message
|
|
end
|
|
|
|
desc 'detect', 'detect the target OS'
|
|
target_options
|
|
def detect
|
|
diagnose
|
|
|
|
runner = Inspec::Runner.new(opts)
|
|
rel = File.join(File.dirname(__FILE__), *%w{.. lib utils detect.rb})
|
|
detect_util = File.expand_path(rel)
|
|
runner.add_tests([detect_util])
|
|
runner.run
|
|
rescue RuntimeError => e
|
|
puts e.message
|
|
end
|
|
|
|
desc 'shell', 'open an interactive debugging shell'
|
|
target_options
|
|
option :format, type: :string, default: Inspec::NoSummaryFormatter, hide: true
|
|
def shell_func
|
|
diagnose
|
|
|
|
runner = Inspec::Runner.new(opts)
|
|
Inspec::Shell.new(runner).start
|
|
rescue RuntimeError => e
|
|
puts e.message
|
|
end
|
|
|
|
desc 'version', 'prints the version of this tool'
|
|
def version
|
|
puts Inspec::VERSION
|
|
end
|
|
|
|
private
|
|
|
|
def diagnose
|
|
return unless opts['diagnose']
|
|
puts "InSpec version: #{Inspec::VERSION}"
|
|
puts "Train version: #{Train::VERSION}"
|
|
puts 'Command line configuration:'
|
|
pp options
|
|
puts 'JSON configuration file:'
|
|
pp options_json
|
|
puts 'Merged configuration:'
|
|
pp opts
|
|
puts
|
|
end
|
|
|
|
def opts
|
|
# argv overrides json
|
|
Thor::CoreExt::HashWithIndifferentAccess.new(options_json.merge(options))
|
|
end
|
|
|
|
def options_json
|
|
conffile = options['json_config']
|
|
@json ||= conffile ? read_config(conffile) : {}
|
|
end
|
|
|
|
def read_config(file)
|
|
if file == '-'
|
|
puts 'WARN: reading JSON config from standard input' if STDIN.tty?
|
|
config = STDIN.read
|
|
else
|
|
config = File.read(file)
|
|
end
|
|
|
|
JSON.load(config)
|
|
rescue JSON::ParserError => e
|
|
puts "Failed to load JSON configuration: #{e}\nConfig was: #{config.inspect}"
|
|
exit 1
|
|
end
|
|
end
|
|
InspecCLI.start(ARGV)
|