inspec 1.6.0 → 1.7.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 +34 -2
- data/Rakefile +2 -2
- data/examples/meta-profile/inspec.yml +2 -2
- data/lib/bundles/inspec-compliance/api.rb +33 -11
- data/lib/bundles/inspec-compliance/cli.rb +73 -12
- data/lib/bundles/inspec-compliance/http.rb +8 -13
- data/lib/bundles/inspec-compliance/target.rb +17 -6
- data/lib/fetchers/url.rb +14 -2
- data/lib/inspec/base_cli.rb +30 -1
- data/lib/inspec/cli.rb +5 -30
- data/lib/inspec/dependencies/lockfile.rb +7 -2
- data/lib/inspec/profile.rb +8 -7
- data/lib/inspec/rspec_json_formatter.rb +106 -88
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/processes.rb +4 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a69a3a78ee7d17ad89e5d13c6445346393e1e1a1
|
4
|
+
data.tar.gz: 03059ff1d249a73bc2f49bdfbac8f162eb3ee3ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c71b46c3f283a84725615ebcdab4d8b0e58e301a7bd53ba0903a4abbd7e0d54af271b2d24dc21d1cafcbade09ced2ee5b1a4cc2af55594d47d925b9b39e13e46
|
7
|
+
data.tar.gz: db25eac456c658775d97fa388e68b7d1e8a39562615cfdaf5d76647d9045c5b4a4ab914f2a12d3321e4e44261f02eaa0ef8ea0017dc667663b98677323cb8cac
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,39 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [1.
|
4
|
-
[Full Changelog](https://github.com/chef/inspec/compare/v1.
|
3
|
+
## [1.7.0](https://github.com/chef/inspec/tree/1.7.0) (2016-12-02)
|
4
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v1.6.0...1.7.0)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- inspec compliance profiles should support automate as a backend [\#1295](https://github.com/chef/inspec/issues/1295)
|
9
|
+
- this is killing my eyes!!!!!!!!! [\#951](https://github.com/chef/inspec/issues/951)
|
10
|
+
- Show process name during inspec output [\#1329](https://github.com/chef/inspec/pull/1329) ([jcastillocano](https://github.com/jcastillocano))
|
11
|
+
|
12
|
+
**Fixed bugs:**
|
13
|
+
|
14
|
+
- inspec.lock not loaded from tarball profiles [\#1322](https://github.com/chef/inspec/issues/1322)
|
15
|
+
- InSpec tries to re-fetch profiles even if lockfile exists [\#1316](https://github.com/chef/inspec/issues/1316)
|
16
|
+
- fix docker release script [\#1328](https://github.com/chef/inspec/pull/1328) ([chris-rock](https://github.com/chris-rock))
|
17
|
+
- Provide inspec.lock for archives as well [\#1323](https://github.com/chef/inspec/pull/1323) ([alexpop](https://github.com/alexpop))
|
18
|
+
- inspec check and json to use vendored dependencies [\#1321](https://github.com/chef/inspec/pull/1321) ([alexpop](https://github.com/alexpop))
|
19
|
+
|
20
|
+
**Closed issues:**
|
21
|
+
|
22
|
+
- RegExp in processes resource can't match long-run process [\#1332](https://github.com/chef/inspec/issues/1332)
|
23
|
+
- inspec archive vendoring [\#1325](https://github.com/chef/inspec/issues/1325)
|
24
|
+
- inspec compliance upload of a meta-profile [\#1294](https://github.com/chef/inspec/issues/1294)
|
25
|
+
|
26
|
+
**Merged pull requests:**
|
27
|
+
|
28
|
+
- improve functional tests for vendored profiles [\#1337](https://github.com/chef/inspec/pull/1337) ([chris-rock](https://github.com/chris-rock))
|
29
|
+
- Adds junit to the inspec help exec [\#1336](https://github.com/chef/inspec/pull/1336) ([burtlo](https://github.com/burtlo))
|
30
|
+
- Vendor profile when uploading to chef-compliance [\#1334](https://github.com/chef/inspec/pull/1334) ([vjeffrey](https://github.com/vjeffrey))
|
31
|
+
- fix bug: RegExp in processes resource can't match long-run process \#1332 [\#1333](https://github.com/chef/inspec/pull/1333) ([Wing924](https://github.com/Wing924))
|
32
|
+
- clean up rspec\_json\_formatter [\#1314](https://github.com/chef/inspec/pull/1314) ([vjeffrey](https://github.com/vjeffrey))
|
33
|
+
- enable inspec compliance cli support automate [\#1297](https://github.com/chef/inspec/pull/1297) ([vjeffrey](https://github.com/vjeffrey))
|
34
|
+
|
35
|
+
## [v1.6.0](https://github.com/chef/inspec/tree/v1.6.0) (2016-11-28)
|
36
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v1.5.0...v1.6.0)
|
5
37
|
|
6
38
|
**Fixed bugs:**
|
7
39
|
|
data/Rakefile
CHANGED
@@ -163,8 +163,8 @@ task :release_docker do
|
|
163
163
|
cmd = "rm *.gem; gem build *gemspec && "\
|
164
164
|
"mv *.gem inspec.gem && "\
|
165
165
|
"docker build -t chef/inspec:#{version} . && "\
|
166
|
-
"docker push chef/inspec:#{version}"
|
167
|
-
"docker tag chef/inspec:#{version} chef/inspec:latest"
|
166
|
+
"docker push chef/inspec:#{version} && "\
|
167
|
+
"docker tag chef/inspec:#{version} chef/inspec:latest &&"\
|
168
168
|
"docker push chef/inspec:latest"
|
169
169
|
puts "--> #{cmd}"
|
170
170
|
sh('sh', '-c', cmd)
|
@@ -8,6 +8,6 @@ summary: InSpec Profile that is only consuming dependencies
|
|
8
8
|
version: 0.2.0
|
9
9
|
depends:
|
10
10
|
- name: hardening/ssh-hardening # defaults to supermarket
|
11
|
-
-
|
11
|
+
- url: https://github.com/dev-sec/ssl-benchmark
|
12
12
|
- name: windows-patch-benchmark
|
13
|
-
|
13
|
+
url: https://github.com/chris-rock/windows-patch-benchmark
|
@@ -8,12 +8,12 @@ require 'uri'
|
|
8
8
|
module Compliance
|
9
9
|
# API Implementation does not hold any state by itself,
|
10
10
|
# everything will be stored in local Configuration store
|
11
|
-
class API
|
11
|
+
class API # rubocop:disable Metrics/ClassLength
|
12
12
|
# return all compliance profiles available for the user
|
13
13
|
def self.profiles(config)
|
14
|
-
url = "#{config['server']}/user/compliance"
|
15
|
-
|
16
|
-
response = Compliance::HTTP.get(url,
|
14
|
+
config['server_type'] == 'automate' ? url = "#{config['server']}/#{config['user']}" : url = "#{config['server']}/user/compliance"
|
15
|
+
headers = get_headers(config)
|
16
|
+
response = Compliance::HTTP.get(url, headers, config['insecure'])
|
17
17
|
data = response.body
|
18
18
|
response_code = response.code
|
19
19
|
case response_code
|
@@ -21,11 +21,17 @@ module Compliance
|
|
21
21
|
msg = 'success'
|
22
22
|
profiles = JSON.parse(data)
|
23
23
|
# iterate over profiles
|
24
|
-
|
25
|
-
|
26
|
-
{ org:
|
27
|
-
end
|
28
|
-
|
24
|
+
if config['server_type'] == 'automate'
|
25
|
+
mapped_profiles = profiles.map do |owner, ps|
|
26
|
+
{ org: ps['owner_id'], name: owner }
|
27
|
+
end.flatten
|
28
|
+
else
|
29
|
+
mapped_profiles = profiles.map do |owner, ps|
|
30
|
+
ps.keys.map do |name|
|
31
|
+
{ org: owner, name: name }
|
32
|
+
end
|
33
|
+
end.flatten
|
34
|
+
end
|
29
35
|
return msg, mapped_profiles
|
30
36
|
when '401'
|
31
37
|
msg = '401 Unauthorized. Please check your token.'
|
@@ -69,8 +75,9 @@ Please login using `inspec compliance login https://compliance.test --user admin
|
|
69
75
|
|
70
76
|
def self.upload(config, owner, profile_name, archive_path)
|
71
77
|
# upload the tar to Chef Compliance
|
72
|
-
url = "#{config['server']}/owners/#{owner}/compliance/#{profile_name}/tar"
|
73
|
-
|
78
|
+
config['server_type'] == 'automate' ? url = "#{config['server']}/#{config['user']}" : url = "#{config['server']}/owners/#{owner}/compliance/#{profile_name}/tar"
|
79
|
+
headers = get_headers(config)
|
80
|
+
res = Compliance::HTTP.post_file(url, headers, archive_path, config['insecure'])
|
74
81
|
[res.is_a?(Net::HTTPSuccess), res.body]
|
75
82
|
end
|
76
83
|
|
@@ -121,5 +128,20 @@ Please login using `inspec compliance login https://compliance.test --user admin
|
|
121
128
|
|
122
129
|
[success, msg, access_token]
|
123
130
|
end
|
131
|
+
|
132
|
+
def self.get_headers(config)
|
133
|
+
if config['server_type'] == 'automate'
|
134
|
+
headers = { 'chef-delivery-enterprise' => config['automate']['ent'] }
|
135
|
+
if config['automate']['token_type'] == 'dctoken'
|
136
|
+
headers['x-data-collector-token'] = config['token']
|
137
|
+
else
|
138
|
+
headers['chef-delivery-user'] = config['user']
|
139
|
+
headers['chef-delivery-token'] = config['token']
|
140
|
+
end
|
141
|
+
else
|
142
|
+
headers = { 'Authorization' => "Bearer #{config['token']}" }
|
143
|
+
end
|
144
|
+
headers
|
145
|
+
end
|
124
146
|
end
|
125
147
|
end
|
@@ -36,6 +36,7 @@ module Compliance
|
|
36
36
|
|
37
37
|
options['server'] = server
|
38
38
|
url = options['server'] + options['apipath']
|
39
|
+
|
39
40
|
if !options['user'].nil? && !options['password'].nil?
|
40
41
|
# username / password
|
41
42
|
_success, msg = login_username_password(url, options['user'], options['password'], options['insecure'])
|
@@ -56,6 +57,35 @@ module Compliance
|
|
56
57
|
puts '', msg
|
57
58
|
end
|
58
59
|
|
60
|
+
desc "login_automate SERVER --user='USER' --ent='ENT' --dctoken or --usertoken='TOKEN'", 'Log in to an Automate SERVER'
|
61
|
+
option :dctoken, type: :string,
|
62
|
+
desc: 'Data Collector token'
|
63
|
+
option :usertoken, type: :string,
|
64
|
+
desc: 'Automate user token'
|
65
|
+
option :user, type: :string,
|
66
|
+
desc: 'Automate username'
|
67
|
+
option :ent, type: :string,
|
68
|
+
desc: 'Enterprise for Chef Automate reporting'
|
69
|
+
option :insecure, aliases: :k, type: :boolean,
|
70
|
+
desc: 'Explicitly allows InSpec to perform "insecure" SSL connections and transfers'
|
71
|
+
def login_automate(server) # rubocop:disable Metrics/AbcSize
|
72
|
+
options['server'] = server
|
73
|
+
url = options['server'] + '/compliance/profiles'
|
74
|
+
|
75
|
+
if url && !options['user'].nil? && !options['ent'].nil?
|
76
|
+
if !options['dctoken'].nil? || !options['usertoken'].nil?
|
77
|
+
msg = login_automate_config(url, options['user'], options['dctoken'], options['usertoken'], options['ent'], options['insecure'])
|
78
|
+
else
|
79
|
+
puts "Please specify a token using --dctoken='DATA_COLLECTOR_TOKEN' or usertoken='AUTOMATE_TOKEN' "
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
else
|
83
|
+
puts "Please login to your automate instance using 'inspec compliance login_automate SERVER --user AUTOMATE_USER --ent AUTOMATE_ENT --dctoken DC_TOKEN or --usertoken USER_TOKEN' "
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
puts '', msg
|
87
|
+
end
|
88
|
+
|
59
89
|
desc 'profiles', 'list all available profiles in Chef Compliance'
|
60
90
|
def profiles
|
61
91
|
config = Compliance::Configuration.new
|
@@ -79,10 +109,8 @@ module Compliance
|
|
79
109
|
def exec(*tests)
|
80
110
|
config = Compliance::Configuration.new
|
81
111
|
return if !loggedin(config)
|
82
|
-
|
83
112
|
# iterate over tests and add compliance scheme
|
84
113
|
tests = tests.map { |t| 'compliance://' + t }
|
85
|
-
|
86
114
|
# execute profile from inspec exec implementation
|
87
115
|
diagnose
|
88
116
|
run_tests(tests, opts)
|
@@ -100,6 +128,8 @@ module Compliance
|
|
100
128
|
exit 1
|
101
129
|
end
|
102
130
|
|
131
|
+
vendor_deps(path, options) if File.directory?(path)
|
132
|
+
|
103
133
|
o = options.dup
|
104
134
|
configure_logger(o)
|
105
135
|
# check the profile, we only allow to upload valid profiles
|
@@ -144,7 +174,6 @@ module Compliance
|
|
144
174
|
# if it is a directory, tar it to tmp directory
|
145
175
|
if File.directory?(path)
|
146
176
|
archive_path = Dir::Tmpname.create([profile_name, '.tar.gz']) {}
|
147
|
-
# archive_path = file.path
|
148
177
|
puts "Generate temporary profile archive at #{archive_path}"
|
149
178
|
profile.archive({ output: archive_path, ignore_errors: false, overwrite: true })
|
150
179
|
else
|
@@ -154,7 +183,8 @@ module Compliance
|
|
154
183
|
puts "Start upload to #{owner}/#{profile_name}"
|
155
184
|
pname = ERB::Util.url_encode(profile_name)
|
156
185
|
|
157
|
-
|
186
|
+
config['server_type'] == 'automate' ? upload_msg = 'Uploading to Chef Automate' : upload_msg = 'Uploading to Chef Compliance'
|
187
|
+
puts upload_msg
|
158
188
|
success, msg = Compliance::API.upload(config, owner, pname, archive_path)
|
159
189
|
|
160
190
|
if success
|
@@ -169,24 +199,27 @@ module Compliance
|
|
169
199
|
desc 'version', 'displays the version of the Chef Compliance server'
|
170
200
|
def version
|
171
201
|
config = Compliance::Configuration.new
|
172
|
-
|
173
|
-
|
174
|
-
puts "Chef Compliance version: #{info['version']}"
|
202
|
+
if config['server_type'] == 'automate'
|
203
|
+
puts 'Version not available when logged in with Automate.'
|
175
204
|
else
|
176
|
-
|
177
|
-
|
205
|
+
info = Compliance::API.version(config['server'], config['insecure'])
|
206
|
+
if !info.nil? && info['version']
|
207
|
+
puts "Chef Compliance version: #{info['version']}"
|
208
|
+
else
|
209
|
+
puts 'Could not determine server version.'
|
210
|
+
exit 1
|
211
|
+
end
|
178
212
|
end
|
179
213
|
end
|
180
214
|
|
181
215
|
desc 'logout', 'user logout from Chef Compliance'
|
182
216
|
def logout
|
183
217
|
config = Compliance::Configuration.new
|
184
|
-
unless config.supported?(:oidc) || config['token'].nil?
|
218
|
+
unless config.supported?(:oidc) || config['token'].nil? || config['server_type'] == 'automate'
|
185
219
|
config = Compliance::Configuration.new
|
186
220
|
url = "#{config['server']}/logout"
|
187
221
|
Compliance::API.post(url, config['token'], config['insecure'], !config.supported?(:oidc))
|
188
222
|
end
|
189
|
-
|
190
223
|
success = config.destroy
|
191
224
|
|
192
225
|
if success
|
@@ -198,6 +231,32 @@ module Compliance
|
|
198
231
|
|
199
232
|
private
|
200
233
|
|
234
|
+
def login_automate_config(url, user, dctoken, usertoken, ent, insecure) # rubocop:disable Metrics/ParameterLists
|
235
|
+
config = Compliance::Configuration.new
|
236
|
+
config['user'] = user
|
237
|
+
config['server'] = url
|
238
|
+
config['automate'] = {}
|
239
|
+
config['automate']['ent'] = ent
|
240
|
+
config['server_type'] = 'automate'
|
241
|
+
config['insecure'] = insecure
|
242
|
+
|
243
|
+
# determine token method being used
|
244
|
+
if !dctoken.nil?
|
245
|
+
config['token'] = dctoken
|
246
|
+
token_type = 'dctoken'
|
247
|
+
token_msg = 'data collector token'
|
248
|
+
else
|
249
|
+
config['token'] = usertoken
|
250
|
+
token_type = 'usertoken'
|
251
|
+
token_msg = 'automate user token'
|
252
|
+
end
|
253
|
+
|
254
|
+
config['automate']['token_type'] = token_type
|
255
|
+
config.store
|
256
|
+
msg = "Stored configuration for Chef Automate: '#{url}' with user: '#{user}', ent: '#{ent}' and your #{token_msg}"
|
257
|
+
msg
|
258
|
+
end
|
259
|
+
|
201
260
|
def login_refreshtoken(url, options)
|
202
261
|
success, msg, access_token = Compliance::API.get_token_via_refresh_token(url, options['refresh_token'], options['insecure'])
|
203
262
|
if success
|
@@ -206,6 +265,7 @@ module Compliance
|
|
206
265
|
config['token'] = access_token
|
207
266
|
config['insecure'] = options['insecure']
|
208
267
|
config['version'] = Compliance::API.version(url, options['insecure'])
|
268
|
+
config['server_type'] = 'compliance'
|
209
269
|
config.store
|
210
270
|
end
|
211
271
|
|
@@ -221,6 +281,7 @@ module Compliance
|
|
221
281
|
config['token'] = api_token
|
222
282
|
config['insecure'] = insecure
|
223
283
|
config['version'] = Compliance::API.version(url, insecure)
|
284
|
+
config['server_type'] = 'compliance'
|
224
285
|
config.store
|
225
286
|
success = true
|
226
287
|
end
|
@@ -267,7 +328,7 @@ module Compliance
|
|
267
328
|
|
268
329
|
def loggedin(config)
|
269
330
|
serverknown = !config['server'].nil?
|
270
|
-
puts 'You need to login first with `inspec compliance login`' if !serverknown
|
331
|
+
puts 'You need to login first with `inspec compliance login` or `inspec compliance login_automate`' if !serverknown
|
271
332
|
serverknown
|
272
333
|
end
|
273
334
|
end
|
@@ -9,16 +9,13 @@ module Compliance
|
|
9
9
|
# implements a simple http abstraction on top of Net::HTTP
|
10
10
|
class HTTP
|
11
11
|
# generic get requires
|
12
|
-
def self.get(url,
|
12
|
+
def self.get(url, headers = nil, insecure)
|
13
13
|
uri = URI.parse(url)
|
14
14
|
req = Net::HTTP::Get.new(uri.path)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
req.basic_auth(token, '')
|
20
|
-
else
|
21
|
-
req['Authorization'] = "Bearer #{token}"
|
15
|
+
if !headers.nil?
|
16
|
+
headers.each do |key, value|
|
17
|
+
req.add_field(key, value)
|
18
|
+
end
|
22
19
|
end
|
23
20
|
send_request(uri, req, insecure)
|
24
21
|
end
|
@@ -39,7 +36,7 @@ module Compliance
|
|
39
36
|
end
|
40
37
|
|
41
38
|
# post a file
|
42
|
-
def self.post_file(url,
|
39
|
+
def self.post_file(url, headers, file_path, insecure)
|
43
40
|
uri = URI.parse(url)
|
44
41
|
fail "Unable to parse URL: #{url}" if uri.nil? || uri.host.nil?
|
45
42
|
http = Net::HTTP.new(uri.host, uri.port)
|
@@ -49,10 +46,8 @@ module Compliance
|
|
49
46
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if insecure
|
50
47
|
|
51
48
|
req = Net::HTTP::Post.new(uri.path)
|
52
|
-
|
53
|
-
req.
|
54
|
-
else
|
55
|
-
req['Authorization'] = "Bearer #{token}"
|
49
|
+
headers.each do |key, value|
|
50
|
+
req.add_field(key, value)
|
56
51
|
end
|
57
52
|
|
58
53
|
req.body_stream=File.open(file_path, 'rb')
|
@@ -13,8 +13,7 @@ module Compliance
|
|
13
13
|
class Fetcher < Fetchers::Url
|
14
14
|
name 'compliance'
|
15
15
|
priority 500
|
16
|
-
|
17
|
-
def self.resolve(target)
|
16
|
+
def self.resolve(target) # rubocop:disable PerceivedComplexity
|
18
17
|
uri = if target.is_a?(String) && URI(target).scheme == 'compliance'
|
19
18
|
URI(target)
|
20
19
|
elsif target.respond_to?(:key?) && target.key?(:compliance)
|
@@ -26,14 +25,21 @@ module Compliance
|
|
26
25
|
# check if we have a compliance token
|
27
26
|
config = Compliance::Configuration.new
|
28
27
|
if config['token'].nil?
|
28
|
+
if config['server_type'] == 'automate'
|
29
|
+
server = 'automate'
|
30
|
+
msg = 'inspec compliance login_automate https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --usertoken USERTOKEN'
|
31
|
+
else
|
32
|
+
server = 'compliance'
|
33
|
+
msg = "inspec compliance login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE' "
|
34
|
+
end
|
29
35
|
fail Inspec::FetcherFailure, <<EOF
|
30
36
|
|
31
|
-
Cannot fetch #{uri} because your
|
37
|
+
Cannot fetch #{uri} because your #{server} token has not been
|
32
38
|
configured.
|
33
39
|
|
34
40
|
Please login using
|
35
41
|
|
36
|
-
|
42
|
+
#{msg}
|
37
43
|
EOF
|
38
44
|
end
|
39
45
|
|
@@ -48,8 +54,13 @@ EOF
|
|
48
54
|
end
|
49
55
|
|
50
56
|
def self.target_url(profile, config)
|
51
|
-
|
52
|
-
|
57
|
+
if config['server_type'] == 'automate'
|
58
|
+
target = "#{config['server']}/#{profile}/tar"
|
59
|
+
else
|
60
|
+
owner, id = profile.split('/')
|
61
|
+
target = "#{config['server']}/owners/#{owner}/compliance/#{id}/tar"
|
62
|
+
end
|
63
|
+
target
|
53
64
|
end
|
54
65
|
|
55
66
|
#
|
data/lib/fetchers/url.rb
CHANGED
@@ -8,7 +8,7 @@ require 'tempfile'
|
|
8
8
|
require 'open-uri'
|
9
9
|
|
10
10
|
module Fetchers
|
11
|
-
class Url < Inspec.fetcher(1)
|
11
|
+
class Url < Inspec.fetcher(1) # rubocop:disable Metrics/ClassLength
|
12
12
|
MIME_TYPES = {
|
13
13
|
'application/x-zip-compressed' => '.zip',
|
14
14
|
'application/zip' => '.zip',
|
@@ -126,7 +126,19 @@ module Fetchers
|
|
126
126
|
Inspec::Log.debug("Fetching URL: #{@target}")
|
127
127
|
http_opts = {}
|
128
128
|
http_opts['ssl_verify_mode'.to_sym] = OpenSSL::SSL::VERIFY_NONE if @insecure
|
129
|
-
|
129
|
+
if @config
|
130
|
+
if @config['server_type'] == 'automate'
|
131
|
+
http_opts['chef-delivery-enterprise'] = @config['automate']['ent']
|
132
|
+
if @config['automate']['token_type'] == 'dctoken'
|
133
|
+
http_opts['x-data-collector-token'] = @config['token']
|
134
|
+
else
|
135
|
+
http_opts['chef-delivery-user'] = @config['user']
|
136
|
+
http_opts['chef-delivery-token'] = @config['token']
|
137
|
+
end
|
138
|
+
elsif @token
|
139
|
+
http_opts['Authorization'] = "Bearer #{@token}"
|
140
|
+
end
|
141
|
+
end
|
130
142
|
remote = open(@target, http_opts)
|
131
143
|
@archive_type = file_type_from_remote(remote) # side effect :(
|
132
144
|
archive = Tempfile.new(['inspec-dl-', @archive_type])
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -57,7 +57,7 @@ module Inspec
|
|
57
57
|
option :controls, type: :array,
|
58
58
|
desc: 'A list of controls to run. Ignore all other tests.'
|
59
59
|
option :format, type: :string,
|
60
|
-
desc: 'Which formatter to use: cli, progress, documentation, json, json-min'
|
60
|
+
desc: 'Which formatter to use: cli, progress, documentation, json, json-min, junit'
|
61
61
|
option :color, type: :boolean, default: true,
|
62
62
|
desc: 'Use colors in output.'
|
63
63
|
option :attrs, type: :array,
|
@@ -146,6 +146,35 @@ module Inspec
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
+
def vendor_deps(path, opts)
|
150
|
+
path.nil? ? path = Pathname.new(Dir.pwd) : path = Pathname.new(path)
|
151
|
+
cache_path = path.join('vendor')
|
152
|
+
inspec_lock = path.join('inspec.lock')
|
153
|
+
|
154
|
+
if (cache_path.exist? || inspec_lock.exist?) && !opts[:overwrite]
|
155
|
+
puts 'Profile is already vendored. Use --overwrite.'
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
|
159
|
+
# remove existing
|
160
|
+
FileUtils.rm_rf(cache_path) if cache_path.exist?
|
161
|
+
File.delete(inspec_lock) if inspec_lock.exist?
|
162
|
+
|
163
|
+
puts "Vendor dependencies of #{path} into #{cache_path}"
|
164
|
+
opts[:logger] = Logger.new(STDOUT)
|
165
|
+
opts[:logger].level = get_log_level(opts.log_level)
|
166
|
+
opts[:cache] = Inspec::Cache.new(cache_path.to_s)
|
167
|
+
opts[:backend] = Inspec::Backend.create(target: 'mock://')
|
168
|
+
configure_logger(opts)
|
169
|
+
|
170
|
+
# vendor dependencies and generate lockfile
|
171
|
+
profile = Inspec::Profile.for_target(path.to_s, opts)
|
172
|
+
lockfile = profile.generate_lockfile
|
173
|
+
File.write(inspec_lock, lockfile.to_yaml)
|
174
|
+
rescue StandardError => e
|
175
|
+
pretty_handle_exception(e)
|
176
|
+
end
|
177
|
+
|
149
178
|
def configure_logger(o)
|
150
179
|
#
|
151
180
|
# TODO(ssd): This is a big gross, but this configures the
|
data/lib/inspec/cli.rb
CHANGED
@@ -33,6 +33,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
33
33
|
def json(target)
|
34
34
|
diagnose
|
35
35
|
o = opts.dup
|
36
|
+
configure_logger(o)
|
36
37
|
o[:ignore_supports] = true
|
37
38
|
o[:backend] = Inspec::Backend.create(target: 'mock://')
|
38
39
|
|
@@ -59,7 +60,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
59
60
|
def check(path) # rubocop:disable Metrics/AbcSize
|
60
61
|
diagnose
|
61
62
|
o = opts.dup
|
62
|
-
|
63
|
+
configure_logger(o)
|
63
64
|
o[:ignore_supports] = true # we check for integrity only
|
64
65
|
o[:backend] = Inspec::Backend.create(target: 'mock://')
|
65
66
|
|
@@ -108,35 +109,9 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
108
109
|
desc 'vendor PATH', 'Download all dependencies and generate a lockfile in a `vendor` directory'
|
109
110
|
option :overwrite, type: :boolean, default: false,
|
110
111
|
desc: 'Overwrite existing vendored dependencies and lockfile.'
|
111
|
-
def vendor(path = nil)
|
112
|
+
def vendor(path = nil)
|
112
113
|
o = opts.dup
|
113
|
-
|
114
|
-
path.nil? ? path = Pathname.new(Dir.pwd) : path = Pathname.new(path)
|
115
|
-
cache_path = path.join('vendor')
|
116
|
-
inspec_lock = path.join('inspec.lock')
|
117
|
-
|
118
|
-
if (cache_path.exist? || inspec_lock.exist?) && !opts[:overwrite]
|
119
|
-
puts 'Profile is already vendored. Use --overwrite.'
|
120
|
-
return false
|
121
|
-
end
|
122
|
-
|
123
|
-
# remove existing
|
124
|
-
FileUtils.rm_rf(cache_path) if cache_path.exist?
|
125
|
-
File.delete(inspec_lock) if inspec_lock.exist?
|
126
|
-
|
127
|
-
puts "Vendor dependencies of #{path} into #{cache_path}"
|
128
|
-
o[:logger] = Logger.new(STDOUT)
|
129
|
-
o[:logger].level = get_log_level(o.log_level)
|
130
|
-
o[:cache] = Inspec::Cache.new(cache_path.to_s)
|
131
|
-
o[:backend] = Inspec::Backend.create(target: 'mock://')
|
132
|
-
configure_logger(o)
|
133
|
-
|
134
|
-
# vendor dependencies and generate lockfile
|
135
|
-
profile = Inspec::Profile.for_target(path.to_s, o)
|
136
|
-
lockfile = profile.generate_lockfile
|
137
|
-
File.write(inspec_lock, lockfile.to_yaml)
|
138
|
-
rescue StandardError => e
|
139
|
-
pretty_handle_exception(e)
|
114
|
+
vendor_deps(path, o)
|
140
115
|
end
|
141
116
|
|
142
117
|
desc 'archive PATH', 'archive a profile to tar.gz (default) or zip'
|
@@ -211,7 +186,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
211
186
|
option :command, aliases: :c,
|
212
187
|
desc: 'A single command string to run instead of launching the shell'
|
213
188
|
option :format, type: :string, default: nil, hide: true,
|
214
|
-
desc: 'Which formatter to use: cli, progress, documentation, json, json-min'
|
189
|
+
desc: 'Which formatter to use: cli, progress, documentation, json, json-min, junit'
|
215
190
|
def shell_func
|
216
191
|
diagnose
|
217
192
|
o = opts.dup
|
@@ -15,14 +15,19 @@ module Inspec
|
|
15
15
|
new(lockfile_content)
|
16
16
|
end
|
17
17
|
|
18
|
-
def self.
|
19
|
-
parsed_content = YAML.load(
|
18
|
+
def self.from_content(content)
|
19
|
+
parsed_content = YAML.load(content)
|
20
20
|
version = parsed_content['lockfile_version']
|
21
21
|
fail "No lockfile_version set in #{path}!" if version.nil?
|
22
22
|
validate_lockfile_version!(version.to_i)
|
23
23
|
new(parsed_content)
|
24
24
|
end
|
25
25
|
|
26
|
+
def self.from_file(path)
|
27
|
+
content = File.read(path)
|
28
|
+
from_content(content)
|
29
|
+
end
|
30
|
+
|
26
31
|
def self.validate_lockfile_version!(version)
|
27
32
|
if version < MINIMUM_SUPPORTED_VERSION
|
28
33
|
fail <<EOF
|
data/lib/inspec/profile.rb
CHANGED
@@ -21,10 +21,9 @@ module Inspec
|
|
21
21
|
class Profile # rubocop:disable Metrics/ClassLength
|
22
22
|
extend Forwardable
|
23
23
|
|
24
|
-
def self.resolve_target(target, cache
|
25
|
-
|
26
|
-
Inspec::
|
27
|
-
Inspec::CachedFetcher.new(target, cache || Cache.new)
|
24
|
+
def self.resolve_target(target, cache)
|
25
|
+
Inspec::Log.debug "Resolve #{target} into cache #{cache.path}"
|
26
|
+
Inspec::CachedFetcher.new(target, cache)
|
28
27
|
end
|
29
28
|
|
30
29
|
# Check if the profile contains a vendored cache, move content into global cache
|
@@ -65,11 +64,13 @@ module Inspec
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def self.for_fetcher(fetcher, opts)
|
67
|
+
opts[:cache] = opts[:cache] || Cache.new
|
68
68
|
path, writable = fetcher.fetch
|
69
69
|
for_path(path, opts.merge(target: fetcher.target, writable: writable))
|
70
70
|
end
|
71
71
|
|
72
72
|
def self.for_target(target, opts = {})
|
73
|
+
opts[:cache] = opts[:cache] || Cache.new
|
73
74
|
fetcher = resolve_target(target, opts[:cache])
|
74
75
|
for_fetcher(fetcher, opts)
|
75
76
|
end
|
@@ -205,7 +206,7 @@ module Inspec
|
|
205
206
|
res
|
206
207
|
end
|
207
208
|
|
208
|
-
# Check if the profile is
|
209
|
+
# Check if the profile is internally well-structured. The logger will be
|
209
210
|
# used to print information on errors and warnings which are found.
|
210
211
|
#
|
211
212
|
# @return [Boolean] true if no errors were found, false otherwise
|
@@ -342,7 +343,7 @@ module Inspec
|
|
342
343
|
end
|
343
344
|
|
344
345
|
def lockfile_exists?
|
345
|
-
|
346
|
+
@source_reader.target.files.include?('inspec.lock')
|
346
347
|
end
|
347
348
|
|
348
349
|
def lockfile_path
|
@@ -360,7 +361,7 @@ module Inspec
|
|
360
361
|
|
361
362
|
def lockfile
|
362
363
|
@lockfile ||= if lockfile_exists?
|
363
|
-
Inspec::Lockfile.
|
364
|
+
Inspec::Lockfile.from_content(@source_reader.target.read('inspec.lock'))
|
364
365
|
else
|
365
366
|
generate_lockfile
|
366
367
|
end
|
@@ -280,13 +280,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
280
280
|
MULTI_TEST_CONTROL_SUMMARY_MAX_LEN = 60
|
281
281
|
|
282
282
|
def initialize(*args)
|
283
|
-
@colors = COLORS
|
284
|
-
@indicators = INDICATORS
|
285
|
-
|
286
|
-
@format = '%color%indicator%id%summary'
|
287
283
|
@current_control = nil
|
288
|
-
@current_profile = nil
|
289
|
-
@missing_controls = []
|
290
284
|
@anonymous_tests = []
|
291
285
|
@control_tests = []
|
292
286
|
@profile_printed = false
|
@@ -294,12 +288,12 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
294
288
|
end
|
295
289
|
|
296
290
|
def close(_notification) # rubocop:disable Metrics/AbcSize
|
297
|
-
flush_current_control
|
291
|
+
flush_current_control(@current_control)
|
298
292
|
output.puts('') unless @current_control.nil?
|
299
|
-
print_tests
|
293
|
+
print_tests(@anonymous_tests)
|
300
294
|
output.puts('')
|
301
295
|
|
302
|
-
print_profiles_info if !@profile_printed
|
296
|
+
print_profiles_info(@current_control) if !@profile_printed
|
303
297
|
controls_res = controls_summary
|
304
298
|
tests_res = tests_summary
|
305
299
|
|
@@ -318,6 +312,31 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
318
312
|
|
319
313
|
private
|
320
314
|
|
315
|
+
# Formats example; calls example2control, gets a 'status_type', and calls
|
316
|
+
# flush current_control; returns control data
|
317
|
+
def format_example(example)
|
318
|
+
data = super(example)
|
319
|
+
control = example2control(data, @profiles_info) || {}
|
320
|
+
control[:id] = data[:id]
|
321
|
+
control[:profile_id] = data[:profile_id]
|
322
|
+
|
323
|
+
data[:status_type] = status_type(data, control)
|
324
|
+
dump_one_example(data, control)
|
325
|
+
|
326
|
+
@current_control ||= control
|
327
|
+
if !control[:id].nil?
|
328
|
+
if @current_control[:id] != control[:id]
|
329
|
+
flush_current_control(@current_control)
|
330
|
+
@current_control = control
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
data
|
335
|
+
end
|
336
|
+
|
337
|
+
# Determines 'status_type' (critical, major, minor) of control given
|
338
|
+
# status (failed/passed/skipped) and impact value (0.0 - 1.0).
|
339
|
+
# Called from format_example, sets the 'status_type' for each 'example'
|
321
340
|
def status_type(data, control)
|
322
341
|
status = data[:status]
|
323
342
|
return status if status != 'failed' || control[:impact].nil?
|
@@ -330,12 +349,45 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
330
349
|
end
|
331
350
|
end
|
332
351
|
|
333
|
-
|
352
|
+
# TODO: does a lot of stuff!
|
353
|
+
# Called from format_example and close
|
354
|
+
def flush_current_control(current_control)
|
355
|
+
return if current_control.nil?
|
356
|
+
|
357
|
+
profile = @profiles_info.find { |i| i[:id] == current_control[:profile_id] }
|
358
|
+
print_current_profile(profile) if !@profile_printed
|
359
|
+
|
360
|
+
fails, skips, passes, summary_indicator = current_control_infos(current_control)
|
361
|
+
summary = current_control_summary(fails, skips, current_control)
|
362
|
+
|
363
|
+
control_id = current_control[:id].to_s
|
364
|
+
control_id += ': '
|
365
|
+
if control_id.start_with? '(generated from '
|
366
|
+
@anonymous_tests.push(current_control)
|
367
|
+
else
|
368
|
+
@control_tests.push(current_control)
|
369
|
+
print_line(
|
370
|
+
color: COLORS[summary_indicator] || '',
|
371
|
+
indicator: INDICATORS[summary_indicator] || INDICATORS['unknown'],
|
372
|
+
summary: format_lines(summary, INDICATORS['empty']),
|
373
|
+
id: control_id,
|
374
|
+
profile: current_control[:profile_id],
|
375
|
+
)
|
376
|
+
|
377
|
+
print_results(fails + skips + passes)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
############# Current control methods #############
|
382
|
+
|
383
|
+
# Takes current_control (called from flush_current_control) and returns
|
384
|
+
# fails, skips, passes.
|
385
|
+
def current_control_infos(current_control)
|
334
386
|
summary_status = STATUS_TYPES['unknown']
|
335
387
|
skips = []
|
336
388
|
fails = []
|
337
389
|
passes = []
|
338
|
-
|
390
|
+
current_control[:results].each do |r|
|
339
391
|
i = STATUS_TYPES[r[:status_type]]
|
340
392
|
summary_status = i if i > summary_status
|
341
393
|
fails.push(r) if i > 0
|
@@ -345,9 +397,11 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
345
397
|
[fails, skips, passes, STATUS_TYPES.key(summary_status)]
|
346
398
|
end
|
347
399
|
|
348
|
-
|
349
|
-
|
350
|
-
|
400
|
+
# Determine title for control given current_control.
|
401
|
+
# Called from current_control_summary.
|
402
|
+
def current_control_title(current_control)
|
403
|
+
title = current_control[:title]
|
404
|
+
res = current_control[:results]
|
351
405
|
if title
|
352
406
|
title
|
353
407
|
elsif res.length == 1
|
@@ -368,9 +422,10 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
368
422
|
end
|
369
423
|
end
|
370
424
|
|
371
|
-
|
372
|
-
|
373
|
-
|
425
|
+
# Return summary of current_control, called from flush_current_control
|
426
|
+
def current_control_summary(fails, skips, current_control)
|
427
|
+
title = current_control_title(current_control)
|
428
|
+
res = current_control[:results]
|
374
429
|
suffix =
|
375
430
|
if res.length == 1
|
376
431
|
# Single test - be nice and just print the exception message if the test
|
@@ -389,27 +444,34 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
389
444
|
end
|
390
445
|
end
|
391
446
|
|
447
|
+
############# Print results and lines methods #############
|
448
|
+
|
449
|
+
# Formats the line (called from print_line)
|
392
450
|
def format_line(fields)
|
393
|
-
|
451
|
+
format = '%color%indicator%id%summary'
|
452
|
+
format.gsub(/%\w+/) do |x|
|
394
453
|
term = x[1..-1]
|
395
454
|
fields.key?(term.to_sym) ? fields[term.to_sym].to_s : x
|
396
|
-
end +
|
455
|
+
end + COLORS['reset']
|
397
456
|
end
|
398
457
|
|
458
|
+
# Prints line; used to print results
|
399
459
|
def print_line(fields)
|
400
460
|
output.puts(format_line(fields))
|
401
461
|
end
|
402
462
|
|
463
|
+
# Helps formatting summary lines (called from within print_line arguments)
|
403
464
|
def format_lines(lines, indentation)
|
404
465
|
lines.gsub(/\n/, "\n" + indentation)
|
405
466
|
end
|
406
467
|
|
468
|
+
# Sorts through results, calls print_line (called from flush_current_control)
|
407
469
|
def print_results(all)
|
408
470
|
all.each do |x|
|
409
471
|
test_status = x[:status_type]
|
410
|
-
test_color =
|
411
|
-
indicator =
|
412
|
-
indicator =
|
472
|
+
test_color = COLORS[test_status]
|
473
|
+
indicator = INDICATORS[x[:status]]
|
474
|
+
indicator = INDICATORS['empty'] if indicator.nil?
|
413
475
|
if x[:message]
|
414
476
|
msg = x[:code_desc] + "\n" + x[:message]
|
415
477
|
else
|
@@ -417,15 +479,16 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
417
479
|
end
|
418
480
|
print_line(
|
419
481
|
color: test_color,
|
420
|
-
indicator:
|
421
|
-
summary: format_lines(msg,
|
482
|
+
indicator: INDICATORS['small'] + indicator,
|
483
|
+
summary: format_lines(msg, INDICATORS['empty']),
|
422
484
|
id: nil, profile: nil
|
423
485
|
)
|
424
486
|
end
|
425
487
|
end
|
426
488
|
|
427
|
-
|
428
|
-
|
489
|
+
# Prints anonymous describe blocks; called from close method
|
490
|
+
def print_tests(anonymous_tests) # rubocop:disable Metrics/AbcSize
|
491
|
+
anonymous_tests.each do |control|
|
429
492
|
control_result = control[:results]
|
430
493
|
title = control_result[0][:code_desc].split[0..1].join(' ')
|
431
494
|
puts ' ' + title
|
@@ -443,9 +506,9 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
443
506
|
end
|
444
507
|
status_indicator = test[:status_type]
|
445
508
|
print_line(
|
446
|
-
color:
|
447
|
-
indicator:
|
448
|
-
summary: format_lines(test_result,
|
509
|
+
color: COLORS[status_indicator] || '',
|
510
|
+
indicator: INDICATORS['small'] + INDICATORS[status_indicator] || INDICATORS['unknown'],
|
511
|
+
summary: format_lines(test_result, INDICATORS['empty']),
|
449
512
|
id: control_id,
|
450
513
|
profile: control[:profile_id],
|
451
514
|
)
|
@@ -453,57 +516,33 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
453
516
|
end
|
454
517
|
end
|
455
518
|
|
456
|
-
|
457
|
-
return if @current_control.nil?
|
458
|
-
|
459
|
-
@current_profile = @profiles_info.find { |i| i[:id] == @current_control[:profile_id] }
|
460
|
-
print_current_profile if !@profile_printed
|
461
|
-
|
462
|
-
fails, skips, passes, summary_indicator = current_control_infos
|
463
|
-
summary = current_control_summary(fails, skips)
|
464
|
-
|
465
|
-
control_id = @current_control[:id].to_s
|
466
|
-
control_id += ': '
|
467
|
-
if control_id.start_with? '(generated from '
|
468
|
-
@anonymous_tests.push(@current_control)
|
469
|
-
else
|
470
|
-
@control_tests.push(@current_control)
|
471
|
-
print_line(
|
472
|
-
color: @colors[summary_indicator] || '',
|
473
|
-
indicator: @indicators[summary_indicator] || @indicators['unknown'],
|
474
|
-
summary: format_lines(summary, @indicators['empty']),
|
475
|
-
id: control_id,
|
476
|
-
profile: @current_control[:profile_id],
|
477
|
-
)
|
478
|
-
|
479
|
-
print_results(fails + skips + passes)
|
480
|
-
end
|
481
|
-
end
|
519
|
+
############# Print profile info methods #############
|
482
520
|
|
483
|
-
|
521
|
+
# Prints target information; called from print_current_profile
|
522
|
+
def print_target
|
484
523
|
return if @backend.nil?
|
485
524
|
connection = @backend.backend
|
486
525
|
return unless connection.respond_to?(:uri)
|
487
|
-
output.puts(
|
526
|
+
output.puts('Target: ' + connection.uri + "\n\n")
|
488
527
|
end
|
489
528
|
|
490
|
-
|
529
|
+
# Prints blank info is no current_control is defined
|
530
|
+
# Called from print_current_profile and close
|
531
|
+
def print_profiles_info(current_control)
|
491
532
|
@profiles_info.each do |profile|
|
492
533
|
next if profile[:already_printed]
|
493
|
-
|
494
|
-
next unless print_current_profile
|
534
|
+
next unless print_current_profile(profile)
|
495
535
|
print_line(
|
496
|
-
color: '', indicator:
|
536
|
+
color: '', indicator: INDICATORS['empty'], id: '', profile: '',
|
497
537
|
summary: 'No tests executed.'
|
498
|
-
) if
|
538
|
+
) if current_control.nil?
|
499
539
|
output.puts('')
|
500
540
|
end
|
501
541
|
end
|
502
542
|
|
503
|
-
def print_current_profile
|
504
|
-
profile = @current_profile
|
543
|
+
def print_current_profile(profile)
|
505
544
|
if profile.nil?
|
506
|
-
print_profiles_info
|
545
|
+
print_profiles_info(@current_control)
|
507
546
|
@profile_printed = true
|
508
547
|
return true
|
509
548
|
end
|
@@ -511,7 +550,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
511
550
|
profile[:already_printed] = true
|
512
551
|
|
513
552
|
if profile[:name].nil?
|
514
|
-
print_target
|
553
|
+
print_target
|
515
554
|
@profile_printed = true
|
516
555
|
return true
|
517
556
|
end
|
@@ -523,31 +562,10 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
523
562
|
end
|
524
563
|
|
525
564
|
output.puts 'Version: ' + (profile[:version] || 'unknown')
|
526
|
-
print_target
|
527
|
-
output.puts
|
565
|
+
print_target
|
528
566
|
@profile_printed = true
|
529
567
|
true
|
530
568
|
end
|
531
|
-
|
532
|
-
def format_example(example)
|
533
|
-
data = super(example)
|
534
|
-
control = example2control(data, @profiles_info) || {}
|
535
|
-
control[:id] = data[:id]
|
536
|
-
control[:profile_id] = data[:profile_id]
|
537
|
-
|
538
|
-
data[:status_type] = status_type(data, control)
|
539
|
-
dump_one_example(data, control)
|
540
|
-
|
541
|
-
@current_control ||= control
|
542
|
-
if control[:id].nil?
|
543
|
-
@missing_controls.push(data)
|
544
|
-
elsif @current_control[:id] != control[:id]
|
545
|
-
flush_current_control
|
546
|
-
@current_control = control
|
547
|
-
end
|
548
|
-
|
549
|
-
data
|
550
|
-
end
|
551
569
|
end
|
552
570
|
|
553
571
|
class InspecRspecJUnit < RSpecJUnitFormatter
|
data/lib/inspec/version.rb
CHANGED
data/lib/resources/processes.rb
CHANGED
@@ -21,9 +21,10 @@ module Inspec::Resources
|
|
21
21
|
:states
|
22
22
|
|
23
23
|
def initialize(grep)
|
24
|
+
@grep = grep
|
24
25
|
# turn into a regexp if it isn't one yet
|
25
26
|
if grep.class == String
|
26
|
-
grep = '(/[^/]*)*'+grep if grep[0] != '/'
|
27
|
+
grep = '(/[^/]*)*' + grep if grep[0] != '/'
|
27
28
|
grep = Regexp.new('^' + grep + '(\s|$)')
|
28
29
|
end
|
29
30
|
all_cmds = ps_axo
|
@@ -38,7 +39,7 @@ module Inspec::Resources
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def to_s
|
41
|
-
|
42
|
+
"Processes #{@grep.class == String ? @grep : @grep.inspect}"
|
42
43
|
end
|
43
44
|
|
44
45
|
private
|
@@ -48,7 +49,7 @@ module Inspec::Resources
|
|
48
49
|
|
49
50
|
if os.linux?
|
50
51
|
command = 'ps axo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command'
|
51
|
-
regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(
|
52
|
+
regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
52
53
|
else
|
53
54
|
command = 'ps axo pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user,command'
|
54
55
|
regex = /^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
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: 1.
|
4
|
+
version: 1.7.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-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: train
|