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 +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
|
[](https://gitter.im/chef/inspec?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
4
|
+
[](https://travis-ci.org/chef/inspec)
|
|
5
|
+
[](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
|