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 +4 -4
- data/CHANGELOG.md +19 -2
- data/README.md +8 -0
- data/examples/profile/README.md +2 -2
- data/examples/profile/controls/gordon.rb +13 -1
- data/examples/profile/libraries/gordon_config.rb +17 -7
- data/lib/inspec/dsl.rb +1 -1
- data/lib/inspec/profile.rb +1 -1
- data/lib/inspec/profile_context.rb +13 -18
- data/lib/inspec/rule.rb +62 -21
- data/lib/inspec/runner.rb +15 -3
- data/lib/inspec/version.rb +1 -1
- data/test/functional/inspec_exec_test.rb +27 -5
- data/test/unit/mock/profiles/skippy-profile-os/controls/one.rb +3 -0
- data/test/unit/mock/profiles/skippy-profile-os/inspec.yml +5 -0
- data/test/unit/profile_context_test.rb +97 -3
- metadata +7 -10
- data/lib/utils/hash_map.rb +0 -37
- data/test/unit/mock/profiles/resource-tiny/inspec.yml +0 -10
- data/test/unit/mock/profiles/resource-tiny/libraries/resource.rb +0 -3
- data/test/unit/utils/hash_map_test.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fcd7959abdb3de12c11854323ad29f484f0dbda
|
4
|
+
data.tar.gz: 79bbc6496cc71d18e02a9b05b4e6fbd3a5043315
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4256867dac4a3a9978b4f5dfda36aba67f9d97461d9d074e694f048d51ae22cd2e835593524e5dcbcc9d3f87a34279cbcd295f6f66d0d372939c8daf5e73688f
|
7
|
+
data.tar.gz: c6cc148cae574dd9dce10ad9781cb9e088fff6c52fdde9f3b40463d7166689e23923b539ba077a4d224e3611f33b0fd7c3b2799e9308590516a6231f536a78cc
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,24 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [0.
|
4
|
-
[Full Changelog](https://github.com/chef/inspec/compare/v0.17.
|
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)!
|
data/examples/profile/README.md
CHANGED
@@ -12,7 +12,7 @@ Summary
|
|
12
12
|
-------
|
13
13
|
Location: examples/profile
|
14
14
|
Profile: profile
|
15
|
-
Controls:
|
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
|
-
|
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('
|
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('
|
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
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
data/lib/inspec/dsl.rb
CHANGED
@@ -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 =
|
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
|
data/lib/inspec/profile.rb
CHANGED
@@ -256,7 +256,7 @@ module Inspec
|
|
256
256
|
impact: rule.impact,
|
257
257
|
refs: rule.ref,
|
258
258
|
tags: rule.tag,
|
259
|
-
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
|
-
|
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
|
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)
|
data/lib/inspec/rule.rb
CHANGED
@@ -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
|
-
@
|
27
|
-
@
|
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(:
|
102
|
+
end.new(method(:__add_check))
|
91
103
|
else
|
92
|
-
|
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
|
-
|
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
|
108
|
-
dp = dst
|
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
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
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
|
158
|
-
@
|
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
|
data/lib/inspec/runner.rb
CHANGED
@@ -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 =
|
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
|
data/lib/inspec/version.rb
CHANGED
@@ -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 '
|
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
|
40
|
-
json['examples'].length.must_equal
|
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
|
86
|
-
json['examples'].length.must_equal
|
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
|
@@ -60,7 +60,7 @@ describe Inspec::ProfileContext do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def get_checks
|
63
|
-
|
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
|
-
|
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
|
-
|
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.
|
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-
|
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.
|
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
|
data/lib/utils/hash_map.rb
DELETED
@@ -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,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
|