inspec 1.45.9 → 1.45.13

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +54 -32
  3. data/CHANGELOG.md +29 -21
  4. data/Gemfile +1 -1
  5. data/docs/resources/ini.md.erb +14 -1
  6. data/docs/shell.md +1 -1
  7. data/inspec.gemspec +2 -2
  8. data/lib/bundles/inspec-artifact/cli.rb +3 -8
  9. data/lib/bundles/inspec-compliance/configuration.rb +5 -5
  10. data/lib/bundles/inspec-compliance/http.rb +2 -5
  11. data/lib/bundles/inspec-compliance/target.rb +6 -6
  12. data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +1 -1
  13. data/lib/bundles/inspec-habitat/profile.rb +68 -74
  14. data/lib/bundles/inspec-supermarket/api.rb +7 -7
  15. data/lib/bundles/inspec-supermarket/cli.rb +1 -1
  16. data/lib/fetchers/git.rb +3 -8
  17. data/lib/fetchers/local.rb +7 -13
  18. data/lib/fetchers/url.rb +1 -1
  19. data/lib/inspec/backend.rb +0 -1
  20. data/lib/inspec/base_cli.rb +1 -1
  21. data/lib/inspec/cached_fetcher.rb +11 -12
  22. data/lib/inspec/cli.rb +0 -1
  23. data/lib/inspec/control_eval_context.rb +2 -2
  24. data/lib/inspec/dependencies/lockfile.rb +13 -15
  25. data/lib/inspec/dependencies/requirement.rb +1 -1
  26. data/lib/inspec/dependencies/resolver.rb +3 -5
  27. data/lib/inspec/dsl.rb +5 -5
  28. data/lib/inspec/dsl_shared.rb +1 -1
  29. data/lib/inspec/env_printer.rb +26 -26
  30. data/lib/inspec/metadata.rb +11 -10
  31. data/lib/inspec/objects/or_test.rb +4 -2
  32. data/lib/inspec/objects/test.rb +1 -1
  33. data/lib/inspec/profile.rb +2 -2
  34. data/lib/inspec/resource.rb +1 -3
  35. data/lib/inspec/rspec_json_formatter.rb +6 -8
  36. data/lib/inspec/shell.rb +51 -52
  37. data/lib/inspec/version.rb +1 -1
  38. data/lib/matchers/matchers.rb +1 -2
  39. data/lib/resources/audit_policy.rb +2 -2
  40. data/lib/resources/auditd.rb +6 -3
  41. data/lib/resources/dh_params.rb +1 -2
  42. data/lib/resources/docker.rb +2 -2
  43. data/lib/resources/docker_container.rb +4 -4
  44. data/lib/resources/elasticsearch.rb +2 -6
  45. data/lib/resources/etc_group.rb +2 -4
  46. data/lib/resources/groups.rb +14 -14
  47. data/lib/resources/host.rb +2 -3
  48. data/lib/resources/packages.rb +1 -1
  49. data/lib/resources/port.rb +1 -1
  50. data/lib/resources/postgres.rb +6 -6
  51. data/lib/resources/powershell.rb +1 -1
  52. data/lib/resources/service.rb +4 -5
  53. data/lib/resources/users.rb +58 -58
  54. data/lib/resources/vbscript.rb +10 -10
  55. data/lib/resources/virtualization.rb +3 -4
  56. data/lib/resources/x509_certificate.rb +1 -1
  57. data/lib/resources/yum.rb +1 -1
  58. data/lib/source_readers/inspec.rb +2 -1
  59. data/lib/utils/command_wrapper.rb +3 -8
  60. data/lib/utils/filter.rb +1 -1
  61. data/lib/utils/json_log.rb +2 -1
  62. data/lib/utils/latest_version.rb +5 -4
  63. data/lib/utils/object_traversal.rb +1 -1
  64. data/lib/utils/parser.rb +2 -2
  65. metadata +4 -4
@@ -42,7 +42,7 @@ module Inspec
42
42
  def describe_chain
43
43
  return nil if @qualifier.empty?
44
44
 
45
- resource = (@qualifier.length > 1) ? @qualifier[0..-2] : [@qualifier[0]]
45
+ resource = @qualifier.length > 1 ? @qualifier[0..-2] : [@qualifier[0]]
46
46
  res = resource.map { |q| ruby_qualifier(q) }.join('.')
47
47
  xres = nil
48
48
 
@@ -106,7 +106,7 @@ module Inspec
106
106
  # we share the backend between profiles.
107
107
  #
108
108
  # This will cause issues if a profile attempts to load a file via `inspec.profile.file`
109
- train_options = options.select { |k, _| k != 'target' } # See https://github.com/chef/inspec/pull/1646
109
+ train_options = options.reject { |k, _| k == 'target' } # See https://github.com/chef/inspec/pull/1646
110
110
  @backend = options[:backend].nil? ? Inspec::Backend.create(train_options) : options[:backend].dup
111
111
  @runtime_profile = RuntimeProfile.new(self)
112
112
  @backend.profile = @runtime_profile
@@ -421,7 +421,7 @@ module Inspec
421
421
  [['inspec.yml', source_reader.metadata.content]] +
422
422
  [['inspec.lock.deps', YAML.dump(deps)]]
423
423
 
424
- files.sort { |a, b| a[0] <=> b[0] }
424
+ files.sort_by { |a| a[0] }
425
425
  .map { |f| res << f[0] << "\0" << f[1] << "\0" }
426
426
 
427
427
  res.digest.unpack('H*')[0]
@@ -66,9 +66,7 @@ module Inspec
66
66
  end
67
67
 
68
68
  def self.validate_resource_dsl_version!(version)
69
- if version != 1
70
- raise 'Only resource version 1 is supported!'
71
- end
69
+ raise 'Only resource version 1 is supported!' if version != 1
72
70
  end
73
71
  end
74
72
 
@@ -455,10 +455,10 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
455
455
  end
456
456
 
457
457
  def print_last_control_with_examples
458
- if @last_control
459
- print_control(@last_control)
460
- @last_control.examples.each { |example| print_result(example) }
461
- end
458
+ return unless @last_control
459
+
460
+ print_control(@last_control)
461
+ @last_control.examples.each { |example| print_result(example) }
462
462
  end
463
463
 
464
464
  def last_control_is_anonymous?
@@ -634,8 +634,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
634
634
  s = format('Profile Summary: %s, %s, %s',
635
635
  format_with_color(success_color, success_str),
636
636
  format_with_color(failed_color, failed_str),
637
- format_with_color(skipped_color, skipped_str),
638
- )
637
+ format_with_color(skipped_color, skipped_str))
639
638
  output.puts(s) if summary['total'] > 0
640
639
  end
641
640
 
@@ -651,8 +650,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
651
650
  s = format('Test Summary: %s, %s, %s',
652
651
  format_with_color(success_color, "#{summary['passed']} successful"),
653
652
  format_with_color(failed_color, failed_str),
654
- format_with_color(skipped_color, "#{summary['skipped']} skipped"),
655
- )
653
+ format_with_color(skipped_color, "#{summary['skipped']} skipped"))
656
654
 
657
655
  output.puts(s)
658
656
  end
data/lib/inspec/shell.rb CHANGED
@@ -103,35 +103,34 @@ module Inspec
103
103
 
104
104
  def print_target_info
105
105
  ctx = @runner.backend
106
- puts <<EOF
107
- You are currently running on:
106
+ puts <<~EOF
107
+ You are currently running on:
108
108
 
109
- OS platform: #{mark ctx.os[:name] || 'unknown'}
110
- OS family: #{mark ctx.os[:family] || 'unknown'}
111
- OS release: #{mark ctx.os[:release] || 'unknown'}
112
- EOF
109
+ OS platform: #{mark ctx.os[:name] || 'unknown'}
110
+ OS family: #{mark ctx.os[:family] || 'unknown'}
111
+ OS release: #{mark ctx.os[:release] || 'unknown'}
112
+ EOF
113
113
  end
114
114
 
115
115
  def help(topic = nil)
116
116
  if topic.nil?
117
117
 
118
- puts <<EOF
118
+ puts <<~EOF
119
+ Available commands:
119
120
 
120
- Available commands:
121
+ `[resource]` - run resource on target machine
122
+ `help resources` - show all available resources that can be used as commands
123
+ `help [resource]` - information about a specific resource
124
+ `help matchers` - show information about common matchers
125
+ `exit` - exit the InSpec shell
121
126
 
122
- `[resource]` - run resource on target machine
123
- `help resources` - show all available resources that can be used as commands
124
- `help [resource]` - information about a specific resource
125
- `help matchers` - show information about common matchers
126
- `exit` - exit the InSpec shell
127
+ You can use resources in this environment to test the target machine. For example:
127
128
 
128
- You can use resources in this environment to test the target machine. For example:
129
+ command('uname -a').stdout
130
+ file('/proc/cpuinfo').content => "value"
129
131
 
130
- command('uname -a').stdout
131
- file('/proc/cpuinfo').content => "value"
132
-
133
- #{print_target_info}
134
- EOF
132
+ #{print_target_info}
133
+ EOF
135
134
  elsif topic == 'resources'
136
135
  resources.sort.each do |resource|
137
136
  puts " - #{resource}"
@@ -164,60 +163,60 @@ EOF
164
163
  end
165
164
 
166
165
  def print_matchers_help
167
- puts <<-EOL
168
- Matchers are used to compare resource values to expectations. While some
169
- resources implement their own custom matchers, the following matchers are
170
- common amongst all resources:
166
+ puts <<~EOL
167
+ Matchers are used to compare resource values to expectations. While some
168
+ resources implement their own custom matchers, the following matchers are
169
+ common amongst all resources:
171
170
 
172
- #{mark 'be'}
171
+ #{mark 'be'}
173
172
 
174
- The #{mark 'be'} matcher can be used to compare numeric values.
173
+ The #{mark 'be'} matcher can be used to compare numeric values.
175
174
 
176
- its('size') { should be >= 10 }
175
+ its('size') { should be >= 10 }
177
176
 
178
- #{mark 'cmp'}
177
+ #{mark 'cmp'}
179
178
 
180
- The #{mark 'cmp'} matcher is like #{mark 'eq'} but less restrictive. It will try
181
- to fit the resource value to the expectation.
179
+ The #{mark 'cmp'} matcher is like #{mark 'eq'} but less restrictive. It will try
180
+ to fit the resource value to the expectation.
182
181
 
183
- "Protocol" likely returns a string, but cmp will ensure it's a number before
184
- comparing:
182
+ "Protocol" likely returns a string, but cmp will ensure it's a number before
183
+ comparing:
185
184
 
186
- its('Protocol') { should cmp 2 }
187
- its('Protocol') { should cmp '2' }
185
+ its('Protocol') { should cmp 2 }
186
+ its('Protocol') { should cmp '2' }
188
187
 
189
- "users" may return an array, but if it contains only one item, cmp will compare
190
- it as a string or number as needed:
188
+ "users" may return an array, but if it contains only one item, cmp will compare
189
+ it as a string or number as needed:
191
190
 
192
- its('users') { should cmp 'root' }
191
+ its('users') { should cmp 'root' }
193
192
 
194
- cmp is not case-sensitive:
193
+ cmp is not case-sensitive:
195
194
 
196
- its('log_format') { should cmp 'raw' }
197
- its('log_format') { should cmp 'RAW' }
195
+ its('log_format') { should cmp 'raw' }
196
+ its('log_format') { should cmp 'RAW' }
198
197
 
199
- #{mark 'eq'}
198
+ #{mark 'eq'}
200
199
 
201
- The #{mark 'eq'} matcher tests for exact equality of two values. Value type
202
- (string, number, etc.) is important and must be the same. For a less-restrictive
203
- comparison matcher, use the #{mark 'cmp'} matcher.
200
+ The #{mark 'eq'} matcher tests for exact equality of two values. Value type
201
+ (string, number, etc.) is important and must be the same. For a less-restrictive
202
+ comparison matcher, use the #{mark 'cmp'} matcher.
204
203
 
205
- its('RSAAuthentication') { should_not eq 'no' }
204
+ its('RSAAuthentication') { should_not eq 'no' }
206
205
 
207
- #{mark 'include'}
206
+ #{mark 'include'}
208
207
 
209
- The #{mark 'include'} matcher tests to see if a value is included in a list.
208
+ The #{mark 'include'} matcher tests to see if a value is included in a list.
210
209
 
211
- its('users') { should include 'my_user' }
210
+ its('users') { should include 'my_user' }
212
211
 
213
- #{mark 'match'}
212
+ #{mark 'match'}
214
213
 
215
- The #{mark 'match'} matcher can be used to test a string for a match using a
216
- regular expression.
214
+ The #{mark 'match'} matcher can be used to test a string for a match using a
215
+ regular expression.
217
216
 
218
- its('content') { should_not match /^MyKey:\\s+some value/ }
217
+ its('content') { should_not match /^MyKey:\\s+some value/ }
219
218
 
220
- For more examples, see: https://www.inspec.io/docs/reference/matchers/
219
+ For more examples, see: https://www.inspec.io/docs/reference/matchers/
221
220
 
222
221
  EOL
223
222
  end
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '1.45.9'
7
+ VERSION = '1.45.13'
8
8
  end
@@ -266,7 +266,7 @@ end
266
266
  # - compare strings case-insensitive
267
267
  # - you expect a number (strings will be converted if possible)
268
268
  #
269
- RSpec::Matchers.define :cmp do |first_expected|
269
+ RSpec::Matchers.define :cmp do |first_expected| # rubocop:disable Metrics/BlockLength
270
270
 
271
271
  def integer?(value)
272
272
  !(value =~ /\A0+\Z|\A[1-9]\d*\Z/).nil?
@@ -324,7 +324,6 @@ RSpec::Matchers.define :cmp do |first_expected|
324
324
 
325
325
  # fallback to simple operation
326
326
  actual.method(op).call(expected)
327
-
328
327
  rescue NameError => _
329
328
  false
330
329
  rescue ArgumentError
@@ -43,9 +43,9 @@ module Inspec::Resources
43
43
 
44
44
  # find line
45
45
  target = nil
46
- result.each_line {|s|
46
+ result.each_line do |s|
47
47
  target = s.strip if s =~ /\b.*#{key}.*\b/
48
- }
48
+ end
49
49
 
50
50
  # extract value
51
51
  values = nil
@@ -101,7 +101,8 @@ module Inspec::Resources
101
101
  'permissions' => perms,
102
102
  'key' => key,
103
103
  'fields_nokey' => fields_nokey,
104
- },)
104
+ },
105
+ )
105
106
  end
106
107
 
107
108
  def syscall_rules_for(line)
@@ -128,7 +129,8 @@ module Inspec::Resources
128
129
  'permissions' => perms,
129
130
  'exit' => exit_field,
130
131
  'fields_nokey' => fields_nokey,
131
- },)
132
+ },
133
+ )
132
134
  end
133
135
  end
134
136
 
@@ -142,7 +144,8 @@ module Inspec::Resources
142
144
  'file' => file,
143
145
  'key' => key,
144
146
  'permissions' => perms,
145
- },)
147
+ },
148
+ )
146
149
  end
147
150
 
148
151
  def to_s
@@ -26,8 +26,7 @@ class DhParams < Inspec.resource(1)
26
26
  def initialize(filename)
27
27
  @dh_params_path = filename
28
28
  file = inspec.file(@dh_params_path)
29
- return skip_resource 'Unable to find DH parameters file ' \
30
- "#{@dh_params_path}" unless file.exist?
29
+ return skip_resource "Unable to find DH parameters file #{@dh_params_path}" unless file.exist?
31
30
 
32
31
  begin
33
32
  @dh_params = OpenSSL::PKey::DH.new file.content
@@ -146,7 +146,7 @@ module Inspec::Resources
146
146
  # @see https://github.com/moby/moby/issues/20625, works for docker 1.13+
147
147
  # raw_containers = inspec.command('docker ps -a --no-trunc --format \'{{ json . }}\'').stdout
148
148
  # therefore we stick with older approach
149
- labels = %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status}
149
+ labels = %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status}
150
150
 
151
151
  # Networks LocalVolumes work with 1.13+ only
152
152
  if !version.empty? && Gem::Version.new(version['Client']['Version']) >= Gem::Version.new('1.13')
@@ -183,7 +183,7 @@ module Inspec::Resources
183
183
  end
184
184
 
185
185
  def ensure_container_keys(entry)
186
- %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status Networks LocalVolumes}.each { |key|
186
+ %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status Networks LocalVolumes}.each { |key|
187
187
  entry[key.downcase] = nil if !entry.key?(key.downcase)
188
188
  }
189
189
  entry
@@ -63,10 +63,10 @@ module Inspec::Resources
63
63
  end
64
64
 
65
65
  def command
66
- if container_info.entries.length == 1
67
- cmd = container_info.commands[0]
68
- cmd.slice(1, cmd.length - 2)
69
- end
66
+ return unless container_info.entries.length == 1
67
+
68
+ cmd = container_info.commands[0]
69
+ cmd.slice(1, cmd.length - 2)
70
70
  end
71
71
 
72
72
  def image
@@ -154,9 +154,7 @@ module Inspec::Resources
154
154
  raise 'Connection refused - peer certificate issuer is not recognized'
155
155
  end
156
156
 
157
- if !cmd.exit_status.zero?
158
- raise "Error fetching Elastcsearch data from curl #{url}: #{cmd.stderr}"
159
- end
157
+ raise "Error fetching Elastcsearch data from curl #{url}: #{cmd.stderr}" unless cmd.exit_status.zero?
160
158
  end
161
159
 
162
160
  def verify_json_payload!(content)
@@ -164,9 +162,7 @@ module Inspec::Resources
164
162
  raise "#{content['error']['type']}: #{content['error']['reason']}"
165
163
  end
166
164
 
167
- if content['_nodes']['successful'].zero?
168
- raise 'No successful nodes available in cluster'
169
- end
165
+ raise 'No successful nodes available in cluster' if content['_nodes']['successful'].zero?
170
166
  end
171
167
  end
172
168
  end
@@ -49,13 +49,11 @@ module Inspec::Resources
49
49
  end
50
50
 
51
51
  def groups(filter = nil)
52
- entries = filter || @entries
53
- entries.map { |x| x['name'] } if !entries.nil?
52
+ (filter || @entries)&.map { |x| x['name'] }
54
53
  end
55
54
 
56
55
  def gids(filter = nil)
57
- entries = filter || @entries
58
- entries.map { |x| x['gid'] } if !entries.nil?
56
+ (filter || @entries)&.map { |x| x['gid'] }
59
57
  end
60
58
 
61
59
  def users(filter = nil)
@@ -157,20 +157,20 @@ module Inspec::Resources
157
157
  class WindowsGroup < GroupInfo
158
158
  # returns all local groups
159
159
  def groups
160
- script = <<-EOH
161
- Function ConvertTo-SID { Param([byte[]]$BinarySID)
162
- (New-Object System.Security.Principal.SecurityIdentifier($BinarySID,0)).Value
163
- }
164
-
165
- $Computername = $Env:Computername
166
- $adsi = [ADSI]"WinNT://$Computername"
167
- $groups = $adsi.Children | where {$_.SchemaClassName -eq 'group'} | ForEach {
168
- $name = $_.Name[0]
169
- $sid = ConvertTo-SID -BinarySID $_.ObjectSID[0]
170
- $group =[ADSI]$_.Path
171
- new-object psobject -property @{name = $group.Name[0]; gid = $sid; domain=$Computername}
172
- }
173
- $groups | ConvertTo-Json -Depth 3
160
+ script = <<~EOH
161
+ Function ConvertTo-SID { Param([byte[]]$BinarySID)
162
+ (New-Object System.Security.Principal.SecurityIdentifier($BinarySID,0)).Value
163
+ }
164
+
165
+ $Computername = $Env:Computername
166
+ $adsi = [ADSI]"WinNT://$Computername"
167
+ $groups = $adsi.Children | where {$_.SchemaClassName -eq 'group'} | ForEach {
168
+ $name = $_.Name[0]
169
+ $sid = ConvertTo-SID -BinarySID $_.ObjectSID[0]
170
+ $group =[ADSI]$_.Path
171
+ new-object psobject -property @{name = $group.Name[0]; gid = $sid; domain=$Computername}
172
+ }
173
+ $groups | ConvertTo-Json -Depth 3
174
174
  EOH
175
175
  cmd = inspec.powershell(script)
176
176
  # cannot rely on exit code for now, successful command returns exit code 1
@@ -70,9 +70,8 @@ module Inspec::Resources
70
70
  end
71
71
 
72
72
  missing_requirements = @host_provider.missing_requirements(protocol)
73
- unless missing_requirements.empty?
74
- return skip_resource "The following requirements are not met for this resource: #{missing_requirements.join(', ')}"
75
- end
73
+ return skip_resource 'The following requirements are not met for this resource: ' \
74
+ "#{missing_requirements.join(', ')}" unless missing_requirements.empty?
76
75
  end
77
76
 
78
77
  def proto
@@ -97,7 +97,7 @@ module Inspec::Resources
97
97
  class Rpms < PkgsManagement
98
98
  def build_package_list
99
99
  # use two spaces as delimiter in case any of the fields has a space in it
100
- command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'"
100
+ command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'" # rubocop:disable Style/FormatStringToken
101
101
  cmd = inspec.command(command)
102
102
  all = cmd.stdout.split("\n")
103
103
  return [] if all.nil?
@@ -242,7 +242,7 @@ module Inspec::Resources
242
242
  procs[proc_id] = [] unless procs.key?(proc_id)
243
243
 
244
244
  # change address '*' to zero
245
- host = (port_id =~ /^ipv6:/) ? '[::]' : '0.0.0.0' if host == '*'
245
+ host = port_id =~ /^ipv6:/ ? '[::]' : '0.0.0.0' if host == '*'
246
246
  # entrust URI to scrub the host and port
247
247
  begin
248
248
  uri = URI("addr://#{host}:#{port}")