inspec 0.14.8 → 0.15.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -2
  3. data/bin/inspec +3 -4
  4. data/examples/inheritance/README.md +19 -0
  5. data/examples/inheritance/controls/example.rb +11 -0
  6. data/examples/inheritance/inspec.yml +10 -0
  7. data/lib/bundles/inspec-compliance/cli.rb +1 -4
  8. data/lib/bundles/inspec-supermarket/cli.rb +1 -4
  9. data/lib/inspec/dsl.rb +48 -55
  10. data/lib/inspec/profile.rb +6 -2
  11. data/lib/inspec/profile_context.rb +21 -8
  12. data/lib/inspec/runner.rb +17 -12
  13. data/lib/inspec/runner_rspec.rb +1 -0
  14. data/lib/inspec/version.rb +1 -1
  15. data/lib/resources/apache.rb +20 -18
  16. data/lib/resources/apache_conf.rb +92 -90
  17. data/lib/resources/apt.rb +92 -90
  18. data/lib/resources/audit_policy.rb +35 -33
  19. data/lib/resources/auditd_conf.rb +41 -39
  20. data/lib/resources/auditd_rules.rb +155 -153
  21. data/lib/resources/bond.rb +1 -1
  22. data/lib/resources/bridge.rb +97 -95
  23. data/lib/resources/command.rb +47 -45
  24. data/lib/resources/csv.rb +23 -21
  25. data/lib/resources/directory.rb +1 -1
  26. data/lib/resources/etc_group.rb +116 -114
  27. data/lib/resources/file.rb +1 -1
  28. data/lib/resources/gem.rb +39 -37
  29. data/lib/resources/group.rb +100 -98
  30. data/lib/resources/host.rb +103 -101
  31. data/lib/resources/inetd_conf.rb +42 -40
  32. data/lib/resources/ini.rb +15 -13
  33. data/lib/resources/interface.rb +106 -104
  34. data/lib/resources/iptables.rb +36 -34
  35. data/lib/resources/json.rb +64 -62
  36. data/lib/resources/kernel_module.rb +30 -28
  37. data/lib/resources/kernel_parameter.rb +44 -42
  38. data/lib/resources/limits_conf.rb +41 -39
  39. data/lib/resources/login_def.rb +38 -36
  40. data/lib/resources/mount.rb +43 -41
  41. data/lib/resources/mysql.rb +67 -65
  42. data/lib/resources/mysql_conf.rb +89 -87
  43. data/lib/resources/mysql_session.rb +46 -44
  44. data/lib/resources/npm.rb +35 -33
  45. data/lib/resources/ntp_conf.rb +44 -42
  46. data/lib/resources/oneget.rb +46 -44
  47. data/lib/resources/os.rb +22 -20
  48. data/lib/resources/os_env.rb +47 -45
  49. data/lib/resources/package.rb +213 -211
  50. data/lib/resources/parse_config.rb +59 -57
  51. data/lib/resources/passwd.rb +89 -87
  52. data/lib/resources/pip.rb +60 -58
  53. data/lib/resources/port.rb +352 -350
  54. data/lib/resources/postgres.rb +26 -24
  55. data/lib/resources/postgres_conf.rb +66 -64
  56. data/lib/resources/postgres_session.rb +47 -45
  57. data/lib/resources/processes.rb +56 -54
  58. data/lib/resources/registry_key.rb +150 -148
  59. data/lib/resources/script.rb +30 -28
  60. data/lib/resources/security_policy.rb +56 -54
  61. data/lib/resources/service.rb +638 -636
  62. data/lib/resources/shadow.rb +98 -96
  63. data/lib/resources/ssh_conf.rb +58 -56
  64. data/lib/resources/user.rb +363 -361
  65. data/lib/resources/windows_feature.rb +46 -44
  66. data/lib/resources/xinetd.rb +111 -109
  67. data/lib/resources/yaml.rb +16 -14
  68. data/lib/resources/yum.rb +107 -105
  69. data/lib/utils/base_cli.rb +18 -0
  70. data/test/helper.rb +2 -2
  71. data/test/unit/profile_context_test.rb +1 -1
  72. data/test/unit/resources/file_test.rb +1 -1
  73. data/test/unit/resources/mount_test.rb +1 -1
  74. metadata +5 -2
@@ -5,7 +5,7 @@
5
5
  # license: All rights reserved
6
6
 
7
7
  module Inspec::Resources
8
- class File < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
8
+ class FileResource < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
9
9
  name 'file'
10
10
  desc 'Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, named pipes, sockets, character devices, block devices, and doors.'
11
11
  example "
data/lib/resources/gem.rb CHANGED
@@ -2,47 +2,49 @@
2
2
  # author: Christoph Hartmann
3
3
  # author: Dominik Richter
4
4
 
5
- class GemPackage < Inspec.resource(1)
6
- name 'gem'
7
- desc 'Use the gem InSpec audit resource to test if a global gem package is installed.'
8
- example "
9
- describe gem('rubocop') do
10
- it { should be_installed }
5
+ module Inspec::Resources
6
+ class GemPackage < Inspec.resource(1)
7
+ name 'gem'
8
+ desc 'Use the gem InSpec audit resource to test if a global gem package is installed.'
9
+ example "
10
+ describe gem('rubocop') do
11
+ it { should be_installed }
12
+ end
13
+ "
14
+
15
+ def initialize(package_name)
16
+ @package_name = package_name
11
17
  end
12
- "
13
18
 
14
- def initialize(package_name)
15
- @package_name = package_name
16
- end
17
-
18
- def info
19
- return @info if defined?(@info)
20
-
21
- cmd = inspec.command("gem list --local -a -q \^#{@package_name}\$")
22
- @info = {
23
- installed: cmd.exit_status == 0,
24
- type: 'gem',
25
- }
26
- return @info unless @info[:installed]
27
-
28
- # extract package name and version
29
- # parses data like winrm (1.3.4, 1.3.3)
30
- params = /^\s*([^\(]*?)\s*\((.*?)\)\s*$/.match(cmd.stdout.chomp)
31
- versions = params[2].split(',')
32
- @info[:name] = params[1]
33
- @info[:version] = versions[0]
34
- @info
35
- end
19
+ def info
20
+ return @info if defined?(@info)
21
+
22
+ cmd = inspec.command("gem list --local -a -q \^#{@package_name}\$")
23
+ @info = {
24
+ installed: cmd.exit_status == 0,
25
+ type: 'gem',
26
+ }
27
+ return @info unless @info[:installed]
28
+
29
+ # extract package name and version
30
+ # parses data like winrm (1.3.4, 1.3.3)
31
+ params = /^\s*([^\(]*?)\s*\((.*?)\)\s*$/.match(cmd.stdout.chomp)
32
+ versions = params[2].split(',')
33
+ @info[:name] = params[1]
34
+ @info[:version] = versions[0]
35
+ @info
36
+ end
36
37
 
37
- def installed?
38
- info[:installed] == true
39
- end
38
+ def installed?
39
+ info[:installed] == true
40
+ end
40
41
 
41
- def version
42
- info[:version]
43
- end
42
+ def version
43
+ info[:version]
44
+ end
44
45
 
45
- def to_s
46
- "gem package #{@package_name}"
46
+ def to_s
47
+ "gem package #{@package_name}"
48
+ end
47
49
  end
48
50
  end
@@ -13,123 +13,125 @@
13
13
  # it { should have_gid 0 }
14
14
  # end
15
15
 
16
- class Group < Inspec.resource(1)
17
- name 'group'
18
- desc 'Use the group InSpec audit resource to test groups on the system.'
19
- example "
20
- describe group('root') do
21
- it { should exist }
22
- its('gid') { should eq 0 }
16
+ module Inspec::Resources
17
+ class Group < Inspec.resource(1)
18
+ name 'group'
19
+ desc 'Use the group InSpec audit resource to test groups on the system.'
20
+ example "
21
+ describe group('root') do
22
+ it { should exist }
23
+ its('gid') { should eq 0 }
24
+ end
25
+ "
26
+
27
+ def initialize(groupname, domain = nil)
28
+ @group = groupname.downcase
29
+ @domain = domain
30
+ @domain = @domain.downcase unless @domain.nil?
31
+
32
+ @cache = nil
33
+
34
+ # select group manager
35
+ @group_provider = nil
36
+ if inspec.os.unix?
37
+ @group_provider = UnixGroup.new(inspec)
38
+ elsif inspec.os.windows?
39
+ @group_provider = WindowsGroup.new(inspec)
40
+ else
41
+ return skip_resource 'The `group` resource is not supported on your OS yet.'
42
+ end
23
43
  end
24
- "
25
-
26
- def initialize(groupname, domain = nil)
27
- @group = groupname.downcase
28
- @domain = domain
29
- @domain = @domain.downcase unless @domain.nil?
30
-
31
- @cache = nil
32
-
33
- # select group manager
34
- @group_provider = nil
35
- if inspec.os.unix?
36
- @group_provider = UnixGroup.new(inspec)
37
- elsif inspec.os.windows?
38
- @group_provider = WindowsGroup.new(inspec)
39
- else
40
- return skip_resource 'The `group` resource is not supported on your OS yet.'
41
- end
42
- end
43
44
 
44
- # verifies if a group exists
45
- def exists?
46
- # ensure that we found one group
47
- !group_info.nil? && group_info.size > 0
48
- end
45
+ # verifies if a group exists
46
+ def exists?
47
+ # ensure that we found one group
48
+ !group_info.nil? && group_info.size > 0
49
+ end
49
50
 
50
- def gid
51
- return nil if group_info.nil? || group_info.size == 0
51
+ def gid
52
+ return nil if group_info.nil? || group_info.size == 0
52
53
 
53
- # the default case should be one group
54
- return group_info[0][:gid] if group_info.size == 1
54
+ # the default case should be one group
55
+ return group_info[0][:gid] if group_info.size == 1
55
56
 
56
- # return array if we got multiple gids
57
- group_info.map { |grp| grp[:gid] }
58
- end
57
+ # return array if we got multiple gids
58
+ group_info.map { |grp| grp[:gid] }
59
+ end
59
60
 
60
- # implements rspec has matcher, to be compatible with serverspec
61
- def has_gid?(compare_gid)
62
- gid == compare_gid
63
- end
61
+ # implements rspec has matcher, to be compatible with serverspec
62
+ def has_gid?(compare_gid)
63
+ gid == compare_gid
64
+ end
64
65
 
65
- def local
66
- return nil if group_info.nil? || group_info.size == 0
66
+ def local
67
+ return nil if group_info.nil? || group_info.size == 0
67
68
 
68
- # the default case should be one group
69
- return group_info[0][:local] if group_info.size == 1
69
+ # the default case should be one group
70
+ return group_info[0][:local] if group_info.size == 1
70
71
 
71
- # return array if we got multiple gids
72
- group_info.map { |grp| grp[:local] }
73
- end
72
+ # return array if we got multiple gids
73
+ group_info.map { |grp| grp[:local] }
74
+ end
74
75
 
75
- def to_s
76
- "Group #{@group}"
77
- end
76
+ def to_s
77
+ "Group #{@group}"
78
+ end
78
79
 
79
- private
80
+ private
80
81
 
81
- def group_info
82
- return @cache if !@cache.nil?
83
- @cache = @group_provider.group_info(@group, @domain) if !@group_provider.nil?
82
+ def group_info
83
+ return @cache if !@cache.nil?
84
+ @cache = @group_provider.group_info(@group, @domain) if !@group_provider.nil?
85
+ end
84
86
  end
85
- end
86
87
 
87
- class GroupInfo
88
- attr_reader :inspec
89
- def initialize(inspec)
90
- @inspec = inspec
88
+ class GroupInfo
89
+ attr_reader :inspec
90
+ def initialize(inspec)
91
+ @inspec = inspec
92
+ end
91
93
  end
92
- end
93
94
 
94
- # implements generic unix groups via /etc/group
95
- class UnixGroup < GroupInfo
96
- def group_info(group, _domain = nil)
97
- inspec.etc_group.where(name: group).entries.map { |grp|
98
- {
99
- name: grp['name'],
100
- gid: grp['gid'],
95
+ # implements generic unix groups via /etc/group
96
+ class UnixGroup < GroupInfo
97
+ def group_info(group, _domain = nil)
98
+ inspec.etc_group.where(name: group).entries.map { |grp|
99
+ {
100
+ name: grp['name'],
101
+ gid: grp['gid'],
102
+ }
101
103
  }
102
- }
103
- end
104
- end
105
-
106
- class WindowsGroup < GroupInfo
107
- def group_info(compare_group, compare_domain = nil)
108
- cmd = inspec.command('Get-WmiObject Win32_Group | Select-Object -Property Caption, Domain, Name, SID, LocalAccount | ConvertTo-Json')
109
-
110
- # cannot rely on exit code for now, successful command returns exit code 1
111
- # return nil if cmd.exit_status != 0, try to parse json
112
- begin
113
- groups = JSON.parse(cmd.stdout)
114
- rescue JSON::ParserError => _e
115
- return nil
116
104
  end
105
+ end
117
106
 
118
- # ensure we have an array of groups
119
- groups = [groups] if !groups.is_a?(Array)
120
-
121
- # reduce list
122
- groups.each_with_object([]) do |grp, grp_collection|
123
- # map object
124
- grp_info = {
125
- name: grp['Name'],
126
- domain: grp['Domain'],
127
- caption: grp['Caption'],
128
- gid: nil,
129
- sid: grp['SID'],
130
- local: grp['LocalAccount'],
131
- }
132
- return grp_collection.push(grp_info) if grp_info[:name].casecmp(compare_group) == 0 && (compare_domain.nil? || grp_info[:domain].casecmp(compare_domain) == 0)
107
+ class WindowsGroup < GroupInfo
108
+ def group_info(compare_group, compare_domain = nil)
109
+ cmd = inspec.command('Get-WmiObject Win32_Group | Select-Object -Property Caption, Domain, Name, SID, LocalAccount | ConvertTo-Json')
110
+
111
+ # cannot rely on exit code for now, successful command returns exit code 1
112
+ # return nil if cmd.exit_status != 0, try to parse json
113
+ begin
114
+ groups = JSON.parse(cmd.stdout)
115
+ rescue JSON::ParserError => _e
116
+ return nil
117
+ end
118
+
119
+ # ensure we have an array of groups
120
+ groups = [groups] if !groups.is_a?(Array)
121
+
122
+ # reduce list
123
+ groups.each_with_object([]) do |grp, grp_collection|
124
+ # map object
125
+ grp_info = {
126
+ name: grp['Name'],
127
+ domain: grp['Domain'],
128
+ caption: grp['Caption'],
129
+ gid: nil,
130
+ sid: grp['SID'],
131
+ local: grp['LocalAccount'],
132
+ }
133
+ return grp_collection.push(grp_info) if grp_info[:name].casecmp(compare_group) == 0 && (compare_domain.nil? || grp_info[:domain].casecmp(compare_domain) == 0)
134
+ end
133
135
  end
134
136
  end
135
137
  end
@@ -24,126 +24,128 @@
24
24
  # it { should be_resolvable.by('dns') }
25
25
  # end
26
26
 
27
- class Host < Inspec.resource(1)
28
- name 'host'
29
- desc 'Use the host InSpec audit resource to test the name used to refer to a specific host and its availability, including the Internet protocols and ports over which that host name should be available.'
30
- example "
31
- describe host('example.com') do
32
- it { should be_reachable }
27
+ module Inspec::Resources
28
+ class Host < Inspec.resource(1)
29
+ name 'host'
30
+ desc 'Use the host InSpec audit resource to test the name used to refer to a specific host and its availability, including the Internet protocols and ports over which that host name should be available.'
31
+ example "
32
+ describe host('example.com') do
33
+ it { should be_reachable }
34
+ end
35
+ "
36
+
37
+ def initialize(hostname, params = {})
38
+ @hostname = hostname
39
+ @port = params[:port] || nil
40
+ @proto = params[:proto] || nil
41
+
42
+ @host_provider = nil
43
+ if inspec.os.linux?
44
+ @host_provider = LinuxHostProvider.new(inspec)
45
+ elsif inspec.os.windows?
46
+ @host_provider = WindowsHostProvider.new(inspec)
47
+ else
48
+ return skip_resource 'The `host` resource is not supported on your OS yet.'
49
+ end
33
50
  end
34
- "
35
-
36
- def initialize(hostname, params = {})
37
- @hostname = hostname
38
- @port = params[:port] || nil
39
- @proto = params[:proto] || nil
40
-
41
- @host_provider = nil
42
- if inspec.os.linux?
43
- @host_provider = LinuxHostProvider.new(inspec)
44
- elsif inspec.os.windows?
45
- @host_provider = WindowsHostProvider.new(inspec)
46
- else
47
- return skip_resource 'The `host` resource is not supported on your OS yet.'
48
- end
49
- end
50
51
 
51
- # if we get the IP adress, the host is resolvable
52
- def resolvable?(type = nil)
53
- warn "The `host` resource ignores #{type} parameters. Continue to resolve host." if !type.nil?
54
- resolve.nil? || resolve.empty? ? false : true
55
- end
52
+ # if we get the IP adress, the host is resolvable
53
+ def resolvable?(type = nil)
54
+ warn "The `host` resource ignores #{type} parameters. Continue to resolve host." if !type.nil?
55
+ resolve.nil? || resolve.empty? ? false : true
56
+ end
56
57
 
57
- def reachable?(port = nil, proto = nil, timeout = nil)
58
- fail "Use `host` resource with host('#{@hostname}', port: #{port}, proto: '#{proto}') parameters." if !port.nil? || !proto.nil? || !timeout.nil?
59
- ping.nil? ? false : ping
60
- end
58
+ def reachable?(port = nil, proto = nil, timeout = nil)
59
+ fail "Use `host` resource with host('#{@hostname}', port: #{port}, proto: '#{proto}') parameters." if !port.nil? || !proto.nil? || !timeout.nil?
60
+ ping.nil? ? false : ping
61
+ end
61
62
 
62
- # returns all A records of the IP adress, will return an array
63
- def ipaddress
64
- resolve.nil? || resolve.empty? ? nil : resolve
65
- end
63
+ # returns all A records of the IP adress, will return an array
64
+ def ipaddress
65
+ resolve.nil? || resolve.empty? ? nil : resolve
66
+ end
66
67
 
67
- def to_s
68
- "Host #{@hostname}"
69
- end
68
+ def to_s
69
+ "Host #{@hostname}"
70
+ end
70
71
 
71
- private
72
+ private
72
73
 
73
- def ping
74
- return @ping_cache if defined?(@ping_cache)
75
- @ping_cache = @host_provider.ping(@hostname, @port, @proto) if !@host_provider.nil?
76
- end
74
+ def ping
75
+ return @ping_cache if defined?(@ping_cache)
76
+ @ping_cache = @host_provider.ping(@hostname, @port, @proto) if !@host_provider.nil?
77
+ end
77
78
 
78
- def resolve
79
- return @ip_cache if defined?(@ip_cache)
80
- @ip_cache = @host_provider.resolve(@hostname) if !@host_provider.nil?
79
+ def resolve
80
+ return @ip_cache if defined?(@ip_cache)
81
+ @ip_cache = @host_provider.resolve(@hostname) if !@host_provider.nil?
82
+ end
81
83
  end
82
- end
83
84
 
84
- class HostProvider
85
- attr_reader :inspec
86
- def initialize(inspec)
87
- @inspec = inspec
85
+ class HostProvider
86
+ attr_reader :inspec
87
+ def initialize(inspec)
88
+ @inspec = inspec
89
+ end
88
90
  end
89
- end
90
91
 
91
- class LinuxHostProvider < HostProvider
92
- # ping is difficult to achieve, since we are not sure
93
- def ping(hostname, _port = nil, _proto = nil)
94
- # fall back to ping, but we can only test ICMP packages with ping
95
- # therefore we have to skip the test, if we do not have everything on the node to run the test
96
- ping = inspec.command("ping -w 1 -c 1 #{hostname}")
97
- ping.exit_status.to_i != 0 ? false : true
98
- end
92
+ class LinuxHostProvider < HostProvider
93
+ # ping is difficult to achieve, since we are not sure
94
+ def ping(hostname, _port = nil, _proto = nil)
95
+ # fall back to ping, but we can only test ICMP packages with ping
96
+ # therefore we have to skip the test, if we do not have everything on the node to run the test
97
+ ping = inspec.command("ping -w 1 -c 1 #{hostname}")
98
+ ping.exit_status.to_i != 0 ? false : true
99
+ end
99
100
 
100
- def resolve(hostname)
101
- # TODO: we rely on getent hosts for now, but it prefers to return IPv6, only then IPv4
102
- cmd = inspec.command("getent hosts #{hostname}")
103
- return nil if cmd.exit_status.to_i != 0
101
+ def resolve(hostname)
102
+ # TODO: we rely on getent hosts for now, but it prefers to return IPv6, only then IPv4
103
+ cmd = inspec.command("getent hosts #{hostname}")
104
+ return nil if cmd.exit_status.to_i != 0
104
105
 
105
- # extract ip adress
106
- resolve = /^\s*(?<ip>\S+)\s+(.*)\s*$/.match(cmd.stdout.chomp)
107
- [resolve[1]] if resolve
106
+ # extract ip adress
107
+ resolve = /^\s*(?<ip>\S+)\s+(.*)\s*$/.match(cmd.stdout.chomp)
108
+ [resolve[1]] if resolve
109
+ end
108
110
  end
109
- end
110
111
 
111
- # Windows
112
- # TODO: UDP is not supported yey, we need a custom ps1 script to add udp support
113
- # @see http://blogs.technet.com/b/josebda/archive/2015/04/18/windows-powershell-equivalents-for-common-networking-commands-ipconfig-ping-nslookup.aspx
114
- # @see http://blogs.technet.com/b/heyscriptingguy/archive/2014/03/19/creating-a-port-scanner-with-windows-powershell.aspx
115
- class WindowsHostProvider < HostProvider
116
- def ping(hostname, port = nil, proto = nil)
117
- # TODO: abort if we cannot run it via udp
118
- return nil if proto == 'udp'
119
-
120
- # ICMP: Test-NetConnection www.microsoft.com
121
- # TCP and port: Test-NetConnection -ComputerName www.microsoft.com -RemotePort 80
122
- request = "Test-NetConnection -ComputerName #{hostname}"
123
- request += " -RemotePort #{port}" unless port.nil?
124
- request += '| Select-Object -Property ComputerName, RemoteAddress, RemotePort, SourceAddress, PingSucceeded | ConvertTo-Json'
125
- p request
126
- request += '| Select-Object -Property ComputerName, PingSucceeded | ConvertTo-Json'
127
- cmd = inspec.command(request)
128
-
129
- begin
130
- ping = JSON.parse(cmd.stdout)
131
- rescue JSON::ParserError => _e
132
- return nil
112
+ # Windows
113
+ # TODO: UDP is not supported yey, we need a custom ps1 script to add udp support
114
+ # @see http://blogs.technet.com/b/josebda/archive/2015/04/18/windows-powershell-equivalents-for-common-networking-commands-ipconfig-ping-nslookup.aspx
115
+ # @see http://blogs.technet.com/b/heyscriptingguy/archive/2014/03/19/creating-a-port-scanner-with-windows-powershell.aspx
116
+ class WindowsHostProvider < HostProvider
117
+ def ping(hostname, port = nil, proto = nil)
118
+ # TODO: abort if we cannot run it via udp
119
+ return nil if proto == 'udp'
120
+
121
+ # ICMP: Test-NetConnection www.microsoft.com
122
+ # TCP and port: Test-NetConnection -ComputerName www.microsoft.com -RemotePort 80
123
+ request = "Test-NetConnection -ComputerName #{hostname}"
124
+ request += " -RemotePort #{port}" unless port.nil?
125
+ request += '| Select-Object -Property ComputerName, RemoteAddress, RemotePort, SourceAddress, PingSucceeded | ConvertTo-Json'
126
+ p request
127
+ request += '| Select-Object -Property ComputerName, PingSucceeded | ConvertTo-Json'
128
+ cmd = inspec.command(request)
129
+
130
+ begin
131
+ ping = JSON.parse(cmd.stdout)
132
+ rescue JSON::ParserError => _e
133
+ return nil
134
+ end
135
+
136
+ ping['PingSucceeded']
133
137
  end
134
138
 
135
- ping['PingSucceeded']
136
- end
139
+ def resolve(hostname)
140
+ cmd = inspec.command("Resolve-DnsName –Type A #{hostname} | ConvertTo-Json")
141
+ begin
142
+ resolv = JSON.parse(cmd.stdout)
143
+ rescue JSON::ParserError => _e
144
+ return nil
145
+ end
137
146
 
138
- def resolve(hostname)
139
- cmd = inspec.command("Resolve-DnsName –Type A #{hostname} | ConvertTo-Json")
140
- begin
141
- resolv = JSON.parse(cmd.stdout)
142
- rescue JSON::ParserError => _e
143
- return nil
147
+ resolv = [resolv] unless resolv.is_a?(Array)
148
+ resolv.map { |entry| entry['IPAddress'] }
144
149
  end
145
-
146
- resolv = [resolv] unless resolv.is_a?(Array)
147
- resolv.map { |entry| entry['IPAddress'] }
148
150
  end
149
151
  end