inspec/lib/bundles/inspec-compliance/cli.rb

261 lines
8.8 KiB
Ruby
Raw Normal View History

2016-02-05 07:38:45 +00:00
# encoding: utf-8
# author: Christoph Hartmann
# author: Dominik Richter
require 'thor'
require 'erb'
2016-02-05 07:38:45 +00:00
module Compliance
class ComplianceCLI < Inspec::BaseCLI
2016-02-05 07:38:45 +00:00
namespace 'compliance'
2016-08-18 18:10:09 +00:00
# TODO: find another solution, once https://github.com/erikhuda/thor/issues/261 is fixed
def self.banner(command, _namespace = nil, _subcommand = false)
"#{basename} #{subcommand_prefix} #{command.usage}"
end
def self.subcommand_prefix
namespace
end
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
desc "login https://SERVER --insecure --user='USER' --ent='ENTERPRISE' --token='TOKEN'", 'Log in to a Chef Compliance/Chef Automate SERVER'
long_desc <<-LONGDESC
`login` allows you to use InSpec with Chef Automate or a Chef Compliance Server
You need to a token for communication. More information about token retrieval
is available at:
https://docs.chef.io/api_automate.html#authentication-methods
https://docs.chef.io/api_compliance.html#obtaining-an-api-token
LONGDESC
option :insecure, aliases: :k, type: :boolean,
desc: 'Explicitly allows InSpec to perform "insecure" SSL connections and transfers'
option :user, type: :string, required: false,
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
desc: 'Username'
option :password, type: :string, required: false,
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
desc: 'Password (Chef Compliance Only)'
option :token, type: :string, required: false,
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
desc: 'Access token'
option :refresh_token, type: :string, required: false,
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
desc: 'Chef Compliance refresh token (Chef Compliance Only)'
option :dctoken, type: :string, required: false,
desc: 'Data Collector token (Chef Automate Only)'
option :ent, type: :string, required: false,
desc: 'Enterprise for Chef Automate reporting (Chef Automate Only)'
def login(server)
options['server'] = server
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
Compliance::API.login(options)
config = Compliance::Configuration.new
puts "Stored configuration for Chef #{config['server_type'].capitalize}: #{config['server']}' with user: '#{config['user']}'"
2016-02-05 07:38:45 +00:00
end
desc 'profiles', 'list all available profiles in Chef Compliance'
option :owner, type: :string, required: false,
desc: 'owner whose profiles to list'
2016-02-05 07:38:45 +00:00
def profiles
config = Compliance::Configuration.new
return if !loggedin(config)
# set owner to config
config['owner'] = options['owner'] || config['user']
msg, profiles = Compliance::API.profiles(config)
profiles.sort_by! { |hsh| hsh['title'] }
2016-02-05 07:38:45 +00:00
if !profiles.empty?
# iterate over profiles
2016-02-05 10:06:00 +00:00
headline('Available profiles:')
2016-02-05 07:38:45 +00:00
profiles.each { |profile|
owner = profile['owner_id'] || profile['owner']
li("#{profile['title']} v#{profile['version']} (#{mark_text(owner + '/' + profile['name'])})")
2016-02-05 07:38:45 +00:00
}
else
puts msg, 'Could not find any profiles'
2016-08-18 16:34:09 +00:00
exit 1
2016-02-05 07:38:45 +00:00
end
rescue Compliance::ServerConfigurationMissing
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
STDERR.puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
exit 1
2016-02-05 07:38:45 +00:00
end
desc 'exec PROFILE', 'executes a Chef Compliance profile'
2016-03-06 14:07:12 +00:00
exec_options
2016-02-05 07:38:45 +00:00
def exec(*tests)
config = Compliance::Configuration.new
return if !loggedin(config)
o = opts(:exec).dup
diagnose(o)
configure_logger(o)
2016-02-05 07:38:45 +00:00
# iterate over tests and add compliance scheme
tests = tests.map { |t| 'compliance://' + Compliance::API.sanitize_profile_name(t) }
runner = Inspec::Runner.new(o)
tests.each { |target| runner.add_target(target) }
exit runner.run
rescue ArgumentError, RuntimeError, Train::UserError => e
$stderr.puts e.message
exit 1
2016-02-05 07:38:45 +00:00
end
desc 'download PROFILE', 'downloads a profile from Chef Compliance'
option :name, type: :string,
desc: 'Name of the archive filename (file type will be added)'
def download(profile_name)
o = options.dup
configure_logger(o)
config = Compliance::Configuration.new
return if !loggedin(config)
profile_name = Compliance::API.sanitize_profile_name(profile_name)
if Compliance::API.exist?(config, profile_name)
puts "Downloading `#{profile_name}`"
fetcher = Compliance::Fetcher.resolve(
{
compliance: profile_name,
},
)
# we provide a name, the fetcher adds the extension
_owner, id = profile_name.split('/')
file_name = fetcher.fetch(o.name || id)
puts "Profile stored to #{file_name}"
else
puts "Profile #{profile_name} is not available in Chef Compliance."
exit 1
end
end
2016-02-05 07:38:45 +00:00
desc 'upload PATH', 'uploads a local profile to Chef Compliance'
2016-02-05 10:06:00 +00:00
option :overwrite, type: :boolean, default: false,
desc: 'Overwrite existing profile on Server.'
option :owner, type: :string, required: false,
desc: 'Owner that should own the profile'
def upload(path) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, PerceivedComplexity, Metrics/CyclomaticComplexity
config = Compliance::Configuration.new
return if !loggedin(config)
# set owner to config
config['owner'] = options['owner'] || config['user']
unless File.exist?(path)
puts "Directory #{path} does not exist."
exit 1
end
vendor_deps(path, options) if File.directory?(path)
2016-02-05 10:06:00 +00:00
o = options.dup
configure_logger(o)
# check the profile, we only allow to upload valid profiles
2016-02-22 20:11:49 +00:00
profile = Inspec::Profile.for_target(path, o)
2016-02-05 10:06:00 +00:00
# start verification process
error_count = 0
error = lambda { |msg|
error_count += 1
puts msg
}
result = profile.check
unless result[:summary][:valid]
error.call('Profile check failed. Please fix the profile before upload.')
else
puts('Profile is valid')
end
# determine user information
if (config['token'].nil? && config['refresh_token'].nil?) || config['user'].nil?
2016-02-05 10:06:00 +00:00
error.call('Please login via `inspec compliance login`')
end
# read profile name from inspec.yml
profile_name = profile.params[:name]
# check that the profile is not uploaded already,
# confirm upload to the user (overwrite with --force)
if Compliance::API.exist?(config, "#{config['owner']}/#{profile_name}") && !options['overwrite']
2016-02-05 10:06:00 +00:00
error.call('Profile exists on the server, use --overwrite')
end
# abort if we found an error
if error_count > 0
puts "Found #{error_count} error(s)"
exit 1
end
2016-02-05 07:38:45 +00:00
2016-02-05 10:06:00 +00:00
# if it is a directory, tar it to tmp directory
if File.directory?(path)
archive_path = Dir::Tmpname.create([profile_name, '.tar.gz']) {}
2016-02-05 10:06:00 +00:00
puts "Generate temporary profile archive at #{archive_path}"
profile.archive({ output: archive_path, ignore_errors: false, overwrite: true })
2016-02-05 10:06:00 +00:00
else
archive_path = path
end
puts "Start upload to #{config['owner']}/#{profile_name}"
pname = ERB::Util.url_encode(profile_name)
2016-02-05 10:06:00 +00:00
if Compliance::API.is_automate_server?(config) || Compliance::API.is_automate2_server?(config)
puts 'Uploading to Chef Automate'
else
puts 'Uploading to Chef Compliance'
end
success, msg = Compliance::API.upload(config, config['owner'], pname, archive_path)
2016-02-05 07:38:45 +00:00
2016-02-05 10:06:00 +00:00
if success
2016-02-05 07:38:45 +00:00
puts 'Successfully uploaded profile'
else
2016-02-05 10:06:00 +00:00
puts 'Error during profile upload:'
puts msg
2016-08-18 16:34:09 +00:00
exit 1
2016-02-05 07:38:45 +00:00
end
end
desc 'version', 'displays the version of the Chef Compliance server'
def version
config = Compliance::Configuration.new
info = Compliance::API.version(config)
if !info.nil? && info['version']
puts "Name: #{info['api']}"
puts "Version: #{info['version']}"
2016-02-05 07:38:45 +00:00
else
puts 'Could not determine server version.'
exit 1
2016-02-05 07:38:45 +00:00
end
rescue Compliance::ServerConfigurationMissing
puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
exit 1
2016-02-05 07:38:45 +00:00
end
desc 'logout', 'user logout from Chef Compliance'
def logout
config = Compliance::Configuration.new
unless config.supported?(:oidc) || config['token'].nil? || config['server_type'] == 'automate'
config = Compliance::Configuration.new
url = "#{config['server']}/logout"
Compliance::HTTP.post(url, config['token'], config['insecure'], !config.supported?(:oidc))
end
success = config.destroy
if success
2016-02-05 07:38:45 +00:00
puts 'Successfully logged out'
else
puts 'Could not log out'
end
end
private
def loggedin(config)
serverknown = !config['server'].nil?
Add Chef Automate support to `inspec compliance login` (#2203) * Merge `login` and `login_automate` commands This provides a single interface for logging into either Chef Automate or Chef Compliance servers. Server type is evaluated at run time via HTTP responses from designated endpoints. This also moves the login logic from `Compliance::ComplianceCLI` to a separate set of modules in `Compliance::API`. This removes logic from Thor and allows for more in depth Unit testing. Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove empty line below class definition Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add message to `raise CannotDetermineServerType` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Refactor `token_info` assignment Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove unnecessary rubocop disable Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `Login` module namespacing Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Remove mentions of login_automate and --usertoken Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Modify `determine_server_type` to return a symbol Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Add support for `login_automate` and `--usertoken` Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Fix encoding typo Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com> * Address PR feedback This does the following: - Moves `CannotDetermineServerType` error to `.login` - Changes methods that store configuration to return the configuration - Moves user output to one location in `.login` - Makes other small improvements Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
2017-10-26 15:32:47 +00:00
puts 'You need to login first with `inspec compliance login`' if !serverknown
serverknown
end
2016-02-05 07:38:45 +00:00
end
2016-02-05 13:48:55 +00:00
# register the subcommand to Inspec CLI registry
Inspec::Plugins::CLI.add_subcommand(ComplianceCLI, 'compliance', 'compliance SUBCOMMAND ...', 'Chef Compliance commands', {})
2016-02-05 07:38:45 +00:00
end