lib/inspec/profile.rb in inspec-0.35.0 vs lib/inspec/profile.rb in inspec-1.0.0.beta2

- old
+ new

@@ -11,31 +11,56 @@ require 'inspec/metadata' require 'inspec/backend' require 'inspec/rule' require 'inspec/log' require 'inspec/profile_context' -require 'inspec/dependencies/vendor_index' +require 'inspec/dependencies/cache' require 'inspec/dependencies/lockfile' require 'inspec/dependencies/dependency_set' module Inspec class Profile # rubocop:disable Metrics/ClassLength extend Forwardable + # + # TODO: This function is getting pretty gross. + # def self.resolve_target(target, cache = nil) - cache ||= VendorIndex.new + cache ||= Cache.new fetcher = Inspec::Fetcher.resolve(target) + if fetcher.nil? fail("Could not fetch inspec profile in #{target.inspect}.") end - if cache.exists?(fetcher.cache_key) + cache_key = if target.is_a?(Hash) + target[:sha256] || target[:ref] || fetcher.cache_key + else + fetcher.cache_key + end + + if cache.exists?(cache_key) Inspec::Log.debug "Using cached dependency for #{target}" - cache.prefered_entry_for(fetcher.cache_key) + [cache.prefered_entry_for(cache_key), false] else fetcher.fetch(cache.base_path_for(fetcher.cache_key)) - fetcher.archive_path + if target.respond_to?(:key?) && target.key?(:sha256) + if fetcher.resolved_source[:sha256] != target[:sha256] + fail <<EOF +The remote source #{fetcher} no longer has the requested content: + +Request Content Hash: #{target[:sha256]} + Actual Content Hash: #{fetcher.resolved_source[:sha256]} + +For URL, supermarket, compliance, and other sources that do not +provide versioned artifacts, this likely means that the remote source +has changed since your lockfile was generated. +EOF + end + end + + [fetcher.archive_path, fetcher.writable?] end end def self.for_path(path, opts) file_provider = FileProvider.for_path(path) @@ -46,11 +71,12 @@ end new(reader, opts) end def self.for_target(target, opts = {}) - for_path(resolve_target(target, opts[:cache]), opts.merge(target: target)) + path, writable = resolve_target(target, opts[:cache]) + for_path(path, opts.merge(target: target, writable: writable)) end attr_reader :source_reader, :backend, :runner_context def_delegator :@source_reader, :tests def_delegator :@source_reader, :libraries @@ -60,14 +86,17 @@ def initialize(source_reader, options = {}) @target = options.delete(:target) @logger = options[:logger] || Logger.new(nil) @locked_dependencies = options[:dependencies] @controls = options[:controls] || [] + @writable = options[:writable] || false @profile_id = options[:id] + @cache = options[:cache] || Cache.new @backend = options[:backend] || Inspec::Backend.create(options) @source_reader = source_reader @tests_collected = false + @libraries_loaded = false Metadata.finalize(@source_reader.metadata, @profile_id) @runner_context = options[:profile_context] || Inspec::ProfileContext.for_profile(self, @backend, options[:attributes]) end @@ -78,10 +107,14 @@ def version metadata.params[:version] end + def writable? # rubocop:disable Style/TrivialAccessors + @writable + end + # # Is this profile is supported on the current platform of the # backend machine and the current inspec version. # # @returns [TrueClass, FalseClass] @@ -123,40 +156,53 @@ include_list.include?(id) end end def load_libraries + return @runner_context if @libraries_loaded + locked_dependencies.each do |d| c = d.load_libraries @runner_context.add_resources(c) end libs = libraries.map do |path, content| [content, path] end @runner_context.load_libraries(libs) + @libraries_loaded = true @runner_context end def to_s "Inspec::Profile<#{name}>" end - def info - res = params.dup + # return info using uncached params + def info! + info(load_params.dup) + end + + def info(res = params.dup) # add information about the controls - controls = res[:controls].map do |id, rule| + res[:controls] = res[:controls].map do |id, rule| next if id.to_s.empty? data = rule.dup data.delete(:checks) data[:impact] ||= 0.5 data[:impact] = 1.0 if data[:impact] > 1.0 data[:impact] = 0.0 if data[:impact] < 0.0 - [id, data] + data[:id] = id + data + end.compact + + # resolve hash structure in groups + res[:groups] = res[:groups].map do |id, group| + group[:id] = id + group end - res[:controls] = Hash[controls.compact] # add information about the required attributes res[:attributes] = res[:attributes].map(&:to_hash) unless res[:attributes].nil? || res[:attributes].empty? res end @@ -327,17 +373,17 @@ # to disk, it must be explicitly written to disk by the caller. # # @param vendor_path [String] Path to the on-disk vendor dir # @return [Inspec::Lockfile] # - def generate_lockfile(vendor_path = nil) - res = Inspec::DependencySet.new(cwd, vendor_path, nil, @backend) + def generate_lockfile + res = Inspec::DependencySet.new(cwd, @cache, nil, @backend) res.vendor(metadata.dependencies) Inspec::Lockfile.from_dependency_set(res) end def load_dependencies - Inspec::DependencySet.from_lockfile(lockfile, cwd, nil, @backend) + Inspec::DependencySet.from_lockfile(lockfile, cwd, @cache, @backend) end private # Create an archive name for this profile and an additional options