inspec-core 4.46.13 → 4.49.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/lib/inspec/base_cli.rb +4 -0
- data/lib/inspec/cli.rb +10 -3
- data/lib/inspec/profile.rb +113 -2
- data/lib/inspec/resources/cassandra.rb +64 -0
- data/lib/inspec/resources/cassandradb_conf.rb +47 -0
- data/lib/inspec/resources/cassandradb_session.rb +68 -0
- data/lib/inspec/resources/groups.rb +22 -3
- data/lib/inspec/resources/oracledb_session.rb +23 -6
- data/lib/inspec/resources/users.rb +16 -2
- data/lib/inspec/resources/windows_firewall.rb +1 -1
- data/lib/inspec/resources.rb +3 -0
- data/lib/inspec/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31dcab9ba9621f43755fc390ad061c08b7e6ab19466d26a38921d33960e1bbf5
|
4
|
+
data.tar.gz: eecdf0ec772ef012bfbf5185b379c47dd008fe902b9e91d4feee6979b0294c0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1059703ad59c2bf7c213a0914f94a8852cc550b1d305f634e07a08b364edae5c0f550927a8bcec9e712cd313949388082fdebf5c3164147ef12c21df952281b9
|
7
|
+
data.tar.gz: 1d4e6e64b8851c40349b7d696d46904fa73c0683d19c70afaa942a4c4bef4591a3ed4d7ec2c89aa5f7717da70617d70f182a7e9b894338da77592231b4c62234
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -174,6 +174,10 @@ module Inspec
|
|
174
174
|
desc: "After normal execution order, results are sorted by control ID, or by file (default), or randomly. None uses legacy unsorted mode."
|
175
175
|
option :filter_empty_profiles, type: :boolean, default: false,
|
176
176
|
desc: "Filter empty profiles (profiles without controls) from the report."
|
177
|
+
option :filter_waived_controls, type: :boolean,
|
178
|
+
desc: "Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores `run` setting of waiver file."
|
179
|
+
option :retain_waiver_data, type: :boolean,
|
180
|
+
desc: "EXPERIMENTAL: Only works in conjunction with --filter-waived-controls, retains waiver data about controls that were skipped"
|
177
181
|
option :command_timeout, type: :numeric,
|
178
182
|
desc: "Maximum seconds to allow commands to run during execution.",
|
179
183
|
long_desc: "Maximum seconds to allow commands to run during execution. A timed out command is considered an error."
|
data/lib/inspec/cli.rb
CHANGED
@@ -122,8 +122,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
122
122
|
end
|
123
123
|
puts
|
124
124
|
|
125
|
-
if result[:errors].empty? && result[:warnings].empty?
|
126
|
-
ui.plain_line("No errors or
|
125
|
+
if result[:errors].empty? && result[:warnings].empty? && result[:offenses].empty?
|
126
|
+
ui.plain_line("No errors, warnings, or offenses")
|
127
127
|
else
|
128
128
|
item_msg = lambda { |item|
|
129
129
|
pos = [item[:file], item[:line], item[:column]].compact.join(":")
|
@@ -135,11 +135,18 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
135
135
|
|
136
136
|
puts
|
137
137
|
|
138
|
+
unless result[:offenses].empty?
|
139
|
+
puts "Offenses:\n"
|
140
|
+
result[:offenses].each { |item| ui.cyan(" #{Inspec::UI::GLYPHS[:script_x]} #{item_msg.call(item)}\n\n") }
|
141
|
+
end
|
142
|
+
|
143
|
+
offenses = ui.cyan("#{result[:offenses].length} offenses", print: false)
|
138
144
|
errors = ui.red("#{result[:errors].length} errors", print: false)
|
139
145
|
warnings = ui.yellow("#{result[:warnings].length} warnings", print: false)
|
140
|
-
ui.plain_line("Summary: #{errors}, #{warnings}")
|
146
|
+
ui.plain_line("Summary: #{errors}, #{warnings}, #{offenses}")
|
141
147
|
end
|
142
148
|
end
|
149
|
+
|
143
150
|
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless result[:summary][:valid]
|
144
151
|
rescue StandardError => e
|
145
152
|
pretty_handle_exception(e)
|
data/lib/inspec/profile.rb
CHANGED
@@ -217,6 +217,9 @@ module Inspec
|
|
217
217
|
|
218
218
|
locked_dependencies.each(&:collect_tests)
|
219
219
|
|
220
|
+
tests = filter_waived_controls
|
221
|
+
|
222
|
+
# Collect tests
|
220
223
|
tests.each do |path, content|
|
221
224
|
next if content.nil? || content.empty?
|
222
225
|
|
@@ -233,6 +236,65 @@ module Inspec
|
|
233
236
|
@runner_context.all_rules
|
234
237
|
end
|
235
238
|
|
239
|
+
# Wipe out waived controls
|
240
|
+
def filter_waived_controls
|
241
|
+
cfg = Inspec::Config.cached
|
242
|
+
return tests unless cfg["filter_waived_controls"]
|
243
|
+
|
244
|
+
## Find the waivers file
|
245
|
+
# - TODO: cli_opts and instance_variable_get could be exposed
|
246
|
+
waiver_paths = cfg.instance_variable_get(:@cli_opts)["waiver_file"]
|
247
|
+
if waiver_paths.blank?
|
248
|
+
Inspec::Log.error "Must use --waiver-file with --filter-waived-controls"
|
249
|
+
Inspec::UI.new.exit(:usage_error)
|
250
|
+
end
|
251
|
+
|
252
|
+
# # Pull together waiver
|
253
|
+
waived_control_ids = []
|
254
|
+
waiver_paths.each do |waiver_path|
|
255
|
+
waiver_content = YAML.load_file(waiver_path)
|
256
|
+
unless waiver_content
|
257
|
+
# Note that we will have already issued a detailed warning
|
258
|
+
Inspec::Log.error "YAML parsing error in #{waiver_path}"
|
259
|
+
Inspec::UI.new.exit(:usage_error)
|
260
|
+
end
|
261
|
+
waived_control_ids << waiver_content.keys
|
262
|
+
end
|
263
|
+
waived_control_id_regex = "(#{waived_control_ids.join("|")})"
|
264
|
+
|
265
|
+
## Purge tests (this could be doone in next block for performance)
|
266
|
+
## TODO: implement earlier with pure AST and pure autocorrect AST
|
267
|
+
filtered_tests = {}
|
268
|
+
if cfg["retain_waiver_data"]
|
269
|
+
# VERY EXPERIMENTAL, but an empty describe block at the top level
|
270
|
+
# of the control blocks evaluation of ruby code until later-term
|
271
|
+
# waivers (behind the scenes this tells RSpec to hold on and use its internals to lazy load the code). This allows current waiver-data (e.g. skips) to still
|
272
|
+
# be processed and rendered
|
273
|
+
tests.each do |control_filename, source_code|
|
274
|
+
cleared_tests = source_code.scan(/control\s+['"].+?['"].+?(?=(?:control\s+['"].+?['"])|\z)/m).collect do |element|
|
275
|
+
next if element.blank?
|
276
|
+
|
277
|
+
if element&.match?(waived_control_id_regex)
|
278
|
+
splitlines = element.split("\n")
|
279
|
+
splitlines[0] + "\ndescribe '---' do\n" + splitlines[1..-1].join("\n") + "\nend\n"
|
280
|
+
else
|
281
|
+
element
|
282
|
+
end
|
283
|
+
end.join("")
|
284
|
+
filtered_tests[control_filename] = cleared_tests
|
285
|
+
end
|
286
|
+
else
|
287
|
+
tests.each do |control_filename, source_code|
|
288
|
+
cleared_tests = source_code.scan(/control\s+['"].+?['"].+?(?=(?:control\s+['"].+?['"])|\z)/m).select do |control_code|
|
289
|
+
!control_code.match?(waived_control_id_regex)
|
290
|
+
end.join("")
|
291
|
+
|
292
|
+
filtered_tests[control_filename] = cleared_tests
|
293
|
+
end
|
294
|
+
end
|
295
|
+
filtered_tests
|
296
|
+
end
|
297
|
+
|
236
298
|
# This creates the list of controls provided in the --controls options which need to be include
|
237
299
|
# for evaluation.
|
238
300
|
def include_controls_list
|
@@ -386,6 +448,43 @@ module Inspec
|
|
386
448
|
res
|
387
449
|
end
|
388
450
|
|
451
|
+
def cookstyle_linting_check
|
452
|
+
msgs = []
|
453
|
+
output = cookstyle_rake_output.split("Offenses:").last
|
454
|
+
msgs = output.split("\n").select { |x| x =~ /[A-Z]:/ } unless output.nil?
|
455
|
+
msgs
|
456
|
+
end
|
457
|
+
|
458
|
+
# Cookstyle linting rake run output
|
459
|
+
def cookstyle_rake_output
|
460
|
+
require "cookstyle"
|
461
|
+
require "rubocop/rake_task"
|
462
|
+
begin
|
463
|
+
RuboCop::RakeTask.new(:cookstyle_lint) do |spec|
|
464
|
+
spec.options += [
|
465
|
+
"--display-cop-names",
|
466
|
+
"--parallel",
|
467
|
+
"--only=InSpec/Deprecations",
|
468
|
+
]
|
469
|
+
spec.patterns += Dir.glob("#{@target}/**/*.rb").reject { |f| File.directory?(f) }
|
470
|
+
spec.fail_on_error = false
|
471
|
+
end
|
472
|
+
rescue LoadError
|
473
|
+
puts "Rubocop is not available. Install the rubocop gem to run the lint tests."
|
474
|
+
end
|
475
|
+
begin
|
476
|
+
stdout = StringIO.new
|
477
|
+
$stdout = stdout
|
478
|
+
Rake::Task["cookstyle_lint"].invoke
|
479
|
+
$stdout = STDOUT
|
480
|
+
Rake.application["cookstyle_lint"].reenable
|
481
|
+
stdout.string
|
482
|
+
rescue => e
|
483
|
+
puts "Cookstyle lint checks could not be performed. Error while running cookstyle - #{e}"
|
484
|
+
""
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
389
488
|
# Check if the profile is internally well-structured. The logger will be
|
390
489
|
# used to print information on errors and warnings which are found.
|
391
490
|
#
|
@@ -402,6 +501,7 @@ module Inspec
|
|
402
501
|
},
|
403
502
|
errors: [],
|
404
503
|
warnings: [],
|
504
|
+
offenses: [],
|
405
505
|
}
|
406
506
|
|
407
507
|
entry = lambda { |file, line, column, control, msg|
|
@@ -424,6 +524,10 @@ module Inspec
|
|
424
524
|
result[:errors].push(entry.call(file, line, column, control, msg))
|
425
525
|
}
|
426
526
|
|
527
|
+
offense = lambda { |file, line, column, control, msg|
|
528
|
+
result[:offenses].push(entry.call(file, line, column, control, msg))
|
529
|
+
}
|
530
|
+
|
427
531
|
@logger.info "Checking profile in #{@target}"
|
428
532
|
meta_path = @source_reader.target.abs_path(@source_reader.metadata.ref)
|
429
533
|
|
@@ -486,8 +590,15 @@ module Inspec
|
|
486
590
|
warn.call(sfile, sline, nil, id, "Control #{id} has no tests defined") if control[:checks].nil? || control[:checks].empty?
|
487
591
|
end
|
488
592
|
|
489
|
-
#
|
490
|
-
|
593
|
+
# Running cookstyle to check for code offenses
|
594
|
+
cookstyle_linting_check.each do |lint_output|
|
595
|
+
data = lint_output.split(":")
|
596
|
+
msg = "#{data[-2]}:#{data[-1]}"
|
597
|
+
offense.call(data[0], data[1], data[2], nil, msg)
|
598
|
+
end
|
599
|
+
|
600
|
+
# profile is valid if we could not find any error & offenses
|
601
|
+
result[:summary][:valid] = result[:errors].empty? && result[:offenses].empty?
|
491
602
|
|
492
603
|
@logger.info "Control definitions OK." if result[:warnings].empty?
|
493
604
|
result
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Inspec::Resources
|
2
|
+
class Cassandra < Inspec.resource(1)
|
3
|
+
name "cassandra"
|
4
|
+
supports platform: "unix"
|
5
|
+
supports platform: "windows"
|
6
|
+
|
7
|
+
desc "The 'cassandra' resource is a helper for the 'cql_conf'"
|
8
|
+
|
9
|
+
attr_reader :conf_path
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
case inspec.os[:family]
|
13
|
+
when "debian", "redhat", "linux", "suse"
|
14
|
+
determine_conf_dir_and_path_in_linux
|
15
|
+
when "windows"
|
16
|
+
determine_conf_dir_and_path_in_windows
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"CassandraDB"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def determine_conf_dir_and_path_in_linux
|
27
|
+
cassandra_home = inspec.os_env("CASSANDRA_HOME").content
|
28
|
+
|
29
|
+
if cassandra_home.nil? || cassandra_home.empty?
|
30
|
+
warn "$CASSANDRA_HOME environment variable not set in the system"
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
conf_path = "#{cassandra_home}/cassandra.yaml"
|
34
|
+
if !inspec.file(conf_path).exist?
|
35
|
+
warn "Cassandra conf file not found in #{cassandra_home} directory."
|
36
|
+
nil
|
37
|
+
else
|
38
|
+
@conf_path = conf_path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
rescue => e
|
42
|
+
fail_resource "Errors reading cassandra conf file: #{e}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def determine_conf_dir_and_path_in_windows
|
46
|
+
cassandra_home = inspec.os_env("CASSANDRA_HOME").content
|
47
|
+
|
48
|
+
if cassandra_home.nil? || cassandra_home.empty?
|
49
|
+
warn "CASSANDRA_HOME environment variable not set in the system"
|
50
|
+
nil
|
51
|
+
else
|
52
|
+
conf_path = "#{cassandra_home}\\conf\\cassandra.yaml"
|
53
|
+
if !inspec.file(conf_path).exist?
|
54
|
+
warn "Cassandra conf file not found in #{cassandra_home}\\conf directory."
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
@conf_path = conf_path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rescue => e
|
61
|
+
fail_resource "Errors reading cassandra conf file: #{e}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "inspec/resources/json"
|
2
|
+
require "inspec/resources/cassandra"
|
3
|
+
|
4
|
+
module Inspec::Resources
|
5
|
+
class CassandradbConf < JsonConfig
|
6
|
+
name "cassandradb_conf"
|
7
|
+
supports platform: "unix"
|
8
|
+
supports platform: "windows"
|
9
|
+
desc "Use the cql_conf InSpec audit resource to test the contents of the configuration file for Cassandra DB"
|
10
|
+
example <<~EXAMPLE
|
11
|
+
describe cassandradb_conf do
|
12
|
+
its('listen_address') { should eq '0.0.0.0' }
|
13
|
+
end
|
14
|
+
EXAMPLE
|
15
|
+
|
16
|
+
def initialize(conf_path = nil)
|
17
|
+
cassandra = nil
|
18
|
+
if conf_path.nil?
|
19
|
+
cassandra = inspec.cassandra
|
20
|
+
@conf_path = cassandra.conf_path
|
21
|
+
else
|
22
|
+
@conf_path = conf_path
|
23
|
+
end
|
24
|
+
|
25
|
+
if cassandra && cassandra.resource_failed?
|
26
|
+
raise cassandra.resource_exception_message
|
27
|
+
elsif @conf_path.nil?
|
28
|
+
return skip_resource "Cassandra db conf path is not set"
|
29
|
+
end
|
30
|
+
|
31
|
+
super(@conf_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def parse(content)
|
37
|
+
YAML.load(content)
|
38
|
+
rescue => e
|
39
|
+
raise Inspec::Exceptions::ResourceFailed, "Unable to parse `cassandra.yaml` file: #{e.message}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def resource_base_name
|
43
|
+
"Cassandra Configuration"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Inspec::Resources
|
2
|
+
class Lines
|
3
|
+
attr_reader :output
|
4
|
+
|
5
|
+
def initialize(raw, desc)
|
6
|
+
@output = raw
|
7
|
+
@desc = desc
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
@desc
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CassandradbSession < Inspec.resource(1)
|
16
|
+
name "cassandradb_session"
|
17
|
+
supports platform: "unix"
|
18
|
+
supports platform: "windows"
|
19
|
+
desc "Use the cassandradb_session InSpec resource to test commands against an Cassandra database"
|
20
|
+
example <<~EXAMPLE
|
21
|
+
cql = cassandradb_session(user: 'my_user', password: 'password', host: 'host', port: 'port')
|
22
|
+
describe cql.query("SELECT cluster_name FROM system.local") do
|
23
|
+
its('output') { should match /Test Cluster/ }
|
24
|
+
end
|
25
|
+
EXAMPLE
|
26
|
+
|
27
|
+
attr_reader :user, :password, :host, :port
|
28
|
+
|
29
|
+
def initialize(opts = {})
|
30
|
+
@user = opts[:user] || "cassandra"
|
31
|
+
@password = opts[:password] || "cassandra"
|
32
|
+
@host = opts[:host]
|
33
|
+
@port = opts[:port]
|
34
|
+
end
|
35
|
+
|
36
|
+
def query(q)
|
37
|
+
cassandra_cmd = create_cassandra_cmd(q)
|
38
|
+
cmd = inspec.command(cassandra_cmd)
|
39
|
+
out = cmd.stdout + "\n" + cmd.stderr
|
40
|
+
if cmd.exit_status != 0 || out =~ /Unable to connect to any servers/ || out.downcase =~ /^error:.*/
|
41
|
+
raise Inspec::Exceptions::ResourceFailed, "Cassandra query with errors: #{out}"
|
42
|
+
else
|
43
|
+
Lines.new(cmd.stdout.strip, "Cassandra query: #{q}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
"Cassandra DB Session"
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def create_cassandra_cmd(q)
|
54
|
+
# TODO: simple escape, must be handled by a library
|
55
|
+
# that does this securely
|
56
|
+
escaped_query = q.gsub(/\\/, "\\\\").gsub(/"/, '\\"').gsub(/\$/, '\\$')
|
57
|
+
|
58
|
+
# construct the query
|
59
|
+
command = "cqlsh"
|
60
|
+
command += " #{@host}" unless @host.nil?
|
61
|
+
command += " #{@port}" unless @port.nil?
|
62
|
+
command += " -u #{@user}"
|
63
|
+
command += " -p #{@password}"
|
64
|
+
command += " --execute '#{escaped_query}'"
|
65
|
+
command
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -22,6 +22,18 @@ module Inspec::Resources
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
# Class defined to check for members without case-sensitivity
|
26
|
+
class Members < Array
|
27
|
+
def initialize(group_members)
|
28
|
+
@group_members = group_members
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def include?(user)
|
33
|
+
!(@group_members.select { |group_member| group_member.casecmp?(user) }.empty?)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
25
37
|
class Groups < Inspec.resource(1)
|
26
38
|
include GroupManagementSelector
|
27
39
|
|
@@ -82,6 +94,7 @@ module Inspec::Resources
|
|
82
94
|
# its('gid') { should eq 0 }
|
83
95
|
# end
|
84
96
|
#
|
97
|
+
|
85
98
|
class Group < Inspec.resource(1)
|
86
99
|
include GroupManagementSelector
|
87
100
|
|
@@ -118,11 +131,13 @@ module Inspec::Resources
|
|
118
131
|
end
|
119
132
|
|
120
133
|
def members
|
121
|
-
flatten_entry(group_info, "members") || empty_value_for_members
|
134
|
+
members_list = flatten_entry(group_info, "members") || empty_value_for_members
|
135
|
+
inspec.os.windows? ? Members.new(members_list) : members_list
|
122
136
|
end
|
123
137
|
|
124
138
|
def members_array
|
125
|
-
flatten_entry(group_info, "members_array") || []
|
139
|
+
members_list = flatten_entry(group_info, "members_array") || []
|
140
|
+
inspec.os.windows? ? Members.new(members_list) : members_list
|
126
141
|
end
|
127
142
|
|
128
143
|
def local
|
@@ -150,7 +165,11 @@ module Inspec::Resources
|
|
150
165
|
def group_info
|
151
166
|
# we need a local copy for the block
|
152
167
|
group = @group.dup
|
153
|
-
|
168
|
+
if inspec.os.windows?
|
169
|
+
@groups_cache ||= inspec.groups.where { name.casecmp?(group) }
|
170
|
+
else
|
171
|
+
@groups_cache ||= inspec.groups.where { name == group }
|
172
|
+
end
|
154
173
|
end
|
155
174
|
|
156
175
|
def empty_value_for_members
|
@@ -42,6 +42,7 @@ module Inspec::Resources
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def query(sql)
|
45
|
+
raise Inspec::Exceptions::ResourceSkipped, "#{resource_exception_message}" if resource_skipped?
|
45
46
|
raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
|
46
47
|
|
47
48
|
if @sqlcl_bin && inspec.command(@sqlcl_bin).exist?
|
@@ -78,7 +79,14 @@ module Inspec::Resources
|
|
78
79
|
# using a db_role
|
79
80
|
# su, using a db_role
|
80
81
|
def command_builder(format_options, query)
|
81
|
-
|
82
|
+
if @db_role.nil? || @su_user.nil?
|
83
|
+
verified_query = verify_query(query)
|
84
|
+
else
|
85
|
+
escaped_query = query.gsub(/\\\\/, "\\").gsub(/"/, '\\"')
|
86
|
+
escaped_query = escaped_query.gsub("$", '\\$') unless escaped_query.include? "\\$"
|
87
|
+
verified_query = verify_query(escaped_query)
|
88
|
+
end
|
89
|
+
|
82
90
|
sql_prefix, sql_postfix = "", ""
|
83
91
|
if inspec.os.windows?
|
84
92
|
sql_prefix = %{@'\n#{format_options}\n#{verified_query}\nEXIT\n'@ | }
|
@@ -87,11 +95,14 @@ module Inspec::Resources
|
|
87
95
|
end
|
88
96
|
|
89
97
|
if @db_role.nil?
|
90
|
-
|
98
|
+
%{#{sql_prefix}#{bin} #{user}/#{password}@#{host}:#{port}/#{@service}#{sql_postfix}}
|
91
99
|
elsif @su_user.nil?
|
92
|
-
|
100
|
+
%{#{sql_prefix}#{bin} #{user}/#{password}@#{host}:#{port}/#{@service} as #{@db_role}#{sql_postfix}}
|
93
101
|
else
|
94
|
-
|
102
|
+
# oracle_query_string is echoed to be able to extract the query output clearly
|
103
|
+
# su - su_user in certain versions of oracle returns a message
|
104
|
+
# Example of msg with query output: The Oracle base remains unchanged with value /oracle\n\nVALUE\n3\n
|
105
|
+
%{su - #{@su_user} -c "echo 'oracle_query_string'; env ORACLE_SID=#{@service} #{@bin} / as #{@db_role}#{sql_postfix}"}
|
95
106
|
end
|
96
107
|
end
|
97
108
|
|
@@ -101,9 +112,15 @@ module Inspec::Resources
|
|
101
112
|
end
|
102
113
|
|
103
114
|
def parse_csv_result(stdout)
|
104
|
-
output = stdout.
|
115
|
+
output = stdout.split("oracle_query_string")[-1]
|
116
|
+
# comma_query_sub replaces the csv delimiter "," in the output.
|
117
|
+
# Handles CSV parsing of data like this (DROP,3) etc
|
118
|
+
output = output.sub(/\r/, "").strip.gsub(",", "comma_query_sub")
|
105
119
|
converter = ->(header) { header.downcase }
|
106
|
-
CSV.parse(output, headers: true, header_converters: converter).map
|
120
|
+
CSV.parse(output, headers: true, header_converters: converter).map do |row|
|
121
|
+
revised_row = row.entries.flatten.map { |entry| entry.gsub("comma_query_sub", ",") }
|
122
|
+
Hashie::Mash.new([revised_row].to_h)
|
123
|
+
end
|
107
124
|
end
|
108
125
|
end
|
109
126
|
end
|
@@ -204,7 +204,9 @@ module Inspec::Resources
|
|
204
204
|
alias group groupname
|
205
205
|
|
206
206
|
def groups
|
207
|
-
|
207
|
+
unless identity.nil?
|
208
|
+
inspec.os.windows? ? UserGroups.new(identity[:groups]) : identity[:groups]
|
209
|
+
end
|
208
210
|
end
|
209
211
|
|
210
212
|
def home
|
@@ -314,6 +316,18 @@ module Inspec::Resources
|
|
314
316
|
end
|
315
317
|
end
|
316
318
|
|
319
|
+
# Class defined to compare for groups without case-sensitivity
|
320
|
+
class UserGroups < Array
|
321
|
+
def initialize(user_groups)
|
322
|
+
@user_groups = user_groups
|
323
|
+
super
|
324
|
+
end
|
325
|
+
|
326
|
+
def include?(group)
|
327
|
+
!(@user_groups.select { |user_group| user_group.casecmp?(group) }.empty?)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
317
331
|
# This is an abstract class that every user provoider has to implement.
|
318
332
|
# A user provider implements a system abstracts and helps the InSpec resource
|
319
333
|
# hand-over system specific behavior to those providers
|
@@ -622,7 +636,7 @@ module Inspec::Resources
|
|
622
636
|
name, _domain = parse_windows_account(username)
|
623
637
|
return if collect_user_details.nil?
|
624
638
|
|
625
|
-
res = collect_user_details.select { |user| user[:username]
|
639
|
+
res = collect_user_details.select { |user| user[:username].casecmp? name }
|
626
640
|
res[0] unless res.empty?
|
627
641
|
end
|
628
642
|
|
@@ -77,7 +77,7 @@ module Inspec::Resources
|
|
77
77
|
|
78
78
|
def load_firewall_profile(profile_name)
|
79
79
|
<<-EOH
|
80
|
-
|
80
|
+
Get-TypeData -TypeName System.Array | Remove-TypeData # workaround for PS bug here: https://bit.ly/2SRMQ8M
|
81
81
|
$profile = Get-NetFirewallProfile -Name "#{profile_name}"
|
82
82
|
$count = @($profile | Get-NetFirewallRule).Count
|
83
83
|
([PSCustomObject]@{
|
data/lib/inspec/resources.rb
CHANGED
@@ -37,6 +37,9 @@ require "inspec/resources/chocolatey_package"
|
|
37
37
|
require "inspec/resources/command"
|
38
38
|
require "inspec/resources/cran"
|
39
39
|
require "inspec/resources/cpan"
|
40
|
+
require "inspec/resources/cassandradb_session"
|
41
|
+
require "inspec/resources/cassandradb_conf"
|
42
|
+
require "inspec/resources/cassandra"
|
40
43
|
require "inspec/resources/crontab"
|
41
44
|
require "inspec/resources/dh_params"
|
42
45
|
require "inspec/resources/directory"
|
data/lib/inspec/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.49.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef InSpec Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-telemetry
|
@@ -505,6 +505,9 @@ files:
|
|
505
505
|
- lib/inspec/resources/bond.rb
|
506
506
|
- lib/inspec/resources/bridge.rb
|
507
507
|
- lib/inspec/resources/bsd_service.rb
|
508
|
+
- lib/inspec/resources/cassandra.rb
|
509
|
+
- lib/inspec/resources/cassandradb_conf.rb
|
510
|
+
- lib/inspec/resources/cassandradb_session.rb
|
508
511
|
- lib/inspec/resources/chocolatey_package.rb
|
509
512
|
- lib/inspec/resources/chrony_conf.rb
|
510
513
|
- lib/inspec/resources/command.rb
|