Get unit and functional tests passing

Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
Clinton Wolfe 2019-03-07 13:52:03 -05:00
parent 502cf1d7b9
commit 7d2028287c
28 changed files with 235 additions and 349 deletions

View file

@ -26,8 +26,23 @@ module Inspec
with_resource_dsl resources_dsl
# allow attributes to be accessed within control blocks
define_method :attribute do |name|
Inspec::InputRegistry.find_input(name, profile_id).value
# TODO: deprecate name, use input()
define_method :attribute do |input_name, options = {}|
if options.empty?
# Simply an access, no event here
Inspec::InputRegistry.find_or_register_input(input_name, profile_id).value
else
options[:priority] = 20
options[:provider] = :inline_control_code
evt = Inspec::Input.infer_event(options)
Inspec::InputRegistry.find_or_register_input(input_name, profile_name, event: evt).value
end
end
# Find the Input object, but don't collapse to a value.
# Will return nil on a miss.
define_method :input_object do |input_name|
Inspec::InputRegistry.find_or_register_input(input_name, profile_id)
end
# Support for Control DSL plugins.
@ -169,14 +184,24 @@ module Inspec
# method for inputs; import input handling
# TODO: deprecate name, use input()
define_method :attribute do |name, options = nil|
if options.nil?
Inspec::InputRegistry.find_input(name, profile_id).value
define_method :attribute do |input_name, options = {}|
if options.empty?
# Simply an access, no event here
Inspec::InputRegistry.find_or_register_input(input_name, profile_id).value
else
Inspec::InputRegistry.register_input(name, profile_id, options).value
options[:priority] = 20
options[:provider] = :inline_control_code
evt = Inspec::Input.infer_event(options)
Inspec::InputRegistry.find_or_register_input(input_name, profile_name, event: evt).value
end
end
# Find the Input object, but don't collapse to a value.
# Will return nil on a miss.
define_method :input_object do |input_name|
Inspec::InputRegistry.find_or_register_input(input_name, profile_id)
end
define_method :skip_control do |id|
profile_context_owner.unregister_rule(id)
end

View file

@ -118,6 +118,7 @@ module Inspec
return @profile unless @profile.nil?
opts = @opts.dup
opts[:backend] = @backend
opts[:runner_conf] = Inspec::Config.cached
if !@dependencies.nil? && !@dependencies.empty?
opts[:dependencies] = Inspec::DependencySet.from_array(@dependencies, @cwd, @cache, @backend)
end

View file

@ -23,6 +23,7 @@ module Inspec
# implementation of the fetcher being used.
#
class Resolver
# Here deps is an Array of Hashes
def self.resolve(dependencies, cache, working_dir, backend)
reqs = dependencies.map do |dep|
req = Inspec::Requirement.from_metadata(dep, cache, cwd: working_dir, backend: backend)
@ -47,6 +48,7 @@ module Inspec
end
end
# Here deps is an Array of Inspec::Requirement
def resolve(deps, top_level = true, seen_items = {}, path_string = '') # rubocop:disable Metrics/AbcSize
graph = {}
if top_level

View file

@ -79,7 +79,7 @@ module Inspec::DSL
def self.filter_included_controls(context, profile, &block)
mock = Inspec::Backend.create(Inspec::Config.mock)
include_ctx = Inspec::ProfileContext.for_profile(profile, mock, {})
include_ctx = Inspec::ProfileContext.for_profile(profile, mock)
include_ctx.load(block) if block_given?
# remove all rules that were not registered
context.all_rules.each do |r|

View file

@ -12,11 +12,12 @@ module Inspec
include Singleton
extend Forwardable
attr_reader :inputs_by_profile
attr_reader :inputs_by_profile, :profile_aliases
def_delegator :inputs_by_profile, :each
def_delegator :inputs_by_profile, :[]
def_delegator :inputs_by_profile, :key?, :profile_known?
def_delegator :inputs_by_profile, :select
def_delegator :profile_aliases, :key?, :profile_alias?
def initialize
# Keyed on String profile_name => Hash of String input_name => Input object
@ -43,35 +44,44 @@ module Inspec
# Support for Individual Inputs
#-------------------------------------------------------------#
def find_input(name, profile)
profile = @profile_aliases[profile] if !profile_known?(profile) && @profile_aliases[profile]
unless profile_known?(profile)
error = Inspec::InputRegistry::ProfileLookupError.new
error.profile_name = profile
raise error, "Profile '#{error.profile_name}' does not have any inputs"
def find_or_register_input(input_name, profile_name, options = {})
if profile_alias?(profile_name)
alias_name = profile_name
profile_name = profile_aliases[profile_name]
handle_late_arriving_alias(alias_name, profile_name) if profile_known?(alias_name)
end
unless inputs_by_profile[profile].key?(name)
error = Inspec::InputRegistry::InputLookupError.new
error.input_name = name
error.profile_name = profile
raise error, "Profile '#{error.profile_name}' does not have an input with name '#{error.input_name}'"
end
inputs_by_profile[profile][name]
end
def register_input(input_name, profile_name, options = {})
if profile_known?(profile_name) && inputs_by_profile[profile_name][input_name] && options.empty?
# Just accessing the input - then why did they call register???
# TODO: handle the "declaration" case better
inputs_by_profile[profile_name][input_name]
inputs_by_profile[profile_name] ||= {}
if inputs_by_profile[profile_name].key?(input_name)
inputs_by_profile[profile_name][input_name].update(options)
else
inputs_by_profile[profile_name] = {} unless profile_known?(profile_name)
# BUG: This a clobbering operation, regardless of precendence!
inputs_by_profile[profile_name][input_name] = Inspec::Input.new(input_name, options)
end
inputs_by_profile[profile_name][input_name]
end
# It is possible for a wrapper profile to create an input in metadata,
# referring to the child profile by an alias that has not yet been registered.
# The registry will then store the inputs under the alias, as if the alias
# were a true profile.
# If that happens and the child profile also mentions the input, we will
# need to move some things - all inputs should be stored under the true
# profile name, and no inputs should be stored under the alias.
def handle_late_arriving_alias(alias_name, profile_name)
inputs_by_profile[profile_name] ||= {}
inputs_by_profile[alias_name].each do |input_name, input_from_alias|
# Move the inpuut, or if it exists, merge events
existing = inputs_by_profile[profile_name][input_name]
if existing
existing.events.concat(input_from_alias.events)
else
inputs_by_profile[profile_name][input_name] = input_from_alias
end
end
# Finally, delete the (now copied-out) entry for the alias
inputs_by_profile.delete(alias_name)
end
#-------------------------------------------------------------#
# Support for Binding Inputs
#-------------------------------------------------------------#
@ -84,7 +94,7 @@ module Inspec
# In a more perfect world, we could let the core plugins choose
# self-determine what to do; but as-is, the APIs that call this
# are a bit over-constrained.
bind_inputs_from_metadata(profile_name, sources[:metadata])
bind_inputs_from_metadata(profile_name, sources[:profile_metadata])
bind_inputs_from_input_files(profile_name, sources[:cli_input_files])
bind_inputs_from_runner_api(profile_name, sources[:runner_api])
end
@ -99,8 +109,15 @@ module Inspec
# These arrive as a bare hash - values are raw values, not options
input_hash.each do |input_name, input_value|
input_options = { value: input_value }
register_input(input_name, profile_name, input_options)
loc = Inspec::Input::Event.probe_stack # TODO: likely modify this to look for a kitchen.yml, if that is realistic
evt = Inspec::Input::Event.new(
value: input_value,
provider: :runner_api, # TODO: suss out if audit cookbook or kitchen-inspec or something unknown
priority: 40,
file: loc.path,
line: loc.lineno,
)
find_or_register_input(input_name, profile_name, event: evt)
end
end
@ -123,8 +140,14 @@ module Inspec
next if data.inputs.nil?
data.inputs.each do |input_name, input_value|
input_options = { value: input_value }
register_input(input_name, profile_name, input_options)
evt = Inspec::Input::Event.new(
value: input_value,
provider: :cli_files,
priority: 40,
file: path,
# TODO: any way we could get a line number?
)
find_or_register_input(input_name, profile_name, event: evt)
end
end
end
@ -151,10 +174,23 @@ module Inspec
return if profile_metadata_obj.nil? # Metadata files are technically optional
if profile_metadata_obj.params.key?(:attributes) && profile_metadata_obj.params[:attributes].is_a?(Array)
profile_metadata_obj.params[:attributes].each do |input|
input_options = input.dup
profile_metadata_obj.params[:attributes].each do |input_orig|
input_options = input_orig.dup
input_name = input_options.delete(:name)
register_input(input_name, profile_name, input_options)
input_options.merge!({ priority: 30, provider: :profile_metadata, file: File.join(profile_name, 'inspec.yml') })
evt = Inspec::Input.infer_event(input_options)
# Profile metadata may set inputs in other profiles by naming them.
if input_options[:profile]
profile_name = input_options[:profile] || profile_name
# Override priority to force this to win. Allow user to set their own priority.
evt.priority = input_orig[:priority] || 35
end
find_or_register_input(input_name,
profile_name,
type: input_options[:type],
required: input_options[:required],
event: evt)
end
elsif profile_metadata_obj.params.key?(:attributes)
Inspec::Log.warn 'Inputs must be defined as an Array. Skipping current definition.'
@ -175,8 +211,7 @@ module Inspec
# These class methods are convenience methods so you don't always
# have to call #instance when calling the registry
[
:find_input,
:register_input,
:find_or_register_input,
:register_profile_alias,
:list_inputs_for_profile,
:bind_profile_inputs,

View file

@ -70,6 +70,12 @@ module Inspec
hash[prop] = send(prop)
end
end
def self.probe_stack
frames = caller_locations(2, 40)
frames.reject! { |f| f.path && f.path.include?('/lib/inspec/') }
frames.first
end
end
#===========================================================================#
@ -197,7 +203,7 @@ module Inspec
Inspec::Log.warn "Do not provide both an Event and a value as an option to attribute('#{name}') - using value from event"
end
else
infer_event(options) # Sets options[:event]
self.class.infer_event(options) # Sets options[:event]
end
end
events << options[:event] if options.key? :event
@ -205,44 +211,17 @@ module Inspec
enforce_type_restriction!
end
private
def _update_set_metadata(options)
# Basic metadata
@title = options[:title] if options.key?(:title)
@description = options[:description] if options.key?(:description)
@required = options[:required] if options.key?(:required)
@identifier = options[:identifier] if options.key?(:identifier) # TODO: determine if this is ever used
@type = options[:type] if options.key?(:type)
end
def make_creation_event(options)
loc = options[:location] || probe_stack
Input::Event.new(
action: :create,
provider: options[:provider],
file: loc.path,
line: loc.lineno,
)
end
def probe_stack
frames = caller_locations(2, 40)
frames.reject! { |f| f.path && f.path.include?('/lib/inspec/') }
frames.first
end
# We can determine a value:
# 1. By event.value (preferred)
# 2. By options[:value]
# 3. By options[:default] (deprecated)
def infer_event(options)
def self.infer_event(options)
# Don't rely on this working; you really should be passing a proper Input::Event
# with the context information you have.
location = probe_stack
location = Input::Event.probe_stack
event = Input::Event.new(
action: :set,
provider: :unknown,
provider: options[:provider] || :unknown,
priority: options[:priority] || Inspec::Input::DEFAULT_PRIORITY_FOR_UNKNOWN_CALLER,
file: location.path,
line: location.lineno,
@ -261,6 +240,27 @@ module Inspec
options[:event] = event
end
private
def _update_set_metadata(options)
# Basic metadata
@title = options[:title] if options.key?(:title)
@description = options[:description] if options.key?(:description)
@required = options[:required] if options.key?(:required)
@identifier = options[:identifier] if options.key?(:identifier) # TODO: determine if this is ever used
@type = options[:type] if options.key?(:type)
end
def make_creation_event(options)
loc = options[:location] || Event.probe_stack
Input::Event.new(
action: :create,
provider: options[:provider],
file: loc.path,
line: loc.lineno,
)
end
# Determine the current winning value, but don't validate it
def current_value
# Examine the events to determine highest-priority value. Tie-break
@ -282,7 +282,7 @@ module Inspec
def value=(new_value, priority = DEFAULT_PRIORITY_FOR_VALUE_SET)
# Inject a new Event with the new value.
location = probe_stack
location = Event.probe_stack
events << Event.new(
action: :set,
provider: :value_setter,

View file

@ -121,14 +121,15 @@ module Inspec
# The AttributeRegistry is in charge of keeping track of inputs;
# it is the single source of truth. Now that we have a profile object,
# we can create any inputs that were provided by various mechanisms.
options[:runner_conf] ||= Inspec::Config.cached
Inspec::InputRegistry.bind_profile_inputs(
# Every input only exists in the context of a profile
metadata.params[:name], # TODO: test this with profile aliasing
# Remaining args are possible sources of inputs
# TODO: deprecation checks throughout
cli_input_files: options[:runner_conf].final_options[:attrs], # From --attrs
cli_input_files: options[:runner_conf][:attrs], # From --attrs
profile_metadata: metadata,
runner_api: options[:runner_conf].final_options[:attributes], # This is the route the audit_cookbook and kitchen-inspec take
runner_api: options[:runner_conf][:attributes], # This is the route the audit_cookbook and kitchen-inspec take
)
@runner_context =

View file

@ -66,9 +66,13 @@ end
class RSpec::Core::ExampleGroup
# This DSL method allows us to access the values of inputs within InSpec tests
def attribute(name)
Inspec::InputRegistry.find_input(name, self.class.metadata[:profile_id]).value
Inspec::InputRegistry.find_or_register_input(name, self.class.metadata[:profile_id]).value
end
define_example_method :attribute
def input_obj(name)
Inspec::InputRegistry.find_or_register_input(name, self.class.metadata[:profile_id])
end
define_example_method :input_obj
# Here, we have to ensure our method_missing gets called prior
# to RSpec::Core::ExampleGroup.method_missing (the class method).

View file

@ -5,9 +5,12 @@ require 'functional/helper'
describe 'inputs' do
include FunctionalHelper
let(:inputs_profiles_path) { File.join(profile_path, 'inputs') }
# This tests being able to load complex structures from
# cli option-specified files.
[
'flat',
#'nested',
'nested',
].each do |input_file|
it "runs OK on #{input_file} inputs" do
cmd = 'exec '
@ -58,28 +61,21 @@ describe 'inputs' do
end
end
describe 'run profile with yaml inputs' do
it "runs using yml inputs" do
describe 'when accessing inputs in a variety of scopes' do
it "is able to read the inputs" do
cmd = 'exec '
cmd += File.join(inputs_profiles_path, 'global')
cmd += ' --no-create-lockfile'
cmd += ' --input-file ' + File.join(inputs_profiles_path, 'global', 'files', "inputs.yml")
out = inspec(cmd)
out.stderr.must_equal ''
# TODO: fix attribute inheritance override test
# we have one failing case on this - run manually to see
# For now, reduce cases to 20; we'll be reworking all this soon anyway
# result.stdout.must_include '21 successful'
# result.exit_status.must_equal 0
result.stdout.must_include '20 successful' # and one failing
cmd += File.join(inputs_profiles_path, 'scoping')
result = run_inspec_process(cmd, json: true)
result.must_have_all_controls_passing
end
end
describe 'run profile with metadata inputs' do
it "does not error when inputs are empty" do
cmd = 'exec '
cmd += File.join(inputs_profiles_path, 'metadata-empty')
result = run_inspec_process(cmd, json: true)
result.stdout.must_include 'WARN: Inputs must be defined as an Array. Skipping current definition.'
result.stderr.must_include 'WARN: Inputs must be defined as an Array. Skipping current definition.'
result.exit_status.must_equal 0
end
@ -88,19 +84,26 @@ describe 'inputs' do
cmd += File.join(inputs_profiles_path, 'metadata-invalid')
result = run_inspec_process(cmd, json: true)
result.stderr.must_equal "Type 'Color' is not a valid input type.\n"
result.stdout.must_equal ''
result.exit_status.must_equal 1
end
it "errors with required input not defined" do
cmd = 'exec '
cmd += File.join(inputs_profiles_path, 'required')
cmd += File.join(inputs_profiles_path, 'metadata-required')
result = run_inspec_process(cmd, json: true)
result.stderr.must_equal "Input 'username' is required and does not have a value.\n"
result.stdout.must_equal ''
result.stderr.must_include "Input 'a_required_input' is required and does not have a value.\n"
result.exit_status.must_equal 1
end
# TODO - add test for backwards compatibility using 'attribute' in DSL
describe 'when profile inheritance is used' do
it 'should correctly assign input values using namespacing' do
cmd = 'exec ' + File.join(inputs_profiles_path, 'inheritance', 'wrapper')
result = run_inspec_process(cmd, json: true)
result.must_have_all_controls_passing
end
end
# # TODO - add test for backwards compatibility using 'attribute' in DSL
end
end

View file

@ -13,60 +13,48 @@ describe Inspec::InputRegistry do
describe 'creating a profile input' do
it 'creates an input without options' do
registry.register_input('test_input', 'dummy_profile')
# confirm we get the dummy default
registry.find_input('test_input', 'dummy_profile').value.class.must_equal Inspec::Input::NO_VALUE_SET
registry.find_or_register_input('test_input', 'dummy_profile')
# confirm we get the dummy value
registry.find_or_register_input('test_input', 'dummy_profile').value.class.must_equal Inspec::Input::NO_VALUE_SET
end
it 'creates an input with a default value' do
registry.register_input('color', 'dummy_profile', default: 'silver')
registry.find_input('color', 'dummy_profile').value.must_equal 'silver'
it 'creates an input with a value' do
registry.find_or_register_input('color', 'dummy_profile', value: 'silver')
registry.find_or_register_input('color', 'dummy_profile').value.must_equal 'silver'
end
end
describe 'creating a profile with a name alias' do
it 'creates a default input on a profile with an alias' do
it 'creates a value input on a profile with an alias' do
registry.register_profile_alias('old_profile', 'new_profile')
registry.register_input('color', 'new_profile', default: 'blue')
registry.find_input('color', 'new_profile').value.must_equal 'blue'
registry.find_input('color', 'old_profile').value.must_equal 'blue'
registry.find_or_register_input('color', 'new_profile', value: 'blue')
registry.find_or_register_input('color', 'new_profile').value.must_equal 'blue'
registry.find_or_register_input('color', 'old_profile').value.must_equal 'blue'
end
end
describe 'creating a profile and select it' do
it 'creates a profile with inputs' do
registry.register_input('color', 'dummy_profile', default: 'silver')
registry.register_input('color2', 'dummy_profile', default: 'blue')
registry.register_input('color3', 'dummy_profile', default: 'green')
registry.find_or_register_input('color', 'dummy_profile', value: 'silver')
registry.find_or_register_input('color2', 'dummy_profile', value: 'blue')
registry.find_or_register_input('color3', 'dummy_profile', value: 'green')
registry.list_inputs_for_profile('dummy_profile').size.must_equal 3
end
end
describe 'validate the correct objects are getting created' do
it 'creates a profile with inputs' do
registry.register_input('color', 'dummy_profile', default: 'silver').class.must_equal Inspec::Input
registry.find_or_register_input('color', 'dummy_profile', value: 'silver').class.must_equal Inspec::Input
registry.list_inputs_for_profile('dummy_profile').size.must_equal 1
end
end
describe 'validate find_input method' do
describe 'validate find_or_register_input method' do
it 'find an input which exist' do
input = registry.register_input('color', 'dummy_profile')
input = registry.find_or_register_input('color', 'dummy_profile')
input.value = 'black'
registry.find_input('color', 'dummy_profile').value.must_equal 'black'
end
it 'errors when trying to find an input on an unknown profile' do
input = registry.register_input('color', 'dummy_profile')
ex = assert_raises(Inspec::InputRegistry::ProfileLookupError) { registry.find_input('color', 'unknown_profile') }
ex.message.must_match "Profile 'unknown_profile' does not have any inputs"
end
it 'errors when trying to find an unknown input on a known profile' do
input = registry.register_input('color', 'dummy_profile')
ex = assert_raises(Inspec::InputRegistry::InputLookupError) { registry.find_input('unknown_input', 'dummy_profile') }
ex.message.must_match "Profile 'dummy_profile' does not have an input with name 'unknown_input'"
registry.find_or_register_input('color', 'dummy_profile').value.must_equal 'black'
end
end

View file

@ -11,7 +11,6 @@ tests = expecteds.keys.map do |test_name|
name: test_name,
expected: expecteds[test_name],
input_via_string: attribute(test_name.to_s, value: "#{test_name}_default"),
input_via_symbol: attribute(test_name, value: "#{test_name}_default"),
}
end

View file

@ -1,47 +0,0 @@
describe 'test the val_string input set in the global inspec.yml' do
subject { attribute('val_string') }
it { should cmp 'test-attr' }
end
describe 'test the val_numeric input set in the global inspec.yml' do
subject { attribute('val_numeric') }
it { should cmp 443 }
end
describe 'test the val_boolean input set in the global inspec.yml' do
subject { attribute('val_boolean') }
it { should cmp true }
end
describe 'test the val_regex input set in the global inspec.yml' do
subject { attribute('val_regex') }
it { should cmp '/^\d*/'}
end
describe 'test the val_array input set in the global inspec.yml' do
subject { attribute('val_array') }
check_array = [ 'a', 'b', 'c' ]
it { should cmp check_array }
end
describe 'test the val_hash input set in the global inspec.yml' do
subject { attribute('val_hash') }
check_hash = { a: true, b: false, c: '123' }
it { should cmp check_hash }
end
describe 'test input when no default or value is set' do
subject { attribute('val_no_default').respond_to?(:fake_method) }
it { should cmp true }
end
describe 'test input with no defualt but has type' do
subject { attribute('val_no_default_with_type').respond_to?(:fake_method) }
it { should cmp true }
end
empty_hash_input = attribute('val_with_empty_hash_default', {})
describe 'test input with default as empty hash' do
subject { empty_hash_input }
it { should cmp 'success' }
end

View file

@ -1,15 +0,0 @@
include_controls 'child_profile_NEW_NAME'
include_controls 'child_profile2' do
control 'test override control on parent using child attribute' do
describe attribute('val_numeric') do
it { should cmp 654321 }
end
end
control 'test override control on parent using parent attribute' do
describe Inspec::InputRegistry.find_input('val_numeric', 'inputs').value do
it { should cmp 443 }
end
end
end

View file

@ -1,6 +0,0 @@
control 'test using the val_numeric_override with a default in the inspec.yml overridden by the secrets file' do
desc 'test the val_numeric_override attr'
describe attribute('val_numeric_override') do
it { should cmp 9999 }
end
end

View file

@ -1,31 +0,0 @@
val_user = attribute('val_user', default: 'alice', description: 'An identification for the user')
val_user_override = attribute('val_user_override', default: 'alice', description: 'An identification for the user')
describe 'reading an input in a file-level definition with a default value' do
subject { val_user }
it { should cmp 'alice' }
end
describe 'reading an input in a file-level definition with a default value and a value in secrets file' do
subject { val_user_override }
it { should cmp 'bob' }
end
control 'test using an input inside a control block as the describe subject' do
desc 'test the val_numeric attr'
describe attribute('val_user') do
it { should cmp 'alice' }
end
end
# test using a input outside controls and as the describe subject
describe attribute('val_user') do
it { should cmp 'alice' }
end
control "test using inputs in the test it's block" do
describe 'alice' do
it { should cmp attribute('val_user') }
end
end

View file

@ -1,3 +0,0 @@
val_user_override: bob
val_numeric_override: 9999
val_with_empty_hash_default: 'success'

View file

@ -1,13 +0,0 @@
---
lockfile_version: 1
depends:
- name: child_profile_NEW_NAME
resolved_source:
url: https://example.com/child_profile.tar.gz
sha256: e39eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477
version_constraints: ">= 0"
- name: child_profile2
resolved_source:
url: https://example.com/child_profile2.tar.gz
sha256: f24eb85366b272bae98e5eecdfac9f84c50a9ae9dd625fba2ce847268a6c3477
version_constraints: ">= 0"

View file

@ -1,43 +0,0 @@
name: global-inputs
title: Profile to test inputs in a variety of locations
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.1.0
depends:
- name: child_profile_NEW_NAME
url: https://example.com/child_profile.tar.gz
- url: https://example.com/child_profile2.tar.gz
attributes:
- name: val_numeric
type: numeric
default: 443
- name: val_numeric_override
type: numeric
default: '72.88'
- name: val_string
type: string
default: 'test-attr'
- name: val_boolean
type: boolean
default: true
- name: val_regex
type: regex
default: '/^\d*/'
- name: val_array
type: array
default:
- a
- b
- c
- name: val_hash
type: hash
default:
a: true
b: false
c: '123'
- name: val_no_default
- name: val_no_default_with_type
type: hash

View file

@ -1,4 +0,0 @@
# Demo Compliance Profile
copyright: Demo Company Ltd
license: All rights reserved

View file

@ -1,10 +0,0 @@
describe 'test child attribute when using a profile with a name override' do
subject { attribute('val_numeric') }
it { should cmp '123456' }
end
control 'test child attribute inside a it block when using a profile with a name override' do
describe '123456' do
it { should cmp attribute('val_numeric') }
end
end

View file

@ -1,12 +0,0 @@
name: child_profile
title: Child Profile
maintainer: Demo, Inc.
copyright: Demo, Inc.
copyright_email: support@example.com
license: Apache-2.0
summary: My Profile 1 summary
version: 1.0.0
attributes:
- name: val_numeric
type: numeric
default: 123456

View file

@ -1,4 +0,0 @@
# Demo Compliance Profile
copyright: Demo Company Ltd
license: All rights reserved

View file

@ -1,22 +0,0 @@
describe 'test child attribute when using a profile without a name override' do
subject { attribute('val_numeric') }
it { should cmp 654321 }
end
control 'test override control on parent using child attribute' do
describe 'dummy' do
it { should cmp 9999 }
end
end
control 'test override control on parent using parent attribute' do
describe 'dummy' do
it { should cmp 9999 }
end
end
control 'test child attribute inside a it block when using a profile without a name override' do
describe '654321' do
it { should cmp attribute('val_numeric') }
end
end

View file

@ -1,12 +0,0 @@
name: child_profile2
title: Child Profile2
maintainer: Demo, Inc.
copyright: Demo, Inc.
copyright_email: support@example.com
license: Apache-2.0
summary: My Profile 1 summary
version: 1.0.0
attributes:
- name: val_numeric
type: numeric
default: 654321

View file

@ -0,0 +1 @@
attribute('a_required_input')

View file

@ -7,6 +7,6 @@ license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.1.0
attributes:
- name: username
- name: a_required_input
type: string
required: true

View file

@ -0,0 +1,29 @@
# This should simply not error
unless attribute('test-01') == 'test-01'
raise 'Failed bare input access'
end
describe attribute('test-02') do
it { should cmp 'test-02' }
end
describe 'mentioning an input in a bare describe block as a redirected subject' do
subject { attribute('test-03') }
it { should cmp 'test-03' }
end
control 'test using an input inside a control block as the describe subject' do
desc 'test the val_numeric attr'
describe attribute('test-04') do
it { should cmp 'test-04' }
end
end
control "test using inputs in the test its block" do
describe 'test-05' do
it { should cmp attribute('test-05') }
end
end
# TODO: add test for OR

View file

@ -0,0 +1,20 @@
name: input-scoping
title: Profile to test reading attributes in a variety of scopes
maintainer: Chef InSpec team
copyright: Chef InSpec team
copyright_email: inspec@chef.io
license: Apache-2.0
summary: Profile to test reading attributes in a variety of scopes
version: 0.1.0
attributes:
- name: test-01
value: test-01
- name: test-02
value: test-02
- name: test-03
value: test-03
- name: test-04
value: test-04
- name: test-05
value: test-05