inspec 0.17.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 92931c330ebe81c9d87899956cec70d7c395854b
4
- data.tar.gz: 93b49fae335d4c153393eca778a0973a46bebb9f
3
+ metadata.gz: 5fcd7959abdb3de12c11854323ad29f484f0dbda
4
+ data.tar.gz: 79bbc6496cc71d18e02a9b05b4e6fbd3a5043315
5
5
  SHA512:
6
- metadata.gz: e78120e5ec5764f3a9a6ce35db482adf9a8304ba13dac930a181984ace5d5cb4e0b8898e9cf26f17e495a382df1acdfc7ce5f97042a7342302a6c6e5d20a2ca3
7
- data.tar.gz: 37bc84c9da07415c800a24af962008098c2b2f8711ac3c1f093ec09f3482a37c4aaa8ff531a52d51f9b9a8377d3485f9b2675c44a7d1bfa29a8d740b60c84130
6
+ metadata.gz: 4256867dac4a3a9978b4f5dfda36aba67f9d97461d9d074e694f048d51ae22cd2e835593524e5dcbcc9d3f87a34279cbcd295f6f66d0d372939c8daf5e73688f
7
+ data.tar.gz: c6cc148cae574dd9dce10ad9781cb9e088fff6c52fdde9f3b40463d7166689e23923b539ba077a4d224e3611f33b0fd7c3b2799e9308590516a6231f536a78cc
@@ -1,7 +1,24 @@
1
1
  # Change Log
2
2
 
3
- ## [0.17.1](https://github.com/chef/inspec/tree/0.17.1) (2016-03-31)
4
- [Full Changelog](https://github.com/chef/inspec/compare/v0.17.0...0.17.1)
3
+ ## [0.18.0](https://github.com/chef/inspec/tree/0.18.0) (2016-04-09)
4
+ [Full Changelog](https://github.com/chef/inspec/compare/v0.17.1...0.18.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - supports keyword marks tests as skipped instead of removing them [\#620](https://github.com/chef/inspec/pull/620) ([arlimus](https://github.com/arlimus))
9
+ - Support only\_if in controls [\#619](https://github.com/chef/inspec/pull/619) ([arlimus](https://github.com/arlimus))
10
+ - don't remove controls with only\_if [\#618](https://github.com/chef/inspec/pull/618) ([arlimus](https://github.com/arlimus))
11
+
12
+ **Merged pull requests:**
13
+
14
+ - Encourage sharing of profiles [\#625](https://github.com/chef/inspec/pull/625) ([nathenharvey](https://github.com/nathenharvey))
15
+ - add travis and appveyor badges [\#622](https://github.com/chef/inspec/pull/622) ([chris-rock](https://github.com/chris-rock))
16
+ - remove unused profile.tar.gz [\#621](https://github.com/chef/inspec/pull/621) ([chris-rock](https://github.com/chris-rock))
17
+ - Extended gordon\_config with more examples [\#610](https://github.com/chef/inspec/pull/610) ([alexpop](https://github.com/alexpop))
18
+ - Create ISSUE\_TEMPLATE [\#581](https://github.com/chef/inspec/pull/581) ([srenatus](https://github.com/srenatus))
19
+
20
+ ## [v0.17.1](https://github.com/chef/inspec/tree/v0.17.1) (2016-03-31)
21
+ [Full Changelog](https://github.com/chef/inspec/compare/v0.17.0...v0.17.1)
5
22
 
6
23
  **Merged pull requests:**
7
24
 
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # InSpec: Inspect Your Infrastructure
2
2
 
3
3
  [![Join the chat at https://gitter.im/chef/inspec](https://badges.gitter.im/chef/inspec.svg)](https://gitter.im/chef/inspec?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
+ [![Build Status Master](https://travis-ci.org/chef/inspec.svg?branch=master)](https://travis-ci.org/chef/inspec)
5
+ [![Build Status Master](https://ci.appveyor.com/api/projects/status/github/chef/inspec?branch=master&svg=true&passingText=master%20-%20Ok&pendingText=master%20-%20Pending&failingText=master%20-%20Failing)](https://ci.appveyor.com/project/Chef/inspec/branch/master)
4
6
 
5
7
  InSpec is an open-source testing framework for infrastructure with a human- and machine-readable language for specifying compliance, security and policy requirements.
6
8
 
@@ -169,6 +171,12 @@ Which will provide you with:
169
171
 
170
172
  Documentation is available: https://github.com/chef/inspec/tree/master/docs
171
173
 
174
+ ## Share your Profiles
175
+
176
+ You may share your InSpec Profiles in the [Tools & Plugins section](https://supermarket.chef.io/tools-directory) of the [Chef Supermarket](https://supermarket.chef.io/). [Sign in](https://supermarket.chef.io/sign-in) and [add the details of your profile](https://supermarket.chef.io/tools/new).
177
+
178
+ You may also [browse the Supermarket for shared Compliance Profiles](https://supermarket.chef.io/tools?type=compliance_profile).
179
+
172
180
  ## Kudos
173
181
 
174
182
  InSpec is inspired by the wonderful [Serverspec](http://serverspec.org) project. Kudos to [mizzy](https://github.com/mizzy) and [all contributors](https://github.com/mizzy/serverspec/graphs/contributors)!
@@ -12,7 +12,7 @@ Summary
12
12
  -------
13
13
  Location: examples/profile
14
14
  Profile: profile
15
- Controls: 3
15
+ Controls: 4
16
16
  Timestamp: 2016-03-24T16:20:21+00:00
17
17
  Valid: true
18
18
 
@@ -32,7 +32,7 @@ $ inspec exec examples/profile
32
32
  ..
33
33
 
34
34
  Finished in 0.0025 seconds (files took 0.12449 seconds to load)
35
- 4 examples, 0 failures
35
+ 8 examples, 0 failures
36
36
  ```
37
37
 
38
38
  ## Execute a specific control from a profile
@@ -18,8 +18,20 @@ control 'gordon-1.0' do
18
18
  tag 'gordon'
19
19
  ref 'Gordon Requirements 1.0', uri: 'http://...'
20
20
 
21
+ # Test using the custom gordon_config Inspec resource
22
+ # Find the resource content here: ../libraries/
21
23
  describe gordon_config do
24
+ it { should exist }
22
25
  its('version') { should eq('1.0') }
23
- its('size') { should <= 20 }
26
+ its('file_size') { should <= 20 }
27
+ its('comma_count') { should eq 0 }
28
+ end
29
+
30
+ # Test the version again to showcase variables
31
+ g = gordon_config
32
+ g_path = g.file_path
33
+ g_version = g.version
34
+ describe file(g_path) do
35
+ its('content') { should match g_version }
24
36
  end
25
37
  end
@@ -11,12 +11,13 @@ class GordonConfig < Inspec.resource(1)
11
11
  example "
12
12
  describe gordon_config do
13
13
  its('version') { should eq('1.0') }
14
- its('size') { should > 1 }
14
+ its('file_size') { should > 1 }
15
15
  end
16
16
  "
17
17
 
18
18
  # Load the configuration file on initialization
19
19
  def initialize
20
+ @params = {}
20
21
  @path = '/tmp/gordon/config.yaml'
21
22
  @file = inspec.file(@path)
22
23
  return skip_resource "Can't find file \"#{@path}\"" if !@file.file?
@@ -24,20 +25,29 @@ class GordonConfig < Inspec.resource(1)
24
25
  # Protect from invalid YAML content
25
26
  begin
26
27
  @params = YAML.load(@file.content)
28
+ # Add two extra matchers
29
+ @params['file_size'] = @file.size
30
+ @params['file_path'] = @path
31
+ @params['ruby'] = 'RUBY IS HERE TO HELP ME!'
27
32
  rescue Exception
28
33
  return skip_resource "#{@file}: #{$!}"
29
34
  end
30
- add_some_extra_params
31
35
  end
32
36
 
33
- # Extra Ruby helper method
34
- def add_some_extra_params
35
- @params['size'] = @file.size
36
- @params['md5sum'] = @file.md5sum
37
+ # Example method called by 'it { should exist }'
38
+ # Returns true or false from the 'File.exists?' method
39
+ def exists?
40
+ return File.exists?(@path)
41
+ end
42
+
43
+ # Example matcher for the number of commas in the file
44
+ def comma_count
45
+ text = @file.content
46
+ return text.count(',')
37
47
  end
38
48
 
39
49
  # Expose all parameters
40
50
  def method_missing(name)
41
- @params[name.to_s]
51
+ return @params[name.to_s]
42
52
  end
43
53
  end
@@ -35,7 +35,7 @@ module Inspec::DSL
35
35
  # let it run. This happens after everything
36
36
  # else is merged in.
37
37
  def self.execute_rule(r, profile_id)
38
- checks = r.instance_variable_get(:@checks)
38
+ checks = ::Inspec::Rule.prepare_checks(r)
39
39
  fid = InspecBaseRule.full_id(r, profile_id)
40
40
  checks.each do |m, a, b|
41
41
  # check if the resource is skippable and skipped
@@ -256,7 +256,7 @@ module Inspec
256
256
  impact: rule.impact,
257
257
  refs: rule.ref,
258
258
  tags: rule.tag,
259
- checks: rule.instance_variable_get(:@checks),
259
+ checks: Inspec::Rule.checks(rule),
260
260
  code: rule.instance_variable_get(:@__code),
261
261
  source_location: rule.instance_variable_get(:@__source_location),
262
262
  group_title: rule.instance_variable_get(:@__group_title),
@@ -102,6 +102,7 @@ module Inspec
102
102
  def initialize(backend, conf) # rubocop:disable Lint/NestedMethodDefinition, Lint/DuplicateMethods
103
103
  @backend = backend
104
104
  @conf = conf
105
+ @skip_profile = false
105
106
  end
106
107
 
107
108
  define_method :title do |arg|
@@ -115,20 +116,7 @@ module Inspec
115
116
  define_method :control do |*args, &block|
116
117
  id = args[0]
117
118
  opts = args[1] || {}
118
-
119
- # Skip the control if the resource triggered a skip;
120
- # However: when this is run on a mock backend, do not skip it.
121
- # This is e.g. relevant for JSON generation, where we need all
122
- # controls.
123
- return if @skip_profile && os[:family] != 'unknown'
124
-
125
- profile_context_owner.register_rule(rule_class.new(id, opts, &block))
126
- end
127
-
128
- alias_method :rule, :control
129
-
130
- define_method :register_control do |control|
131
- profile_context_owner.register_rule(control) unless control.nil?
119
+ register_control(rule_class.new(id, opts, &block))
132
120
  end
133
121
 
134
122
  define_method :describe do |*args, &block|
@@ -139,10 +127,16 @@ module Inspec
139
127
  rule = rule_class.new(id, {}) do
140
128
  res = describe(*args, &block)
141
129
  end
142
- profile_context_owner.register_rule(rule, &block)
130
+ register_control(rule, &block)
143
131
  res
144
132
  end
145
133
 
134
+ define_method :register_control do |control, &block|
135
+ ::Inspec::Rule.set_skip_rule(control, true) if @skip_profile
136
+
137
+ profile_context_owner.register_rule(control, &block) unless control.nil?
138
+ end
139
+
146
140
  # TODO: mock method for attributes; import attribute handling
147
141
  define_method :attributes do |_name, _options|
148
142
  nil
@@ -152,13 +146,14 @@ module Inspec
152
146
  profile_context_owner.unregister_rule(id)
153
147
  end
154
148
 
155
- alias_method :skip_rule, :skip_control
156
-
157
149
  def only_if
158
150
  return unless block_given?
159
- @skip_profile = !yield
151
+ @skip_profile ||= !yield
160
152
  end
161
153
 
154
+ alias_method :rule, :control
155
+ alias_method :skip_rule, :skip_control
156
+
162
157
  private
163
158
 
164
159
  def block_location(block, alternate_caller)
@@ -15,16 +15,19 @@ module Inspec
15
15
  def initialize(id, _opts, &block)
16
16
  @id = id
17
17
  @impact = nil
18
- @__block = block
19
- @__code = __get_block_source(&block)
20
- @__source_location = __get_block_source_location(&block)
21
18
  @title = nil
22
19
  @desc = nil
23
20
  @refs = []
24
21
  @tags = {}
22
+
25
23
  # not changeable by the user:
26
- @profile_id = nil
27
- @checks = []
24
+ @__block = block
25
+ @__code = __get_block_source(&block)
26
+ @__source_location = __get_block_source_location(&block)
27
+ @__rule_id = nil
28
+ @__checks = []
29
+ @__skip_rule = nil
30
+
28
31
  # evaluate the given definition
29
32
  instance_eval(&block) if block_given?
30
33
  end
@@ -70,6 +73,15 @@ module Inspec
70
73
  @tags
71
74
  end
72
75
 
76
+ # Skip all checks if only_if is false
77
+ #
78
+ # @param [Type] &block returns true if tests are added, false otherwise
79
+ # @return [nil]
80
+ def only_if
81
+ return unless block_given?
82
+ @__skip_rule ||= !yield
83
+ end
84
+
73
85
  # Describe will add one or more tests to this control. There is 2 ways
74
86
  # of calling it:
75
87
  #
@@ -87,25 +99,57 @@ module Inspec
87
99
  dsl = self.class.ancestors[1]
88
100
  Class.new(DescribeBase) do
89
101
  include dsl
90
- end.new(method(:add_check))
102
+ end.new(method(:__add_check))
91
103
  else
92
- add_check('describe', values, block)
104
+ __add_check('describe', values, block)
93
105
  end
94
106
  end
95
107
 
96
108
  def expect(value, &block)
97
109
  target = Inspec::Expect.new(value, &block)
98
- add_check('expect', [value], target)
110
+ __add_check('expect', [value], target)
99
111
  target
100
112
  end
101
113
 
114
+ def self.rule_id(rule)
115
+ rule.instance_variable_get(:@__rule_id)
116
+ end
117
+
118
+ def self.set_rule_id(rule, value)
119
+ rule.instance_variable_set(:@__rule_id, value)
120
+ end
121
+
122
+ def self.checks(rule)
123
+ rule.instance_variable_get(:@__checks)
124
+ end
125
+
126
+ def self.skip_status(rule)
127
+ rule.instance_variable_get(:@__skip_rule)
128
+ end
129
+
130
+ def self.set_skip_rule(rule, value)
131
+ rule.instance_variable_set(:@__skip_rule, value)
132
+ end
133
+
134
+ def self.prepare_checks(rule)
135
+ msg = skip_status(rule)
136
+ return checks(rule) unless msg
137
+ msg = 'Skipped control due to only_if condition.' if msg == true
138
+
139
+ # TODO: we use os as the carrier here, but should consider
140
+ # a separate resource to do skipping
141
+ resource = rule.os
142
+ resource.skip_resource(msg)
143
+ [['describe', [resource], nil]]
144
+ end
145
+
102
146
  def self.merge(dst, src)
103
147
  if src.id != dst.id
104
148
  # TODO: register an error, this case should not happen
105
149
  return
106
150
  end
107
- sp = src.instance_variable_get(:@profile_id)
108
- dp = dst.instance_variable_get(:@profile_id)
151
+ sp = rule_id(src)
152
+ dp = rule_id(dst)
109
153
  if sp != dp
110
154
  # TODO: register an error, this case should not happen
111
155
  return
@@ -117,10 +161,10 @@ module Inspec
117
161
  # merge indirect fields
118
162
  # checks defined in the source will completely eliminate
119
163
  # all checks that were defined in the destination
120
- sc = src.instance_variable_get(:@checks)
121
- unless sc.nil? || sc.empty?
122
- dst.instance_variable_set(:@checks, sc)
123
- end
164
+ sc = checks(src)
165
+ dst.instance_variable_set(:@__checks, sc) unless sc.empty?
166
+ sr = skip_status(src)
167
+ set_skip_rule(dst, sr) unless sr.nil?
124
168
  end
125
169
 
126
170
  # Get the full id consisting of profile id + rule id
@@ -140,11 +184,8 @@ module Inspec
140
184
  return nil
141
185
  end
142
186
  end
143
- pid = rule.instance_variable_get(:@profile_id)
144
- if pid.nil?
145
- rule.instance_variable_set(:@profile_id, profile_id)
146
- pid = profile_id
147
- end
187
+ pid = rule_id(rule)
188
+ pid = set_rule_id(rule, profile_id) if pid.nil?
148
189
 
149
190
  # if we don't have a profile id, just return the rule's ID
150
191
  return rid if pid.nil? or pid.empty?
@@ -154,8 +195,8 @@ module Inspec
154
195
 
155
196
  private
156
197
 
157
- def add_check(describe_or_expect, values, block)
158
- @checks.push([describe_or_expect, values, block])
198
+ def __add_check(describe_or_expect, values, block)
199
+ @__checks.push([describe_or_expect, values, block])
159
200
  end
160
201
 
161
202
  # Idio(ma)tic unindent
@@ -53,9 +53,8 @@ module Inspec
53
53
  end
54
54
 
55
55
  def add_profile(profile, options = {})
56
- return unless options[:ignore_supports] ||
57
- profile.metadata.supports_transport?(@backend)
58
56
  @test_collector.add_profile(profile)
57
+ options[:metadata] = profile.metadata
59
58
 
60
59
  libs = profile.libraries.map do |k, v|
61
60
  { ref: k, content: v }
@@ -87,6 +86,19 @@ module Inspec
87
86
  tests = [tests] unless tests.is_a? Array
88
87
  tests.each { |t| add_test_to_context(t, ctx) }
89
88
 
89
+ # skip based on support checks in metadata
90
+ meta = options[:metadata]
91
+ if !options[:ignore_supports] && !meta.nil? &&
92
+ !meta.supports_transport?(@backend)
93
+ os_info = @backend.os[:family].to_s
94
+ ctx.rules.values.each do |ctrl|
95
+ ::Inspec::Rule.set_skip_rule(
96
+ ctrl,
97
+ "This OS/platform (#{os_info}) is not supported by this profile.",
98
+ )
99
+ end
100
+ end
101
+
90
102
  # process the resulting rules
91
103
  filter_controls(ctx.rules, options[:controls]).each do |rule_id, rule|
92
104
  register_rule(rule_id, rule)
@@ -154,7 +166,7 @@ module Inspec
154
166
 
155
167
  def register_rule(rule_id, rule)
156
168
  @rules[rule_id] = rule
157
- checks = rule.instance_variable_get(:@checks)
169
+ checks = ::Inspec::Rule.prepare_checks(rule)
158
170
  examples = checks.map do |m, a, b|
159
171
  get_check_example(m, a, b)
160
172
  end.flatten.compact
@@ -3,5 +3,5 @@
3
3
  # author: Christoph Hartmann
4
4
 
5
5
  module Inspec
6
- VERSION = '0.17.1'.freeze
6
+ VERSION = '0.18.0'.freeze
7
7
  end
@@ -12,7 +12,7 @@ describe 'inspec exec' do
12
12
  out.stderr.must_equal ''
13
13
  out.exit_status.must_equal 0
14
14
  out.stdout.must_match /^Pending: /
15
- out.stdout.must_include '4 examples, 0 failures, 1 pending'
15
+ out.stdout.must_include '5 examples, 0 failures, 1 pending'
16
16
  end
17
17
 
18
18
  it 'executes only specified controls' do
@@ -36,8 +36,8 @@ describe 'inspec exec' do
36
36
  let(:ex2) { examples.find{|x| x['id'] =~ /generated/} }
37
37
  let(:ex3) { examples.find{|x| x['id'] == 'gordon-1.0'} }
38
38
 
39
- it 'must have 4 examples' do
40
- json['examples'].length.must_equal 4
39
+ it 'must have 5 examples' do
40
+ json['examples'].length.must_equal 5
41
41
  end
42
42
 
43
43
  it 'id in json' do
@@ -82,8 +82,8 @@ describe 'inspec exec' do
82
82
  })
83
83
  end
84
84
 
85
- it 'must have 4 examples' do
86
- json['examples'].length.must_equal 4
85
+ it 'must have 5 examples' do
86
+ json['examples'].length.must_equal 5
87
87
  end
88
88
 
89
89
  it 'id in json' do
@@ -138,4 +138,26 @@ describe 'inspec exec' do
138
138
  end
139
139
  end
140
140
 
141
+ describe 'with a profile that is not supported on this OS/platform' do
142
+ let(:out) { inspec('exec ' + File.join(profile_path, 'skippy-profile-os') + ' --format fulljson') }
143
+ let(:json) { JSON.load(out.stdout) }
144
+
145
+ it 'exits cleanly' do
146
+ out.stderr.must_equal ''
147
+ out.exit_status.must_equal 0
148
+ end
149
+
150
+ it 'has one pending' do
151
+ json['summary']['pending_count'].must_equal 1
152
+ json['summary']['example_count'].must_equal 1
153
+ end
154
+
155
+ it 'delivers the pending message' do
156
+ json['examples'][0]['pending'].must_match %r{^This OS/platform \([^)]+\) is not supported by this profile\.$}
157
+ end
158
+
159
+ it 'never runs the actual resource' do
160
+ File.exist?('/tmp/inspec_test_DONT_CREATE').must_equal false
161
+ end
162
+ end
141
163
  end
@@ -0,0 +1,3 @@
1
+ describe command('touch /tmp/inspec_test_DONT_CREATE') do
2
+ its(:exit_status) { should eq 123 }
3
+ end
@@ -0,0 +1,5 @@
1
+ name: skippy
2
+ title: skip-like functionality
3
+ version: 1.0.0
4
+ supports:
5
+ - os-family: definitely_not_supported
@@ -60,7 +60,7 @@ describe Inspec::ProfileContext do
60
60
  end
61
61
 
62
62
  def get_checks
63
- get_rule.instance_variable_get(:@checks)
63
+ Inspec::Rule.prepare_checks(get_rule)
64
64
  end
65
65
 
66
66
  it 'must be able to load empty content' do
@@ -117,7 +117,71 @@ describe Inspec::ProfileContext do
117
117
  load('expect(true).to_eq true').must_raise NoMethodError
118
118
  end
119
119
 
120
- it 'provides the rule keyword in the global DSL' do
120
+ describe 'global only_if' do
121
+ let(:if_true) { "only_if { true }\n" }
122
+ let(:if_false) { "only_if { false }\n" }
123
+ let(:describe) { "describe nil do its(:to_i) { should eq rand } end\n" }
124
+ let(:control) { "control 1 do\n#{describe}end" }
125
+
126
+ it 'provides the keyword' do
127
+ profile.load(if_true)
128
+ profile.rules.must_equal({})
129
+ end
130
+
131
+ it 'doesnt affect controls when positive' do
132
+ profile.load(if_true + 'control 1')
133
+ profile.rules.values[0].must_be_kind_of Inspec::Rule
134
+ end
135
+
136
+ it 'doesnt remove controls when negative' do
137
+ profile.load(if_false + 'control 1')
138
+ profile.rules.values[0].must_be_kind_of Inspec::Rule
139
+ end
140
+
141
+ it 'alters controls when positive' do
142
+ profile.load(if_false + control)
143
+ get_checks.length.must_equal 1
144
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
145
+ end
146
+
147
+ it 'alters non-controls when positive' do
148
+ profile.load(if_false + describe)
149
+ get_checks.length.must_equal 1
150
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
151
+ end
152
+
153
+ it 'doesnt alter controls when negative' do
154
+ profile.load(if_true + control)
155
+ get_checks.length.must_equal 1
156
+ get_checks[0][1][0].must_be_nil
157
+ end
158
+
159
+ it 'doesnt alter non-controls when negative' do
160
+ profile.load(if_true + describe)
161
+ get_checks.length.must_equal 1
162
+ get_checks[0][1][0].must_be_nil
163
+ end
164
+
165
+ it 'doesnt overwrite falsy only_ifs' do
166
+ profile.load(if_false + if_true + control)
167
+ get_checks.length.must_equal 1
168
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
169
+ end
170
+
171
+ it 'doesnt overwrite falsy only_ifs' do
172
+ profile.load(if_true + if_false + control)
173
+ get_checks.length.must_equal 1
174
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
175
+ end
176
+ end
177
+
178
+ it 'provides the control keyword in the global DSL' do
179
+ profile.load('control 1')
180
+ profile.rules.keys.must_equal [1]
181
+ profile.rules.values[0].must_be_kind_of Inspec::Rule
182
+ end
183
+
184
+ it 'provides the rule keyword in the global DSL (legacy mode)' do
121
185
  profile.load('rule 1')
122
186
  profile.rules.keys.must_equal [1]
123
187
  profile.rules.values[0].must_be_kind_of Inspec::Rule
@@ -137,7 +201,7 @@ describe Inspec::ProfileContext do
137
201
  it 'doesnt add any checks if none are provided' do
138
202
  profile.load("rule #{rule_id.inspect}")
139
203
  rule = profile.rules[rule_id]
140
- rule.instance_variable_get(:@checks).must_equal([])
204
+ ::Inspec::Rule.prepare_checks(rule).must_equal([])
141
205
  end
142
206
 
143
207
  describe 'supports empty describe blocks' do
@@ -212,5 +276,35 @@ describe Inspec::ProfileContext do
212
276
  check[2].must_be_kind_of Proc
213
277
  end
214
278
  end
279
+
280
+ describe 'with only_if' do
281
+ it 'provides the only_if keyword' do
282
+ profile.load(format(context_format, 'only_if'))
283
+ get_checks.must_equal([])
284
+ end
285
+
286
+ it 'skips with only_if == false' do
287
+ profile.load(format(context_format, 'only_if { false }'))
288
+ get_checks.length.must_equal 1
289
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
290
+ end
291
+
292
+ it 'does nothing with only_if == false' do
293
+ profile.load(format(context_format, 'only_if { true }'))
294
+ get_checks.length.must_equal 0
295
+ end
296
+
297
+ it 'doesnt overwrite falsy only_ifs' do
298
+ profile.load(format(context_format, "only_if { false }\nonly_if { true }"))
299
+ get_checks.length.must_equal 1
300
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
301
+ end
302
+
303
+ it 'doesnt overwrite falsy only_ifs' do
304
+ profile.load(format(context_format, "only_if { true }\nonly_if { false }"))
305
+ get_checks.length.must_equal 1
306
+ get_checks[0][1][0].resource_skipped.must_equal 'Skipped control due to only_if condition.'
307
+ end
308
+ end
215
309
  end
216
310
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.1
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-31 00:00:00.000000000 Z
11
+ date: 2016-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: r-train
@@ -335,7 +335,6 @@ files:
335
335
  - lib/utils/filter_array.rb
336
336
  - lib/utils/find_files.rb
337
337
  - lib/utils/hash.rb
338
- - lib/utils/hash_map.rb
339
338
  - lib/utils/json_log.rb
340
339
  - lib/utils/modulator.rb
341
340
  - lib/utils/object_traversal.rb
@@ -518,9 +517,9 @@ files:
518
517
  - test/unit/mock/profiles/legacy-empty-metadata/metadata.rb
519
518
  - test/unit/mock/profiles/legacy-simple-metadata/metadata.rb
520
519
  - test/unit/mock/profiles/legacy-simple-metadata/test/.gitkeep
521
- - test/unit/mock/profiles/resource-tiny/inspec.yml
522
- - test/unit/mock/profiles/resource-tiny/libraries/resource.rb
523
520
  - test/unit/mock/profiles/simple-metadata/inspec.yml
521
+ - test/unit/mock/profiles/skippy-profile-os/controls/one.rb
522
+ - test/unit/mock/profiles/skippy-profile-os/inspec.yml
524
523
  - test/unit/plugin_test.rb
525
524
  - test/unit/plugins/resource_test.rb
526
525
  - test/unit/profile_context_test.rb
@@ -576,7 +575,6 @@ files:
576
575
  - test/unit/source_readers/inspec_test.rb
577
576
  - test/unit/utils/filter_array_test.rb
578
577
  - test/unit/utils/find_files_test.rb
579
- - test/unit/utils/hash_map_test.rb
580
578
  - test/unit/utils/passwd_parser_test.rb
581
579
  - test/unit/utils/simpleconfig_test.rb
582
580
  - test/unit/utils/solaris_netstat_parser.rb
@@ -600,7 +598,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
600
598
  version: '0'
601
599
  requirements: []
602
600
  rubyforge_project:
603
- rubygems_version: 2.5.1
601
+ rubygems_version: 2.4.6
604
602
  signing_key:
605
603
  specification_version: 4
606
604
  summary: Infrastructure and compliance testing.
@@ -780,9 +778,9 @@ test_files:
780
778
  - test/unit/mock/profiles/legacy-empty-metadata/metadata.rb
781
779
  - test/unit/mock/profiles/legacy-simple-metadata/metadata.rb
782
780
  - test/unit/mock/profiles/legacy-simple-metadata/test/.gitkeep
783
- - test/unit/mock/profiles/resource-tiny/inspec.yml
784
- - test/unit/mock/profiles/resource-tiny/libraries/resource.rb
785
781
  - test/unit/mock/profiles/simple-metadata/inspec.yml
782
+ - test/unit/mock/profiles/skippy-profile-os/controls/one.rb
783
+ - test/unit/mock/profiles/skippy-profile-os/inspec.yml
786
784
  - test/unit/plugin_test.rb
787
785
  - test/unit/plugins/resource_test.rb
788
786
  - test/unit/profile_context_test.rb
@@ -838,7 +836,6 @@ test_files:
838
836
  - test/unit/source_readers/inspec_test.rb
839
837
  - test/unit/utils/filter_array_test.rb
840
838
  - test/unit/utils/find_files_test.rb
841
- - test/unit/utils/hash_map_test.rb
842
839
  - test/unit/utils/passwd_parser_test.rb
843
840
  - test/unit/utils/simpleconfig_test.rb
844
841
  - test/unit/utils/solaris_netstat_parser.rb
@@ -1,37 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
-
5
- class HashMap
6
- class << self
7
- def [](hash, *keys)
8
- return hash if keys.empty? || hash.nil?
9
- key = keys.shift
10
- if hash.is_a?(Array)
11
- map = hash.map { |i| [i, key] }
12
- else
13
- map = hash[key]
14
- end
15
- [map, *keys]
16
- rescue NoMethodError => _
17
- nil
18
- end
19
- end
20
- end
21
-
22
- class StringMap
23
- class << self
24
- def [](hash, *keys)
25
- return hash if keys.empty? || hash.nil?
26
- key = keys.shift
27
- if hash.is_a?(Array)
28
- map = hash.map { |i| [i, key] }
29
- else
30
- map = hash[key]
31
- end
32
- [map, *keys]
33
- rescue NoMethodError => _
34
- nil
35
- end
36
- end
37
- end
@@ -1,10 +0,0 @@
1
- name: complete
2
- title: complete example profile
3
- maintainer: Chef Software, Inc.
4
- copyright: Chef Software, Inc.
5
- copyright_email: support@chef.io
6
- license: Proprietary, All rights reserved
7
- summary: Testing stub
8
- version: 1.0.0
9
- supports:
10
- - os-family: linux
@@ -1,3 +0,0 @@
1
- class Tiny < Inspec.resource(1)
2
- name 'tiny'
3
- end
@@ -1,63 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
-
5
- require 'helper'
6
- require 'utils/hash_map'
7
-
8
- describe HashMap do
9
- describe '#get_value' do
10
- it 'returns the source value if no keys are given' do
11
- x = rand
12
- HashMap[x].must_equal x
13
- end
14
-
15
- it 'retrieves a key from a map' do
16
- x = { a: rand }
17
- HashMap[x, :a].must_equal x[:a]
18
- end
19
-
20
- it 'returns nil if the key doesnt exist' do
21
- x = { a: rand }
22
- HashMap[x, :b].must_be :nil?
23
- end
24
-
25
- it 'can extract a nil key' do
26
- x = { nil => rand }
27
- HashMap[x, nil].must_equal x[nil]
28
- end
29
-
30
- it 'extracts multiple keys' do
31
- y = rand
32
- x = { a: { b: { c: y }}}
33
- HashMap[x, :a, :b, :c].must_equal y
34
- end
35
-
36
- it 'returns nil if a key in a list doesnt exist' do
37
- x = { a: { b: { c: rand }}}
38
- HashMap[x, :d, :b, :c].must_be :nil?
39
- end
40
-
41
- it 'retrieves exact keys by string' do
42
- x = { a: rand }
43
- HashMap[x, :a].must_equal x[:a]
44
- HashMap[x, 'a'].must_be :nil?
45
- end
46
-
47
- it 'retrieves exact keys by string' do
48
- x = { 'a' => rand }
49
- HashMap[x, 'a'].must_equal x['a']
50
- HashMap[x, :a].must_be :nil?
51
- end
52
-
53
- it 'con retrieve string keys' do
54
- x = { 'a' => rand }
55
- HashMap.extract_keys(x, ['a'], string_keys: true).must_equal x['a']
56
- HashMap.extract_keys(x, [:a], string_keys: true).must_equal x['a']
57
- end
58
- end
59
-
60
- describe 'as an instance' do
61
-
62
- end
63
- end