inspec 0.17.1 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
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