add sha256 checksum to json

Fixes https://github.com/chef/inspec/issues/1658

Signed-off-by: Dominik Richter <dominik.richter@gmail.com>
This commit is contained in:
Dominik Richter 2017-05-10 15:16:40 +02:00
parent 9e1ddfb422
commit d44b751603
6 changed files with 53 additions and 9 deletions

View file

@ -11,10 +11,11 @@ module Inspec
# Extract metadata.rb information # Extract metadata.rb information
class Metadata # rubocop:disable Metrics/ClassLength class Metadata # rubocop:disable Metrics/ClassLength
attr_reader :ref attr_reader :ref
attr_accessor :params attr_accessor :params, :content
def initialize(ref, logger = nil) def initialize(ref, logger = nil)
@ref = ref @ref = ref
@logger = logger || Logger.new(nil) @logger = logger || Logger.new(nil)
@content = ''
@params = {} @params = {}
@missing_methods = [] @missing_methods = []
end end
@ -206,26 +207,28 @@ module Inspec
metadata metadata
end end
def self.from_yaml(ref, contents, profile_id, logger = nil) def self.from_yaml(ref, content, profile_id, logger = nil)
res = Metadata.new(ref, logger) res = Metadata.new(ref, logger)
res.params = YAML.load(contents) res.params = YAML.load(content)
res.content = content
finalize(res, profile_id, {}, logger) finalize(res, profile_id, {}, logger)
end end
def self.from_ruby(ref, contents, profile_id, logger = nil) def self.from_ruby(ref, content, profile_id, logger = nil)
res = Metadata.new(ref, logger) res = Metadata.new(ref, logger)
res.instance_eval(contents, ref, 1) res.instance_eval(content, ref, 1)
res.content = content
finalize(res, profile_id, {}, logger) finalize(res, profile_id, {}, logger)
end end
def self.from_ref(ref, contents, profile_id, logger = nil) def self.from_ref(ref, content, profile_id, logger = nil)
# NOTE there doesn't have to exist an actual file, it may come from an # NOTE there doesn't have to exist an actual file, it may come from an
# archive (i.e., contents) # archive (i.e., content)
case File.basename(ref) case File.basename(ref)
when 'inspec.yml' when 'inspec.yml'
from_yaml(ref, contents, profile_id, logger) from_yaml(ref, content, profile_id, logger)
when 'metadata.rb' when 'metadata.rb'
from_ruby(ref, contents, profile_id, logger) from_ruby(ref, content, profile_id, logger)
else else
logger ||= Logger.new(nil) logger ||= Logger.new(nil)
logger.error "Don't know how to handle metadata in #{ref}" logger.error "Don't know how to handle metadata in #{ref}"

View file

@ -4,6 +4,7 @@
# author: Christoph Hartmann # author: Christoph Hartmann
require 'forwardable' require 'forwardable'
require 'digest'
require 'inspec/polyfill' require 'inspec/polyfill'
require 'inspec/cached_fetcher' require 'inspec/cached_fetcher'
require 'inspec/file_provider' require 'inspec/file_provider'
@ -208,6 +209,7 @@ module Inspec
# add information about the required attributes # add information about the required attributes
res[:attributes] = res[:attributes].map(&:to_hash) unless res[:attributes].nil? || res[:attributes].empty? res[:attributes] = res[:attributes].map(&:to_hash) unless res[:attributes].nil? || res[:attributes].empty?
res[:sha256] = sha256
res res
end end
@ -395,6 +397,26 @@ module Inspec
Inspec::DependencySet.from_lockfile(lockfile, cwd, @cache, @backend, { attributes: @attr_values }) Inspec::DependencySet.from_lockfile(lockfile, cwd, @cache, @backend, { attributes: @attr_values })
end end
# Calculate this profile's SHA256 checksum. Includes metadata, dependencies,
# libraries, data files, and controls.
#
# @return [Type] description of returned object
def sha256
# get all dependency checksums
deps = Hash[locked_dependencies.list.map { |k, v| [k, v.profile.sha256] }]
res = Digest::SHA256.new
files = source_reader.tests.to_a + source_reader.libraries.to_a +
source_reader.data_files.to_a +
[['inspec.yml', source_reader.metadata.content]] +
[['inspec.lock.deps', YAML.dump(deps)]]
files.sort { |a, b| a[0] <=> b[0] }
.map { |f| res << f[0] << "\0" << f[1] << "\0" }
res.hexdigest
end
private private
# Create an archive name for this profile and an additional options # Create an archive name for this profile and an additional options

View file

@ -94,6 +94,7 @@ module Inspec
'properties' => { 'properties' => {
'name' => { 'type' => 'string' }, 'name' => { 'type' => 'string' },
'version' => { 'type' => 'string', 'optional' => true }, 'version' => { 'type' => 'string', 'optional' => true },
'sha256' => { 'type' => 'string', 'optional' => false },
'title' => { 'type' => 'string', 'optional' => true }, 'title' => { 'type' => 'string', 'optional' => true },
'maintainer' => { 'type' => 'string', 'optional' => true }, 'maintainer' => { 'type' => 'string', 'optional' => true },

View file

@ -58,6 +58,7 @@ describe 'inspec exec with json formatter' do
"license" => "Apache 2 license", "license" => "Apache 2 license",
"summary" => "Demonstrates the use of InSpec Compliance Profile", "summary" => "Demonstrates the use of InSpec Compliance Profile",
"version" => "1.0.0", "version" => "1.0.0",
"sha256" => "dc106310cc44b877b6ebf4fae786fb6d0b88bc2660e36b360e8ef28cae8fbfc5",
"supports" => [{"os-family" => "unix"}], "supports" => [{"os-family" => "unix"}],
"attributes" => [] "attributes" => []
}) })

View file

@ -20,6 +20,13 @@ describe 'metadata with supported operating systems' do
describe 'running on ubuntu 14.04' do describe 'running on ubuntu 14.04' do
let (:backend) { MockLoader.new(:ubuntu1404).backend } let (:backend) { MockLoader.new(:ubuntu1404).backend }
it 'provides all metadata content' do
s = "---\nname: hello #{rand}"
res = Inspec::Metadata.from_yaml('mock', s, nil)
Inspec::Metadata.finalize(res, 'mock', empty_options)
res.content.must_equal(s)
end
it 'finalizes a loaded metadata via Profile ID' do it 'finalizes a loaded metadata via Profile ID' do
res = Inspec::Metadata.from_yaml('mock', '---', nil) res = Inspec::Metadata.from_yaml('mock', '---', nil)
Inspec::Metadata.finalize(res, 'mock', empty_options) Inspec::Metadata.finalize(res, 'mock', empty_options)

View file

@ -64,6 +64,16 @@ describe Inspec::Profile do
end end
end end
describe 'SHA256 sums' do
it 'works on an empty profile' do
MockLoader.load_profile('empty-metadata').sha256.must_equal 'ee95f4cf4258402604d4cc581a672bbd2f73d212b09cd4bcf1c5984e97e68963'
end
it 'works on a complete profile' do
MockLoader.load_profile('complete-profile').sha256.must_equal '41ce15e61b7e02aad5dade183f68c547e062f1390762d266c5c8cf96d49134c7'
end
end
describe 'when checking' do describe 'when checking' do
describe 'an empty profile' do describe 'an empty profile' do
let(:profile_id) { 'empty-metadata' } let(:profile_id) { 'empty-metadata' }