class Compliance::ComplianceCLI
def self.banner(command, _namespace = nil, _subcommand = false)
def self.banner(command, _namespace = nil, _subcommand = false) "#{basename} #{subcommand_prefix} #{command.usage}" end
def self.subcommand_prefix
def self.subcommand_prefix namespace end
def download(profile_name)
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
def exec(*tests)
def exec(*tests) config = Compliance::Configuration.new return if !loggedin(config) o = opts(:exec).dup diagnose(o) configure_logger(o) # 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 end
def loggedin(config)
def loggedin(config) serverknown = !config['server'].nil? puts 'You need to login first with `inspec compliance login`' if !serverknown serverknown end
def login(server)
def login(server) options['server'] = server Compliance::API.login(options) config = Compliance::Configuration.new puts "Stored configuration for Chef #{config['server_type'].capitalize}: #{config['server']}' with user: '#{config['user']}'" end
def logout
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 puts 'Successfully logged out' else puts 'Could not log out' end end
def profiles
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'] } if !profiles.empty? # iterate over profiles headline('Available profiles:') profiles.each { |profile| owner = profile['owner_id'] || profile['owner'] li("#{profile['title']} v#{profile['version']} (#{mark_text(owner + '/' + profile['name'])})") } else puts msg, 'Could not find any profiles' exit 1 end rescue Compliance::ServerConfigurationMissing STDERR.puts "\nServer configuration information is missing. Please login using `inspec compliance login`" exit 1 end
def upload(path) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, PerceivedComplexity, Metrics/CyclomaticComplexity
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) o = options.dup configure_logger(o) # check the profile, we only allow to upload valid profiles profile = Inspec::Profile.for_target(path, o) # 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? error.call('Please login via `inspec compliance login`') end # read profile name from inspec.yml profile_name = profile.params[:name] # read profile version from inspec.yml profile_version = profile.params[:version] # 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}##{profile_version}") && !options['overwrite'] 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 # if it is a directory, tar it to tmp directory if File.directory?(path) archive_path = Dir::Tmpname.create([profile_name, '.tar.gz']) {} puts "Generate temporary profile archive at #{archive_path}" profile.archive({ output: archive_path, ignore_errors: false, overwrite: true }) else archive_path = path end puts "Start upload to #{config['owner']}/#{profile_name}" pname = ERB::Util.url_encode(profile_name) 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) if success puts 'Successfully uploaded profile' else puts 'Error during profile upload:' puts msg exit 1 end end
def version
def version config = Compliance::Configuration.new info = Compliance::API.version(config) if !info.nil? && info['version'] puts "Name: #{info['api']}" puts "Version: #{info['version']}" else puts 'Could not determine server version.' exit 1 end rescue Compliance::ServerConfigurationMissing puts "\nServer configuration information is missing. Please login using `inspec compliance login`" exit 1 end