inspec 1.40.0 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -9
- data/docs/matchers.md +18 -0
- data/docs/plugin_kitchen_inspec.md +18 -24
- data/docs/profiles.md +39 -2
- data/docs/resources/aide_conf.md.erb +18 -28
- data/docs/resources/apache_conf.md.erb +19 -33
- data/docs/resources/apt.md.erb +22 -36
- data/docs/resources/audit_policy.md.erb +9 -24
- data/docs/resources/auditd.md.erb +9 -24
- data/docs/resources/auditd_conf.md.erb +20 -34
- data/docs/resources/auditd_rules.md.erb +8 -24
- data/docs/resources/bash.md.erb +4 -26
- data/docs/resources/bond.md.erb +25 -40
- data/docs/resources/bridge.md.erb +5 -25
- data/docs/resources/bsd_service.md.erb +5 -25
- data/docs/resources/command.md.erb +35 -50
- data/docs/resources/crontab.md.erb +9 -23
- data/docs/resources/csv.md.erb +12 -27
- data/docs/resources/dh_params.md +1 -0
- data/docs/resources/directory.md.erb +5 -25
- data/docs/resources/docker.md.erb +60 -57
- data/docs/resources/docker_container.md.erb +23 -19
- data/docs/resources/docker_image.md.erb +20 -16
- data/docs/resources/etc_fstab.md.erb +5 -2
- data/docs/resources/etc_group.md.erb +29 -45
- data/docs/resources/etc_hosts.md.erb +6 -0
- data/docs/resources/etc_hosts_allow.md.erb +6 -2
- data/docs/resources/etc_hosts_deny.md.erb +6 -2
- data/docs/resources/file.md.erb +198 -212
- data/docs/resources/firewalld.md.erb +7 -1
- data/docs/resources/gem.md.erb +21 -35
- data/docs/resources/group.md.erb +16 -30
- data/docs/resources/grub_conf.md.erb +9 -24
- data/docs/resources/host.md.erb +32 -49
- data/docs/resources/http.md.erb +38 -44
- data/docs/resources/iis_app.md.erb +25 -35
- data/docs/resources/iis_site.md.erb +26 -40
- data/docs/resources/inetd_conf.md.erb +27 -42
- data/docs/resources/ini.md.erb +9 -23
- data/docs/resources/interface.md.erb +5 -25
- data/docs/resources/iptables.md.erb +15 -29
- data/docs/resources/json.md.erb +12 -27
- data/docs/resources/kernel_module.md.erb +47 -61
- data/docs/resources/kernel_parameter.md.erb +15 -29
- data/docs/resources/key_rsa.md.erb +3 -0
- data/docs/resources/launchd_service.md.erb +5 -25
- data/docs/resources/limits_conf.md.erb +15 -29
- data/docs/resources/login_def.md.erb +15 -30
- data/docs/resources/mount.md.erb +18 -33
- data/docs/resources/mssql_session.md.erb +9 -12
- data/docs/resources/mysql_conf.md.erb +17 -32
- data/docs/resources/mysql_session.md.erb +15 -29
- data/docs/resources/nginx.md.erb +6 -0
- data/docs/resources/nginx_conf.md.erb +25 -20
- data/docs/resources/npm.md.erb +19 -35
- data/docs/resources/ntp_conf.md.erb +20 -37
- data/docs/resources/oneget.md.erb +15 -30
- data/docs/resources/oracledb_session.md.erb +9 -11
- data/docs/resources/os.md.erb +29 -43
- data/docs/resources/os_env.md.erb +29 -44
- data/docs/resources/package.md.erb +33 -42
- data/docs/resources/parse_config.md.erb +5 -25
- data/docs/resources/parse_config_file.md.erb +31 -43
- data/docs/resources/passwd.md.erb +24 -39
- data/docs/resources/pip.md.erb +20 -35
- data/docs/resources/port.md.erb +43 -57
- data/docs/resources/postgres_conf.md.erb +17 -31
- data/docs/resources/postgres_hba_conf.md.erb +26 -38
- data/docs/resources/postgres_ident_conf.md.erb +25 -37
- data/docs/resources/postgres_session.md.erb +15 -29
- data/docs/resources/powershell.md.erb +27 -42
- data/docs/resources/processes.md.erb +17 -33
- data/docs/resources/rabbitmq_config.md.erb +9 -24
- data/docs/resources/registry_key.md.erb +27 -42
- data/docs/resources/runit_service.md.erb +5 -25
- data/docs/resources/security_policy.md.erb +12 -27
- data/docs/resources/service.md.erb +27 -42
- data/docs/resources/shadow.md.erb +20 -35
- data/docs/resources/ssh_config.md.erb +19 -34
- data/docs/resources/sshd_config.md.erb +19 -34
- data/docs/resources/ssl.md.erb +39 -54
- data/docs/resources/sys_info.md.erb +12 -26
- data/docs/resources/systemd_service.md.erb +5 -25
- data/docs/resources/sysv_service.md.erb +5 -25
- data/docs/resources/upstart_service.md.erb +5 -25
- data/docs/resources/user.md.erb +29 -44
- data/docs/resources/users.md.erb +12 -26
- data/docs/resources/vbscript.md.erb +9 -24
- data/docs/resources/virtualization.md.erb +8 -23
- data/docs/resources/windows_feature.md.erb +15 -30
- data/docs/resources/windows_hotfix.md.erb +15 -9
- data/docs/resources/windows_task.md.erb +12 -26
- data/docs/resources/wmi.md.erb +9 -24
- data/docs/resources/x509_certificate.md.erb +4 -0
- data/docs/resources/xinetd_conf.md.erb +65 -80
- data/docs/resources/xml.md.erb +12 -26
- data/docs/resources/yaml.md.erb +12 -27
- data/docs/resources/yum.md.erb +37 -51
- data/docs/resources/zfs_dataset.md.erb +15 -26
- data/docs/resources/zfs_pool.md.erb +9 -20
- data/lib/inspec/backend.rb +8 -0
- data/lib/inspec/profile.rb +9 -1
- data/lib/inspec/shell.rb +13 -13
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +2 -0
- data/lib/resources/etc_hosts.rb +1 -1
- data/lib/resources/host.rb +4 -1
- data/lib/resources/http.rb +173 -23
- data/lib/resources/processes.rb +106 -20
- data/lib/resources/ssh_conf.rb +1 -1
- data/lib/resources/ssl.rb +4 -3
- data/lib/utils/object_traversal.rb +35 -10
- metadata +2 -2
@@ -6,6 +6,8 @@ title: About the zfs_dataset Resource
|
|
6
6
|
|
7
7
|
Use the `zfs_dataset` InSpec audit resource to test the ZFS datasets on FreeBSD systems.
|
8
8
|
|
9
|
+
<br>
|
10
|
+
|
9
11
|
## Syntax
|
10
12
|
|
11
13
|
A `zfs_dataset` resource block declares the ZFS dataset properties that should be tested:
|
@@ -20,32 +22,7 @@ where
|
|
20
22
|
* `MATCHER` is a valid matcher for this resource
|
21
23
|
* `'value'` is the value to be tested
|
22
24
|
|
23
|
-
|
24
|
-
## Matchers
|
25
|
-
|
26
|
-
This InSpec audit resource has the matchers listed below, in addition to dynamically exposing all ZFS dataset properties available (see: `man zfs` for the list of supported properties.)
|
27
|
-
|
28
|
-
### be
|
29
|
-
|
30
|
-
<%= partial "/shared/matcher_be" %>
|
31
|
-
|
32
|
-
### be_mounted
|
33
|
-
|
34
|
-
The `be_mounted` matcher tests if the dataset is accessible from the file system:
|
35
|
-
|
36
|
-
it { should be_mounted }
|
37
|
-
|
38
|
-
### cmp
|
39
|
-
|
40
|
-
<%= partial "/shared/matcher_cmp" %>
|
41
|
-
|
42
|
-
### eq
|
43
|
-
|
44
|
-
<%= partial "/shared/matcher_eq" %>
|
45
|
-
|
46
|
-
### match
|
47
|
-
|
48
|
-
<%= partial "/shared/matcher_match" %>
|
25
|
+
<br>
|
49
26
|
|
50
27
|
## Examples
|
51
28
|
|
@@ -61,3 +38,15 @@ The following examples show how to use this InSpec audit resource.
|
|
61
38
|
its('readonly') { should eq 'off' }
|
62
39
|
its('setuid') { should eq 'off' }
|
63
40
|
end
|
41
|
+
|
42
|
+
<br>
|
43
|
+
|
44
|
+
## Matchers
|
45
|
+
|
46
|
+
This InSpec audit resource has the matchers listed below, in addition to dynamically exposing all ZFS dataset properties available (see: `man zfs` for the list of supported properties). For a full list of available matchers please visit our [matchers page](https://www.inspec.io/docs/reference/matchers/).
|
47
|
+
|
48
|
+
### be_mounted
|
49
|
+
|
50
|
+
The `be_mounted` matcher tests if the dataset is accessible from the file system:
|
51
|
+
|
52
|
+
it { should be_mounted }
|
@@ -6,6 +6,8 @@ title: About the zfs_pool Resource
|
|
6
6
|
|
7
7
|
Use the `zfs_pool` InSpec audit resource to test the ZFS pools on FreeBSD systems.
|
8
8
|
|
9
|
+
<br>
|
10
|
+
|
9
11
|
## Syntax
|
10
12
|
|
11
13
|
A `zfs_pool` resource block declares the ZFS pool properties that should be tested:
|
@@ -20,26 +22,7 @@ where
|
|
20
22
|
* `MATCHER` is a valid matcher for this resource
|
21
23
|
* `'value'` is the value to be tested
|
22
24
|
|
23
|
-
|
24
|
-
## Matchers
|
25
|
-
|
26
|
-
This InSpec audit resource has the matchers listed below, in addition to dynamically exposing all ZFS pool properties available (see: `man zpool` for the list of supported properties.)
|
27
|
-
|
28
|
-
### be
|
29
|
-
|
30
|
-
<%= partial "/shared/matcher_be" %>
|
31
|
-
|
32
|
-
### cmp
|
33
|
-
|
34
|
-
<%= partial "/shared/matcher_cmp" %>
|
35
|
-
|
36
|
-
### eq
|
37
|
-
|
38
|
-
<%= partial "/shared/matcher_eq" %>
|
39
|
-
|
40
|
-
### match
|
41
|
-
|
42
|
-
<%= partial "/shared/matcher_match" %>
|
25
|
+
<br>
|
43
26
|
|
44
27
|
## Examples
|
45
28
|
|
@@ -55,3 +38,9 @@ The following examples show how to use this InSpec audit resource.
|
|
55
38
|
its('listsnapshots') { should eq 'off' }
|
56
39
|
its('readonly') { should eq 'off' }
|
57
40
|
end
|
41
|
+
|
42
|
+
<br>
|
43
|
+
|
44
|
+
## Matchers
|
45
|
+
|
46
|
+
This InSpec audit resource dynamically exposes all ZFS pool properties available (see: `man zpool` for the list of supported properties). For a full list of available matchers please visit our [matchers page](https://www.inspec.io/docs/reference/matchers/).
|
data/lib/inspec/backend.rb
CHANGED
@@ -17,6 +17,14 @@ module Inspec
|
|
17
17
|
Inspec::VERSION
|
18
18
|
end
|
19
19
|
|
20
|
+
# Determine whether the connection/transport is a local connection
|
21
|
+
# Useful for resources to modify behavior as necessary, such as using
|
22
|
+
# the Ruby stdlib for a better experience.
|
23
|
+
def local_transport?
|
24
|
+
return false unless defined?(Train::Transports::Local)
|
25
|
+
backend.is_a?(Train::Transports::Local::Connection)
|
26
|
+
end
|
27
|
+
|
20
28
|
# Ruby internal for printing a nice name for this class
|
21
29
|
def to_s
|
22
30
|
'Inspec::Backend::Class'
|
data/lib/inspec/profile.rb
CHANGED
@@ -93,12 +93,20 @@ module Inspec
|
|
93
93
|
@writable = options[:writable] || false
|
94
94
|
@profile_id = options[:id]
|
95
95
|
@cache = options[:cache] || Cache.new
|
96
|
-
@backend = options[:backend] || Inspec::Backend.create(options.select { |k, _| k != 'target' })
|
97
96
|
@attr_values = options[:attributes]
|
98
97
|
@tests_collected = false
|
99
98
|
@libraries_loaded = false
|
100
99
|
Metadata.finalize(@source_reader.metadata, @profile_id, options)
|
101
100
|
|
101
|
+
# if a backend has already been created, clone it so each profile has its own unique backend object
|
102
|
+
# otherwise, create a new backend object
|
103
|
+
#
|
104
|
+
# This is necessary since we store the RuntimeProfile on the backend object. If a user runs `inspec exec`
|
105
|
+
# with multiple profiles, only the RuntimeProfile for the last-loaded profile will be available if
|
106
|
+
# we share the backend between profiles.
|
107
|
+
#
|
108
|
+
# This will cause issues if a profile attempts to load a file via `inspec.profile.file`
|
109
|
+
@backend = options[:backend].nil? ? Inspec::Backend.create(options) : options[:backend].dup
|
102
110
|
@runtime_profile = RuntimeProfile.new(self)
|
103
111
|
@backend.profile = @runtime_profile
|
104
112
|
|
data/lib/inspec/shell.rb
CHANGED
@@ -139,21 +139,21 @@ EOF
|
|
139
139
|
elsif topic == 'matchers'
|
140
140
|
print_matchers_help
|
141
141
|
elsif !Inspec::Resource.registry[topic].nil?
|
142
|
-
|
143
|
-
#{mark 'Name:'} #{topic}
|
144
|
-
|
145
|
-
#{mark 'Description:'}
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#{mark 'Example:'}
|
150
|
-
#{print_example(Inspec::Resource.registry[topic].example)}
|
151
|
-
|
152
|
-
#{mark 'Web Reference:'}
|
142
|
+
topic_info = Inspec::Resource.registry[topic]
|
143
|
+
info = "#{mark 'Name:'} #{topic}\n\n"
|
144
|
+
unless topic_info.desc.nil?
|
145
|
+
info += "#{mark 'Description:'}\n\n"
|
146
|
+
info += "#{topic_info.desc}\n\n"
|
147
|
+
end
|
153
148
|
|
154
|
-
|
149
|
+
unless topic_info.example.nil?
|
150
|
+
info += "#{mark 'Example:'}\n"
|
151
|
+
info += "#{print_example(topic_info.example)}\n\n"
|
152
|
+
end
|
155
153
|
|
156
|
-
|
154
|
+
info += "#{mark 'Web Reference:'}\n\n"
|
155
|
+
info += "https://www.inspec.io/docs/reference/resources/#{topic}\n\n"
|
156
|
+
puts info
|
157
157
|
else
|
158
158
|
puts "The resource #{topic} does not exist. For a list of valid resources, type: help resources"
|
159
159
|
end
|
data/lib/inspec/version.rb
CHANGED
data/lib/matchers/matchers.rb
CHANGED
@@ -316,6 +316,8 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
316
316
|
return actual.to_i.method(op).call(expected)
|
317
317
|
elsif expected.is_a?(Float) && float?(actual)
|
318
318
|
return actual.to_f.method(op).call(expected)
|
319
|
+
elsif actual.is_a?(Symbol) && expected.is_a?(String)
|
320
|
+
return actual.to_s.method(op).call(expected)
|
319
321
|
elsif octal?(expected) && actual.is_a?(Integer)
|
320
322
|
return actual.method(op).call(expected.to_i(8))
|
321
323
|
end
|
data/lib/resources/etc_hosts.rb
CHANGED
@@ -20,7 +20,7 @@ class EtcHosts < Inspec.resource(1)
|
|
20
20
|
include CommentParser
|
21
21
|
|
22
22
|
def initialize(hosts_path = nil)
|
23
|
-
return skip_resource 'The `etc_hosts` resource is not supported on your OS.' unless inspec.os.linux? || inspec.os.windows?
|
23
|
+
return skip_resource 'The `etc_hosts` resource is not supported on your OS.' unless inspec.os.bsd? || inspec.os.linux? || inspec.os.windows?
|
24
24
|
@conf_path = hosts_path || default_hosts_file_path
|
25
25
|
@content = nil
|
26
26
|
@params = nil
|
data/lib/resources/host.rb
CHANGED
data/lib/resources/http.rb
CHANGED
@@ -22,51 +22,201 @@ module Inspec::Resources
|
|
22
22
|
its('Content-Length') { should cmp 258 }
|
23
23
|
its('Content-Type') { should cmp 'text/html; charset=UTF-8' }
|
24
24
|
end
|
25
|
+
|
26
|
+
# properly execute the HTTP call on the scanned machine instead of the
|
27
|
+
# machine executing InSpec. This will be the default behavior in InSpec 2.0.
|
28
|
+
describe http('http://localhost:8080', enable_remote_worker: true) do
|
29
|
+
its('body') { should cmp 'local web server on target machine' }
|
30
|
+
end
|
25
31
|
"
|
26
32
|
|
27
33
|
def initialize(url, opts = {})
|
28
34
|
@url = url
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
@opts = opts
|
36
|
+
|
37
|
+
if use_remote_worker?
|
38
|
+
return skip_resource 'curl is not available on the target machine' unless inspec.command('curl').exist?
|
39
|
+
@worker = Worker::Remote.new(inspec, http_method, url, opts)
|
40
|
+
else
|
41
|
+
@worker = Worker::Local.new(http_method, url, opts)
|
42
|
+
end
|
37
43
|
end
|
38
44
|
|
39
45
|
def status
|
40
|
-
|
46
|
+
@worker.status
|
47
|
+
end
|
48
|
+
|
49
|
+
def headers
|
50
|
+
Hashie::Mash.new(@worker.response_headers)
|
41
51
|
end
|
42
52
|
|
43
53
|
def body
|
44
|
-
|
54
|
+
@worker.body
|
45
55
|
end
|
46
56
|
|
47
|
-
def
|
48
|
-
|
57
|
+
def http_method
|
58
|
+
@opts.fetch(:method, 'GET')
|
49
59
|
end
|
50
60
|
|
51
61
|
def to_s
|
52
|
-
"http #{
|
62
|
+
"http #{http_method} on #{@url}"
|
53
63
|
end
|
54
64
|
|
55
65
|
private
|
56
66
|
|
57
|
-
def
|
58
|
-
return
|
59
|
-
|
67
|
+
def use_remote_worker?
|
68
|
+
return false if inspec.local_transport?
|
69
|
+
return true if @opts[:enable_remote_worker]
|
70
|
+
|
71
|
+
warn "[DEPRECATION] #{self} will execute locally instead of the target machine. To execute remotely, add `enable_remote_worker: true`."
|
72
|
+
warn '[DEPRECATION] `enable_remote_worker: true` will be the default behavior in InSpec 2.0.'
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
class Worker
|
77
|
+
class Base
|
78
|
+
attr_reader :http_method, :opts, :url
|
79
|
+
|
80
|
+
def initialize(http_method, url, opts)
|
81
|
+
@http_method = http_method
|
82
|
+
@url = url
|
83
|
+
@opts = opts
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def params
|
89
|
+
opts.fetch(:params, nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
def username
|
93
|
+
opts.fetch(:auth, {})[:user]
|
94
|
+
end
|
95
|
+
|
96
|
+
def password
|
97
|
+
opts.fetch(:auth, {})[:pass]
|
98
|
+
end
|
99
|
+
|
100
|
+
def request_headers
|
101
|
+
opts.fetch(:headers, {})
|
102
|
+
end
|
103
|
+
|
104
|
+
def request_body
|
105
|
+
opts[:data]
|
106
|
+
end
|
107
|
+
|
108
|
+
def open_timeout
|
109
|
+
opts.fetch(:open_timeout, 60)
|
110
|
+
end
|
111
|
+
|
112
|
+
def read_timeout
|
113
|
+
opts.fetch(:read_timeout, 60)
|
114
|
+
end
|
115
|
+
|
116
|
+
def ssl_verify?
|
117
|
+
opts.fetch(:ssl_verify, true)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Local < Base
|
122
|
+
def status
|
123
|
+
response.status
|
124
|
+
end
|
125
|
+
|
126
|
+
def body
|
127
|
+
response.body
|
128
|
+
end
|
129
|
+
|
130
|
+
def response_headers
|
131
|
+
response.headers.to_h
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def response
|
137
|
+
return @response if @response
|
138
|
+
conn = Faraday.new url: url, headers: request_headers, params: params, ssl: { verify: ssl_verify? }
|
139
|
+
|
140
|
+
# set basic authentication
|
141
|
+
conn.basic_auth username, password unless username.nil? || password.nil?
|
142
|
+
|
143
|
+
# set default timeout
|
144
|
+
conn.options.timeout = read_timeout # open/read timeout in seconds
|
145
|
+
conn.options.open_timeout = open_timeout # connection open timeout in seconds
|
146
|
+
|
147
|
+
@response = conn.send(http_method.downcase) do |req|
|
148
|
+
req.body = request_body
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class Remote < Base
|
154
|
+
attr_reader :inspec
|
155
|
+
|
156
|
+
def initialize(inspec, http_method, url, opts)
|
157
|
+
@inspec = inspec
|
158
|
+
super(http_method, url, opts)
|
159
|
+
end
|
160
|
+
|
161
|
+
def status
|
162
|
+
run_curl
|
163
|
+
@status
|
164
|
+
end
|
165
|
+
|
166
|
+
def body
|
167
|
+
run_curl
|
168
|
+
@body
|
169
|
+
end
|
170
|
+
|
171
|
+
def response_headers
|
172
|
+
run_curl
|
173
|
+
@response_headers
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def run_curl
|
179
|
+
return if @ran_curl
|
180
|
+
|
181
|
+
response = inspec.command(curl_command).stdout
|
182
|
+
@ran_curl = true
|
183
|
+
return if response.nil?
|
184
|
+
|
185
|
+
# strip any carriage returns to normalize output
|
186
|
+
response.delete!("\r")
|
187
|
+
|
188
|
+
# split the prelude (status line and headers) and the body
|
189
|
+
prelude, @body = response.split("\n\n", 2)
|
190
|
+
prelude = prelude.lines
|
191
|
+
|
192
|
+
# grab the status off of the first line of the prelude
|
193
|
+
status_line = prelude.shift
|
194
|
+
@status = status_line.split(' ', 3)[1].to_i
|
195
|
+
|
196
|
+
# parse the rest of the prelude which will be all the HTTP headers
|
197
|
+
@response_headers = {}
|
198
|
+
prelude.each do |line|
|
199
|
+
line.strip!
|
200
|
+
key, value = line.split(':', 2)
|
201
|
+
@response_headers[key] = value.strip
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def curl_command
|
206
|
+
cmd = ["curl -i -X #{http_method}"]
|
207
|
+
cmd << "--connect-timeout #{open_timeout}"
|
208
|
+
cmd << "--user \'#{username}:#{password}\'" unless username.nil? || password.nil?
|
209
|
+
cmd << '--insecure' unless ssl_verify?
|
210
|
+
cmd << "--data #{Shellwords.shellescape(request_body)}" unless request_body.nil?
|
60
211
|
|
61
|
-
|
62
|
-
|
212
|
+
request_headers.each do |k, v|
|
213
|
+
cmd << "-H '#{k}=#{v}'"
|
214
|
+
end
|
63
215
|
|
64
|
-
|
65
|
-
conn.options.timeout = @read_timeout # open/read timeout in seconds
|
66
|
-
conn.options.open_timeout = @open_timeout # connection open timeout in seconds
|
216
|
+
cmd << "'#{url}'"
|
67
217
|
|
68
|
-
|
69
|
-
|
218
|
+
cmd.join(' ')
|
219
|
+
end
|
70
220
|
end
|
71
221
|
end
|
72
222
|
end
|
data/lib/resources/processes.rb
CHANGED
@@ -4,9 +4,10 @@
|
|
4
4
|
# author: Christoph Hartmann
|
5
5
|
|
6
6
|
require 'utils/filter'
|
7
|
+
require 'ostruct'
|
7
8
|
|
8
9
|
module Inspec::Resources
|
9
|
-
class Processes < Inspec.resource(1)
|
10
|
+
class Processes < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
10
11
|
name 'processes'
|
11
12
|
desc 'Use the processes InSpec audit resource to test properties for programs that are running on the system.'
|
12
13
|
example "
|
@@ -15,12 +16,18 @@ module Inspec::Resources
|
|
15
16
|
its('users') { should eq ['mysql'] }
|
16
17
|
its('states') { should include 'S' }
|
17
18
|
end
|
19
|
+
|
18
20
|
describe processes(/.+/).where { label != 'unconfined' && pid < 1000 } do
|
19
21
|
its('users') { should cmp [] }
|
20
22
|
end
|
23
|
+
|
24
|
+
# work with all processes
|
25
|
+
describe processes do
|
26
|
+
its('entries.length') { should be <= 100 }
|
27
|
+
end
|
21
28
|
"
|
22
29
|
|
23
|
-
def initialize(grep)
|
30
|
+
def initialize(grep = /.*/)
|
24
31
|
@grep = grep
|
25
32
|
# turn into a regexp if it isn't one yet
|
26
33
|
if grep.class == String
|
@@ -80,39 +87,118 @@ module Inspec::Resources
|
|
80
87
|
os = inspec.os
|
81
88
|
|
82
89
|
if os.linux?
|
83
|
-
command
|
84
|
-
regex = /^(.+?)\s+(\d+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
90
|
+
command, regex, field_map = ps_configuration_for_linux
|
85
91
|
elsif os.windows?
|
86
92
|
command = '$Proc = Get-Process -IncludeUserName | Where-Object {$_.Path -ne $null } | Select-Object PriorityClass,Id,CPU,PM,VirtualMemorySize,NPM,SessionId,Responding,StartTime,TotalProcessorTime,UserName,Path | ConvertTo-Csv -NoTypeInformation;$Proc.Replace("""","").Replace("`r`n","`n")'
|
87
93
|
# Wanted to use /(?:^|,)([^,]*)/; works on rubular.com not sure why here?
|
88
94
|
regex = /^(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+)$/
|
95
|
+
field_map = {
|
96
|
+
pid: 2,
|
97
|
+
cpu: 3,
|
98
|
+
mem: 4,
|
99
|
+
vsz: 5,
|
100
|
+
rss: 6,
|
101
|
+
tty: 7,
|
102
|
+
stat: 8,
|
103
|
+
start: 9,
|
104
|
+
time: 10,
|
105
|
+
user: 11,
|
106
|
+
command: 12,
|
107
|
+
}
|
89
108
|
else
|
90
109
|
command = 'ps axo pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user,command'
|
91
110
|
regex = /^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
111
|
+
field_map = {
|
112
|
+
pid: 1,
|
113
|
+
cpu: 2,
|
114
|
+
mem: 3,
|
115
|
+
vsz: 4,
|
116
|
+
rss: 5,
|
117
|
+
tty: 6,
|
118
|
+
stat: 7,
|
119
|
+
start: 8,
|
120
|
+
time: 9,
|
121
|
+
user: 10,
|
122
|
+
command: 11,
|
123
|
+
}
|
92
124
|
end
|
93
|
-
build_process_list(command, regex,
|
125
|
+
build_process_list(command, regex, field_map)
|
94
126
|
end
|
95
127
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
128
|
+
def ps_configuration_for_linux
|
129
|
+
if busybox_ps?
|
130
|
+
command = 'ps -o pid,vsz,rss,tty,stat,time,ruser,args'
|
131
|
+
regex = /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/
|
132
|
+
field_map = {
|
133
|
+
pid: 1,
|
134
|
+
vsz: 2,
|
135
|
+
rss: 3,
|
136
|
+
tty: 4,
|
137
|
+
stat: 5,
|
138
|
+
time: 6,
|
139
|
+
user: 7,
|
140
|
+
command: 8,
|
141
|
+
}
|
142
|
+
else
|
143
|
+
command = 'ps axo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command'
|
144
|
+
regex = /^(.+?)\s+(\d+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
145
|
+
field_map = {
|
146
|
+
label: 1,
|
147
|
+
pid: 2,
|
148
|
+
cpu: 3,
|
149
|
+
mem: 4,
|
150
|
+
vsz: 5,
|
151
|
+
rss: 6,
|
152
|
+
tty: 7,
|
153
|
+
stat: 8,
|
154
|
+
start: 9,
|
155
|
+
time: 10,
|
156
|
+
user: 11,
|
157
|
+
command: 12,
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
[command, regex, field_map]
|
162
|
+
end
|
100
163
|
|
101
|
-
def
|
164
|
+
def busybox_ps?
|
165
|
+
@busybox_ps ||= inspec.command('ps --help').stderr.include?('BusyBox')
|
166
|
+
end
|
167
|
+
|
168
|
+
def build_process_list(command, regex, field_map)
|
102
169
|
cmd = inspec.command(command)
|
103
170
|
all = cmd.stdout.split("\n")[1..-1]
|
104
171
|
return [] if all.nil?
|
105
|
-
|
106
|
-
|
172
|
+
|
173
|
+
# map all the process lines into match objects, fetch the available fields,
|
174
|
+
# and then build an OpenStruct of the process data for each process
|
175
|
+
all.map do |line|
|
176
|
+
line = line.match(regex)
|
177
|
+
|
178
|
+
# skip this line if we couldn't match the regular expression
|
179
|
+
next if line.nil?
|
180
|
+
|
181
|
+
# skip this entry if there's no command for this line
|
182
|
+
next if line[field_map[:command]].nil?
|
183
|
+
|
184
|
+
# build a hash of process data that we'll turn into a struct for FilterTable
|
185
|
+
process_data = {}
|
186
|
+
[:label, :pid, :cpu, :mem, :vsz, :rss, :tty, :stat, :start, :time, :user, :command].each do |param|
|
187
|
+
# not all operating systems support all fields, so skip the field if we don't have it
|
188
|
+
process_data[param] = line[field_map[param]] if field_map.key?(param)
|
189
|
+
end
|
190
|
+
|
191
|
+
# ensure pid, vsz, and rss are integers for backward compatibility
|
192
|
+
[:pid, :vsz, :rss].each do |int_param|
|
193
|
+
process_data[int_param] = process_data[int_param].to_i if process_data.key?(int_param)
|
194
|
+
end
|
195
|
+
|
196
|
+
# strip any newlines off the command
|
197
|
+
process_data[:command].strip!
|
198
|
+
|
199
|
+
# return an OpenStruct of the process for future use by FilterTable
|
200
|
+
OpenStruct.new(process_data)
|
107
201
|
end.compact
|
108
|
-
lines.map do |m|
|
109
|
-
a = m.to_a[1..-1] # grab all matching groups
|
110
|
-
a.unshift(nil) unless os.linux? || os.windows?
|
111
|
-
a[1] = a[1].to_i
|
112
|
-
a[4] = a[4].to_i
|
113
|
-
a[5] = a[5].to_i
|
114
|
-
Process.new(*a)
|
115
|
-
end
|
116
202
|
end
|
117
203
|
end
|
118
204
|
end
|