inspec 0.20.1 → 0.21.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 +45 -2
- data/docs/dsl_inspec.rst +2 -2
- data/docs/resources.rst +9 -9
- data/docs/ruby_usage.rst +145 -0
- data/inspec.gemspec +1 -0
- data/lib/bundles/inspec-compliance/cli.rb +15 -2
- data/lib/inspec/cli.rb +23 -10
- data/lib/inspec/dsl.rb +0 -52
- data/lib/inspec/objects/or_test.rb +1 -0
- data/lib/inspec/objects/test.rb +4 -4
- data/lib/inspec/profile.rb +76 -61
- data/lib/inspec/profile_context.rb +12 -11
- data/lib/inspec/rspec_json_formatter.rb +93 -40
- data/lib/inspec/rule.rb +7 -29
- data/lib/inspec/runner.rb +15 -4
- data/lib/inspec/runner_mock.rb +1 -1
- data/lib/inspec/runner_rspec.rb +26 -24
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +3 -3
- data/lib/resources/auditd_rules.rb +2 -2
- data/lib/resources/host.rb +1 -1
- data/lib/resources/interface.rb +1 -1
- data/lib/resources/kernel_parameter.rb +1 -1
- data/lib/resources/mount.rb +2 -1
- data/lib/resources/mysql_session.rb +1 -1
- data/lib/resources/os_env.rb +2 -2
- data/lib/resources/passwd.rb +33 -93
- data/lib/resources/port.rb +47 -3
- data/lib/resources/processes.rb +3 -3
- data/lib/resources/service.rb +33 -1
- data/lib/resources/user.rb +15 -15
- data/lib/utils/base_cli.rb +1 -3
- data/lib/utils/filter.rb +30 -7
- data/test/cookbooks/os_prepare/recipes/_upstart_service_centos.rb +4 -0
- data/test/functional/helper.rb +1 -0
- data/test/functional/inheritance_test.rb +1 -1
- data/test/functional/inspec_compliance_test.rb +4 -3
- data/test/functional/inspec_exec_json_test.rb +122 -0
- data/test/functional/inspec_exec_test.rb +23 -117
- data/test/functional/{inspec_json_test.rb → inspec_json_profile_test.rb} +13 -15
- data/test/functional/inspec_test.rb +15 -2
- data/test/helper.rb +5 -1
- data/test/integration/default/auditd_rules_spec.rb +3 -3
- data/test/integration/default/kernel_parameter_spec.rb +6 -6
- data/test/integration/default/service_spec.rb +4 -0
- data/test/resource/command_test.rb +9 -9
- data/test/resource/dsl_test.rb +1 -1
- data/test/resource/file_test.rb +17 -17
- data/test/unit/control_test.rb +1 -1
- data/test/unit/mock/cmd/hpux-netstat-inet +10 -0
- data/test/unit/mock/cmd/hpux-netstat-inet6 +11 -0
- data/test/unit/mock/profiles/skippy-profile-os/controls/one.rb +1 -1
- data/test/unit/profile_context_test.rb +2 -2
- data/test/unit/profile_test.rb +11 -14
- data/test/unit/resources/passwd_test.rb +13 -14
- data/test/unit/resources/port_test.rb +14 -0
- data/test/unit/resources/processes_test.rb +3 -3
- data/test/unit/resources/service_test.rb +103 -39
- data/test/unit/utils/filter_table_test.rb +35 -3
- metadata +25 -4
data/lib/resources/port.rb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
# author: Dominik Richter
|
4
4
|
|
5
5
|
require 'utils/parser'
|
6
|
-
|
7
6
|
# Usage:
|
8
7
|
# describe port(80) do
|
9
8
|
# it { should be_listening }
|
@@ -47,6 +46,8 @@ module Inspec::Resources
|
|
47
46
|
@port_manager = FreeBsdPorts.new(inspec)
|
48
47
|
elsif os.solaris?
|
49
48
|
@port_manager = SolarisPorts.new(inspec)
|
49
|
+
elsif os.hpux?
|
50
|
+
@port_manager = HpuxPorts.new(inspec)
|
50
51
|
else
|
51
52
|
return skip_resource 'The `port` resource is not supported on your OS yet.'
|
52
53
|
end
|
@@ -292,7 +293,6 @@ module Inspec::Resources
|
|
292
293
|
# parse each line
|
293
294
|
# 1 - Proto, 2 - Recv-Q, 3 - Send-Q, 4 - Local Address, 5 - Foreign Address, 6 - State, 7 - Inode, 8 - PID/Program name
|
294
295
|
parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?\s+(\S+)\s+(\S+)\s+(\S+)/.match(line)
|
295
|
-
|
296
296
|
return {} if parsed.nil? || line.match(/^proto/i)
|
297
297
|
|
298
298
|
# parse ip4 and ip6 addresses
|
@@ -408,7 +408,7 @@ module Inspec::Resources
|
|
408
408
|
# parse the content
|
409
409
|
netstat_ports = parse_netstat(cmd.stdout)
|
410
410
|
|
411
|
-
# filter all ports, where we listen
|
411
|
+
# filter all ports, where we `listen`
|
412
412
|
listen = netstat_ports.select { |val|
|
413
413
|
!val['state'].nil? && 'listen'.casecmp(val['state']) == 0
|
414
414
|
}
|
@@ -433,4 +433,48 @@ module Inspec::Resources
|
|
433
433
|
ports
|
434
434
|
end
|
435
435
|
end
|
436
|
+
|
437
|
+
# extracts information from netstat for hpux
|
438
|
+
class HpuxPorts < FreeBsdPorts
|
439
|
+
def info
|
440
|
+
## Can't use 'netstat -an -f inet -f inet6' as the latter -f option overrides the former one and return only inet ports
|
441
|
+
cmd1 = inspec.command('netstat -an -f inet')
|
442
|
+
return nil if cmd1.exit_status.to_i != 0
|
443
|
+
cmd2 = inspec.command('netstat -an -f inet6')
|
444
|
+
return nil if cmd2.exit_status.to_i != 0
|
445
|
+
cmd = cmd1.stdout + cmd2.stdout
|
446
|
+
ports = []
|
447
|
+
# parse all lines
|
448
|
+
cmd.each_line do |line|
|
449
|
+
port_info = parse_netstat_line(line)
|
450
|
+
next unless %w{tcp tcp6 udp udp6}.include?(port_info[:protocol])
|
451
|
+
ports.push(port_info)
|
452
|
+
end
|
453
|
+
# select all ports, where we `listen`
|
454
|
+
ports.select { |val| val if 'listen'.casecmp(val[:state]) == 0 }
|
455
|
+
end
|
456
|
+
|
457
|
+
def parse_netstat_line(line)
|
458
|
+
# parse each line
|
459
|
+
# 1 - Proto, 2 - Recv-Q, 3 - Send-Q, 4 - Local Address, 5 - Foreign Address, 6 - (state)
|
460
|
+
parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?/.match(line)
|
461
|
+
|
462
|
+
return {} if parsed.nil? || line.match(/^proto/i) || line.match(/^active/i)
|
463
|
+
protocol = parsed[1].downcase
|
464
|
+
state = parsed[6].nil?? ' ' : parsed[6].downcase
|
465
|
+
local_addr = parsed[4]
|
466
|
+
local_addr[local_addr.rindex('.')] = ':'
|
467
|
+
# extract host and port information
|
468
|
+
host, port = parse_net_address(local_addr, protocol)
|
469
|
+
# map data
|
470
|
+
{
|
471
|
+
port: port,
|
472
|
+
address: host,
|
473
|
+
protocol: protocol,
|
474
|
+
state: state,
|
475
|
+
process: nil,
|
476
|
+
pid: nil,
|
477
|
+
}
|
478
|
+
end
|
479
|
+
end
|
436
480
|
end
|
data/lib/resources/processes.rb
CHANGED
data/lib/resources/service.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# author: Dominik Richter
|
4
4
|
# author: Stephan Renatus
|
5
5
|
# license: All rights reserved
|
6
|
+
require 'hashie'
|
6
7
|
|
7
8
|
module Inspec::Resources
|
8
9
|
class Runlevels < Hash
|
@@ -67,7 +68,7 @@ module Inspec::Resources
|
|
67
68
|
# Ubuntu < 15.04 : upstart
|
68
69
|
#
|
69
70
|
# TODO: extend the logic to detect the running init system, independently of OS
|
70
|
-
class Service < Inspec.resource(1)
|
71
|
+
class Service < Inspec.resource(1) # rubocop:disable ClassLength
|
71
72
|
name 'service'
|
72
73
|
desc 'Use the service InSpec audit resource to test if the named service is installed, running and/or enabled.'
|
73
74
|
example "
|
@@ -75,11 +76,16 @@ module Inspec::Resources
|
|
75
76
|
it { should be_installed }
|
76
77
|
it { should be_enabled }
|
77
78
|
it { should be_running }
|
79
|
+
its('type') { should be 'systemd' }
|
78
80
|
end
|
79
81
|
|
80
82
|
describe service('service_name').runlevels(3, 5) do
|
81
83
|
it { should be_enabled }
|
82
84
|
end
|
85
|
+
|
86
|
+
describe service('service_name').params do
|
87
|
+
its('UnitFileState') { should eq 'enabled' }
|
88
|
+
end
|
83
89
|
"
|
84
90
|
|
85
91
|
attr_reader :service_ctl
|
@@ -163,6 +169,11 @@ module Inspec::Resources
|
|
163
169
|
info[:enabled]
|
164
170
|
end
|
165
171
|
|
172
|
+
def params
|
173
|
+
return {} if info.nil?
|
174
|
+
Hashie::Mash.new(info[:params] || {})
|
175
|
+
end
|
176
|
+
|
166
177
|
# verifies the service is registered
|
167
178
|
def installed?(_name = nil, _version = nil)
|
168
179
|
return false if info.nil?
|
@@ -181,9 +192,29 @@ module Inspec::Resources
|
|
181
192
|
Runlevels.from_hash(self, info[:runlevels], args)
|
182
193
|
end
|
183
194
|
|
195
|
+
# returns the service type from info
|
196
|
+
def type
|
197
|
+
return nil if info.nil?
|
198
|
+
info[:type]
|
199
|
+
end
|
200
|
+
|
201
|
+
# returns the service name from info
|
202
|
+
def name
|
203
|
+
return @service_name if info.nil?
|
204
|
+
info[:name]
|
205
|
+
end
|
206
|
+
|
207
|
+
# returns the service description from info
|
208
|
+
def description
|
209
|
+
return nil if info.nil?
|
210
|
+
info[:description]
|
211
|
+
end
|
212
|
+
|
184
213
|
def to_s
|
185
214
|
"Service #{@service_name}"
|
186
215
|
end
|
216
|
+
|
217
|
+
private :info
|
187
218
|
end
|
188
219
|
|
189
220
|
class ServiceManager
|
@@ -229,6 +260,7 @@ module Inspec::Resources
|
|
229
260
|
running: running,
|
230
261
|
enabled: enabled,
|
231
262
|
type: 'systemd',
|
263
|
+
params: params,
|
232
264
|
}
|
233
265
|
end
|
234
266
|
end
|
data/lib/resources/user.rb
CHANGED
@@ -6,15 +6,15 @@
|
|
6
6
|
#
|
7
7
|
# describe user('root') do
|
8
8
|
# it { should exist }
|
9
|
-
# its(
|
10
|
-
# its(
|
11
|
-
# its(
|
12
|
-
# its(
|
13
|
-
# its(
|
14
|
-
# its(
|
15
|
-
# its(
|
16
|
-
# its(
|
17
|
-
# its(
|
9
|
+
# its('uid') { should eq 0 }
|
10
|
+
# its('gid') { should eq 0 }
|
11
|
+
# its('group') { should eq 'root' }
|
12
|
+
# its('groups') { should eq ['root', 'wheel']}
|
13
|
+
# its('home') { should eq '/root' }
|
14
|
+
# its('shell') { should eq '/bin/bash' }
|
15
|
+
# its('mindays') { should eq 0 }
|
16
|
+
# its('maxdays') { should eq 99 }
|
17
|
+
# its('warndays') { should eq 5 }
|
18
18
|
# end
|
19
19
|
#
|
20
20
|
# The following Serverspec matchers are deprecated in favor for direct value access
|
@@ -24,8 +24,8 @@
|
|
24
24
|
# it { should have_uid 0 }
|
25
25
|
# it { should have_home_directory '/root' }
|
26
26
|
# it { should have_login_shell '/bin/bash' }
|
27
|
-
# its(
|
28
|
-
# its(
|
27
|
+
# its('minimum_days_between_password_change') { should eq 0 }
|
28
|
+
# its('maximum_days_between_password_change') { should eq 99 }
|
29
29
|
# end
|
30
30
|
|
31
31
|
# ServerSpec tests that are not supported:
|
@@ -119,13 +119,13 @@ module Inspec::Resources
|
|
119
119
|
|
120
120
|
# implement 'mindays' method to be compatible with serverspec
|
121
121
|
def minimum_days_between_password_change
|
122
|
-
deprecated('minimum_days_between_password_change', "Please use
|
122
|
+
deprecated('minimum_days_between_password_change', "Please use: its('mindays')")
|
123
123
|
mindays
|
124
124
|
end
|
125
125
|
|
126
126
|
# implement 'maxdays' method to be compatible with serverspec
|
127
127
|
def maximum_days_between_password_change
|
128
|
-
deprecated('maximum_days_between_password_change', "Please use
|
128
|
+
deprecated('maximum_days_between_password_change', "Please use: its('maxdays')")
|
129
129
|
maxdays
|
130
130
|
end
|
131
131
|
|
@@ -137,12 +137,12 @@ module Inspec::Resources
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def has_home_directory?(compare_home)
|
140
|
-
deprecated('has_home_directory?', "Please use
|
140
|
+
deprecated('has_home_directory?', "Please use: its('home')")
|
141
141
|
home == compare_home
|
142
142
|
end
|
143
143
|
|
144
144
|
def has_login_shell?(compare_shell)
|
145
|
-
deprecated('has_login_shell?', "Please use
|
145
|
+
deprecated('has_login_shell?', "Please use: its('shell')")
|
146
146
|
shell == compare_shell
|
147
147
|
end
|
148
148
|
|
data/lib/utils/base_cli.rb
CHANGED
@@ -45,8 +45,6 @@ module Inspec
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.exec_options
|
48
|
-
option :id, type: :string,
|
49
|
-
desc: 'Attach a profile ID to all test results'
|
50
48
|
target_options
|
51
49
|
profile_options
|
52
50
|
option :controls, type: :array,
|
@@ -68,7 +66,7 @@ module Inspec
|
|
68
66
|
runner = Inspec::Runner.new(o)
|
69
67
|
targets.each { |target| runner.add_target(target, opts) }
|
70
68
|
exit runner.run
|
71
|
-
rescue RuntimeError => e
|
69
|
+
rescue RuntimeError, Train::UserError => e
|
72
70
|
$stderr.puts e.message
|
73
71
|
exit 1
|
74
72
|
end
|
data/lib/utils/filter.rb
CHANGED
@@ -95,15 +95,38 @@ module FilterTable
|
|
95
95
|
|
96
96
|
private
|
97
97
|
|
98
|
+
def matches_float(x, y)
|
99
|
+
return false if x.nil?
|
100
|
+
return false if !x.is_a?(Float) && (x =~ /\A[-+]?(\d+\.?\d*|\.\d+)\z/).nil?
|
101
|
+
x.to_f == y
|
102
|
+
end
|
103
|
+
|
104
|
+
def matches_int(x, y)
|
105
|
+
return false if x.nil?
|
106
|
+
return false if !x.is_a?(Integer) && (x =~ /\A[-+]?\d+\z/).nil?
|
107
|
+
x.to_i == y
|
108
|
+
end
|
109
|
+
|
110
|
+
def matches_regex(x, y)
|
111
|
+
return x == y if x.is_a?(Regexp)
|
112
|
+
!x.to_s.match(y).nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
def matches(x, y)
|
116
|
+
x === y # rubocop:disable Style/CaseEquality
|
117
|
+
end
|
118
|
+
|
98
119
|
def filter_lines(table, field, condition)
|
120
|
+
m = case condition
|
121
|
+
when Float then method(:matches_float)
|
122
|
+
when Integer then method(:matches_int)
|
123
|
+
when Regexp then method(:matches_regex)
|
124
|
+
else method(:matches)
|
125
|
+
end
|
126
|
+
|
99
127
|
table.find_all do |line|
|
100
128
|
next unless line.key?(field)
|
101
|
-
|
102
|
-
when condition
|
103
|
-
true
|
104
|
-
else
|
105
|
-
false
|
106
|
-
end
|
129
|
+
m.call(line[field], condition)
|
107
130
|
end
|
108
131
|
end
|
109
132
|
end
|
@@ -134,7 +157,7 @@ module FilterTable
|
|
134
157
|
fields.each do |method, field_name|
|
135
158
|
block = blocks[method]
|
136
159
|
define_method method.to_sym do |condition = Show, &cond_block|
|
137
|
-
return block.call(self) unless block.nil?
|
160
|
+
return block.call(self, condition) unless block.nil?
|
138
161
|
return where(nil).get_fields(field_name) if condition == Show && !block_given?
|
139
162
|
where({ field_name => condition }, &cond_block)
|
140
163
|
end
|
data/test/functional/helper.rb
CHANGED
@@ -20,6 +20,7 @@ module FunctionalHelper
|
|
20
20
|
let(:examples_path) { File.join(repo_path, 'examples') }
|
21
21
|
|
22
22
|
let(:example_profile) { File.join(examples_path, 'profile') }
|
23
|
+
let(:example_control) { File.join(example_profile, 'controls', 'example.rb') }
|
23
24
|
let(:inheritance_profile) { File.join(examples_path, 'profile') }
|
24
25
|
|
25
26
|
let(:dst) {
|
@@ -37,7 +37,8 @@ describe 'inspec compliance' do
|
|
37
37
|
|
38
38
|
it 'inspec compliance profiles without authentication' do
|
39
39
|
out = inspec('compliance profile')
|
40
|
-
out.
|
40
|
+
out.stdout.must_include 'You need to login first with `inspec compliance login`'
|
41
|
+
out.exit_status.must_equal 0
|
41
42
|
end
|
42
43
|
|
43
44
|
it 'try to upload a profile without directory' do
|
@@ -48,8 +49,8 @@ describe 'inspec compliance' do
|
|
48
49
|
|
49
50
|
it 'try to upload a profile a non-existing path' do
|
50
51
|
out = inspec('compliance upload /path/to/dir')
|
51
|
-
out.stdout.must_include '
|
52
|
-
out.exit_status.must_equal
|
52
|
+
out.stdout.must_include 'You need to login first with `inspec compliance login`'
|
53
|
+
out.exit_status.must_equal 0
|
53
54
|
end
|
54
55
|
|
55
56
|
it 'logout' do
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'functional/helper'
|
6
|
+
|
7
|
+
describe 'inspec exec with json formatter' do
|
8
|
+
include FunctionalHelper
|
9
|
+
|
10
|
+
it 'can execute a simple file with the json formatter' do
|
11
|
+
out = inspec('exec ' + example_control + ' --format json')
|
12
|
+
out.stderr.must_equal ''
|
13
|
+
out.exit_status.must_equal 0
|
14
|
+
JSON.load(out.stdout).must_be_kind_of Hash
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can execute the profile with the json formatter' do
|
18
|
+
out = inspec('exec ' + example_profile + ' --format json')
|
19
|
+
out.stderr.must_equal ''
|
20
|
+
out.exit_status.must_equal 0
|
21
|
+
JSON.load(out.stdout).must_be_kind_of Hash
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'execute a profile with json formatting' do
|
25
|
+
let(:json) { JSON.load(inspec('exec ' + example_profile + ' --format json').stdout) }
|
26
|
+
let(:profile) { json['profiles']['profile'] }
|
27
|
+
let(:controls) { profile['controls'] }
|
28
|
+
let(:ex1) { controls['tmp-1.0'] }
|
29
|
+
let(:ex2) {
|
30
|
+
k = controls.keys.find { |x| x =~ /generated/ }
|
31
|
+
controls[k]
|
32
|
+
}
|
33
|
+
let(:ex3) { profile['controls']['gordon-1.0'] }
|
34
|
+
let(:check_result) {
|
35
|
+
ex3['results'].find { |x| x['resource'] == 'gordon_config' }
|
36
|
+
}
|
37
|
+
|
38
|
+
it 'has all the metadata' do
|
39
|
+
actual = profile.dup
|
40
|
+
key = actual.delete('controls').keys
|
41
|
+
.find { |x| x =~ /generated from example.rb/ }
|
42
|
+
|
43
|
+
actual.must_equal({
|
44
|
+
"name" => "profile",
|
45
|
+
"title" => "InSpec Example Profile",
|
46
|
+
"maintainer" => "Chef Software, Inc.",
|
47
|
+
"copyright" => "Chef Software, Inc.",
|
48
|
+
"copyright_email" => "support@chef.io",
|
49
|
+
"license" => "Apache 2 license",
|
50
|
+
"summary" => "Demonstrates the use of InSpec Compliance Profile",
|
51
|
+
"version" => "1.0.0",
|
52
|
+
"supports" => [{"os-family" => "unix"}],
|
53
|
+
"groups" => {
|
54
|
+
"controls/meta.rb" => {"title"=>"SSH Server Configuration", "controls"=>["ssh-1"]},
|
55
|
+
"controls/example.rb" => {"title"=>"/tmp profile", "controls"=>["tmp-1.0", key]},
|
56
|
+
"controls/gordon.rb" => {"title"=>"Gordon Config Checks", "controls"=>["gordon-1.0"]},
|
57
|
+
},
|
58
|
+
})
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'must have 4 controls' do
|
62
|
+
controls.length.must_equal 4
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'has an id for every control' do
|
66
|
+
controls.keys.find(&:nil?).must_be :nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'has no missing checks' do
|
70
|
+
json['other_checks'].must_equal([])
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'has results for every control' do
|
74
|
+
ex1['results'].length.must_equal 1
|
75
|
+
ex2['results'].length.must_equal 1
|
76
|
+
ex3['results'].length.must_equal 2
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'has the right result for tmp-1.0' do
|
80
|
+
actual = ex1.dup
|
81
|
+
|
82
|
+
src = actual.delete('source_location')
|
83
|
+
src[0].must_match %r{examples/profile/controls/example.rb$}
|
84
|
+
src[1].must_equal 8
|
85
|
+
|
86
|
+
result = actual.delete('results')[0]
|
87
|
+
result.wont_be :nil?
|
88
|
+
result['status'].must_equal 'passed'
|
89
|
+
result['code_desc'].must_equal 'File /tmp should be directory'
|
90
|
+
result['run_time'].wont_be :nil?
|
91
|
+
result['start_time'].wont_be :nil?
|
92
|
+
|
93
|
+
actual.must_equal({
|
94
|
+
"title" => "Create /tmp directory",
|
95
|
+
"desc" => "An optional description...",
|
96
|
+
"impact" => 0.7,
|
97
|
+
"refs" => [
|
98
|
+
{
|
99
|
+
"url" => "http://...",
|
100
|
+
"ref" => "Document A-12"
|
101
|
+
}
|
102
|
+
],
|
103
|
+
"tags" => {
|
104
|
+
"data" => "temp data",
|
105
|
+
"security" => nil
|
106
|
+
},
|
107
|
+
"code" => "control \"tmp-1.0\" do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title \"Create /tmp directory\" # A human-readable title\n desc \"An optional description...\" # Describe why this is needed\n tag data: \"temp data\" # A tag allows you to associate key information\n tag \"security\" # to the test\n ref \"Document A-12\", url: 'http://...' # Additional references\n\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n",
|
108
|
+
})
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'with a profile that is not supported on this OS/platform' do
|
113
|
+
let(:out) { inspec('exec ' + File.join(profile_path, 'skippy-profile-os') + ' --format json') }
|
114
|
+
let(:json) { JSON.load(out.stdout) }
|
115
|
+
|
116
|
+
# TODO: failure handling in json formatters...
|
117
|
+
|
118
|
+
it 'never runs the actual resource' do
|
119
|
+
File.exist?('/tmp/inspec_test_DONT_CREATE').must_equal false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|