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