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

144 lines
5 KiB
Ruby
Raw Normal View History

2016-02-05 07:38:45 +00:00
# encoding: utf-8
# author: Christoph Hartmann
# author: Dominik Richter
require 'uri'
require 'inspec/fetcher'
require 'inspec/errors'
2016-02-05 07:38:45 +00:00
# InSpec Target Helper for Chef Compliance
# reuses UrlHelper, but it knows the target server and the access token already
# similar to `inspec exec http://localhost:2134/owners/%base%/compliance/%ssh%/tar --user %token%`
module Compliance
class Fetcher < Fetchers::Url
name 'compliance'
priority 500
attr_reader :upstream_sha256
def initialize(target, opts)
super(target, opts)
@upstream_sha256 = ''
if target.is_a?(Hash) && target.key?(:url)
@target = target[:url]
@upstream_sha256 = target[:sha256]
elsif target.is_a?(String)
@target = target
end
end
2016-02-05 07:38:45 +00:00
def sha256
upstream_sha256.empty? ? super : upstream_sha256
end
def self.check_compliance_token(uri, config)
if config['token'].nil? && config['refresh_token'].nil?
if config['server_type'] == 'automate'
server = 'automate'
msg = 'inspec compliance login https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --token USERTOKEN'
elsif config['server_type'] == 'automate2'
server = 'automate2'
msg = 'inspec compliance login https://your_automate2_server --user USER --token APITOKEN'
else
server = 'compliance'
msg = "inspec compliance login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE' "
end
raise Inspec::FetcherFailure, <<~EOF
Cannot fetch #{uri} because your #{server} token has not been
configured.
Please login using
#{msg}
EOF
end
end
def self.get_target_uri(target)
if target.is_a?(String) && URI(target).scheme == 'compliance'
URI(target)
elsif target.respond_to?(:key?) && target.key?(:compliance)
URI("compliance://#{target[:compliance]}")
end
end
2016-02-05 07:38:45 +00:00
def self.resolve(target)
uri = get_target_uri(target)
return nil if uri.nil?
config = Compliance::Configuration.new
profile = Compliance::API.sanitize_profile_name(uri)
profile_fetch_url = Compliance::API.target_url(config, profile)
# we have detailed information available in our lockfile, no need to ask the server
if target.respond_to?(:key?) && target.key?(:sha256)
profile_checksum = target[:sha256]
else
check_compliance_token(uri, config)
# verifies that the target e.g base/ssh exists
# Call profiles directly instead of exist? to capture the results
# so we can access the upstream sha256 from the results.
_msg, profile_result = Compliance::API.profiles(config, profile)
if profile_result.empty?
raise Inspec::FetcherFailure, "The compliance profile #{profile} was not found on the configured compliance server"
else
# Guarantee sorting by verison and grab the latest.
# If version was specified, it will be the first and only result.
# Note we are calling the sha256 as a string, not a symbol since
# it was returned as json from the Compliance API.
profile_info = profile_result.sort_by { |x| Gem::Version.new(x['version']) }[0]
profile_checksum = profile_info.key?('sha256') ? profile_info['sha256'] : ''
end
end
# We need to pass the token to the fetcher
config['token'] = Compliance::API.get_token(config)
# Needed for automate2 post request
profile_stub = profile || target[:compliance]
config['profile'] = Compliance::API.profile_split(profile_stub)
new({ url: profile_fetch_url, sha256: profile_checksum }, config)
rescue URI::Error => _e
nil
2016-02-05 07:38:45 +00:00
end
# We want to save compliance: in the lockfile rather than url: to
# make sure we go back through the Compliance API handling.
def resolved_source
@resolved_source ||= {
compliance: compliance_profile_name,
url: @target,
sha256: sha256,
}
end
2016-02-05 07:38:45 +00:00
def to_s
'Chef Compliance Profile Loader'
end
private
# determine the owner_id and the profile name from the url
def compliance_profile_name
m = if Compliance::API.is_automate_server_pre_080?(@config)
%r{^#{@config['server']}/(?<owner>[^/]+)/(?<id>[^/]+)/tar$}
elsif Compliance::API.is_automate_server_080_and_later?(@config)
%r{^#{@config['server']}/profiles/(?<owner>[^/]+)/(?<id>[^/]+)/tar$}
else
%r{^#{@config['server']}/owners/(?<owner>[^/]+)/compliance/(?<id>[^/]+)/tar$}
end.match(@target)
if Compliance::API.is_automate2_server?(@config)
m = {}
m[:owner] = @config['profile'][0]
m[:id] = @config['profile'][1]
end
raise 'Unable to determine compliance profile name. This can be caused by ' \
'an incorrect server in your configuration. Try to login to compliance ' \
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
'via the `inspec compliance login` command.' if m.nil?
"#{m[:owner]}/#{m[:id]}"
end
2016-02-05 07:38:45 +00:00
end
end