inspec-core 4.41.20 → 4.46.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26a893a79810f4d3e7aeb90032bd625636c045c8edc11274dddef456d504d278
4
- data.tar.gz: 05c34cf8764889bc585a0175cfd7d7c63ef54a4c45c30d182f599de1b3ef8a56
3
+ metadata.gz: 1cc013914b6503c547eeb5fbba13ce8398cf039236b82a0422339a8b7d178649
4
+ data.tar.gz: bb763eb39cb82fa264417d15147769d9d4b3fe1dff34ac40351712a35c6dbcb3
5
5
  SHA512:
6
- metadata.gz: 6d04b25d7423b4fec6be048b8f131bfc28e90266a631829270930b8aa96a520b220c19a0d8fe463689441f67cb8d567d6163df7f56fcc27786ef72f25508dbfc
7
- data.tar.gz: f798eee0dafda728d169d34ac8a73fef9803f3a70b1b1342d395d3954420644cef3fedcc202c1dc30204bdf1b2098741831af0200b1b3758c03511f38874e9ca
6
+ metadata.gz: 492c4bbde3afe3c8be2d7640bb5e6a04f973a762aa2b541231dc61a3862d2d4d3248a49ff9b149ca66fa07eba83e1cd61260185a61fb073ba6a3cc9b542ac04f
7
+ data.tar.gz: 89b55b1c8d8da24e1266bf6e19f688d284b88b18ec36c97f3f088c6f0422ac6ae6b0ddcab867bcb174ae789fc8e5bb334ed40cfd49adb26c7c3eb401c3164123
@@ -4,7 +4,7 @@
4
4
  "groups": {
5
5
  "attrs_value_replaces_default": {
6
6
  "action": "warn",
7
- "prefix": "The 'default' option for attributes is being replaced by 'value' - please use it instead."
7
+ "prefix": "The 'default' option for inputs is being replaced by 'value' - please use it instead."
8
8
  },
9
9
  "attrs_dsl": {
10
10
  "action": "ignore",
data/lib/inspec/cli.rb CHANGED
@@ -93,7 +93,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
93
93
  end
94
94
 
95
95
  desc "check PATH", "verify all tests at the specified PATH"
96
- option :format, type: :string
96
+ option :format, type: :string,
97
+ desc: "The output format to use doc (default), json. If valid format is not provided then it will use the default."
97
98
  profile_options
98
99
  def check(path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
99
100
  o = config
@@ -18,6 +18,7 @@ module Inspec
18
18
  attr_accessor :skip_file
19
19
  attr_accessor :profile_context
20
20
  attr_accessor :resources_dsl
21
+ attr_accessor :conf
21
22
 
22
23
  def initialize(profile_context, resources_dsl, backend, conf, dependencies, require_loader, skip_only_if_eval)
23
24
  @profile_context = profile_context
@@ -189,29 +190,24 @@ module Inspec
189
190
  @skip_file = true
190
191
  end
191
192
 
192
- private
193
-
194
- def block_location(block, alternate_caller)
195
- if block.nil?
196
- alternate_caller[/^(.+:\d+):in .+$/, 1] || "unknown"
197
- else
198
- path, line = block.source_location
199
- "#{File.basename(path)}:#{line}"
193
+ # Check if the given control exist in the --tags option
194
+ def tag_exist_in_control_tags?(tag_ids)
195
+ tag_option_matches_with_list = false
196
+ if !tag_ids.empty? && !tag_ids.nil? && profile_tag_config_exist?
197
+ tag_option_matches_with_list = !(tag_ids & @conf["profile"].include_tags_list).empty?
198
+ unless tag_option_matches_with_list
199
+ @conf["profile"].include_tags_list.any? do |inclusion|
200
+ # Try to see if the inclusion is a regex, and if it matches
201
+ if inclusion.is_a?(Regexp)
202
+ tag_ids.each do |id|
203
+ tag_option_matches_with_list = (inclusion =~ id)
204
+ break if tag_option_matches_with_list
205
+ end
206
+ end
207
+ end
208
+ end
200
209
  end
201
- end
202
-
203
- # Returns true if configuration hash is not empty and it contains the list of controls is not empty
204
- def profile_config_exist?
205
- !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_controls_list.empty?
206
- end
207
-
208
- def profile_tag_config_exist?
209
- !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_tags_list.empty?
210
- end
211
-
212
- # Returns true if configuration hash is empty or configuration hash does not have the list of controls that needs to be included
213
- def controls_list_empty?
214
- !@conf.empty? && @conf.key?("profile") && @conf["profile"].include_controls_list.empty? || @conf.empty?
210
+ tag_option_matches_with_list
215
211
  end
216
212
 
217
213
  def tags_list_empty?
@@ -230,24 +226,29 @@ module Inspec
230
226
  id_exist_in_list
231
227
  end
232
228
 
233
- # Check if the given control exist in the --tags option
234
- def tag_exist_in_control_tags?(tag_ids)
235
- tag_option_matches_with_list = false
236
- if !tag_ids.empty? && !tag_ids.nil? && profile_tag_config_exist?
237
- tag_option_matches_with_list = !(tag_ids & @conf["profile"].include_tags_list).empty?
238
- unless tag_option_matches_with_list
239
- @conf["profile"].include_tags_list.any? do |inclusion|
240
- # Try to see if the inclusion is a regex, and if it matches
241
- if inclusion.is_a?(Regexp)
242
- tag_ids.each do |id|
243
- tag_option_matches_with_list = (inclusion =~ id)
244
- break if tag_option_matches_with_list
245
- end
246
- end
247
- end
248
- end
229
+ # Returns true if configuration hash is empty or configuration hash does not have the list of controls that needs to be included
230
+ def controls_list_empty?
231
+ !@conf.empty? && @conf.key?("profile") && @conf["profile"].include_controls_list.empty? || @conf.empty?
232
+ end
233
+
234
+ private
235
+
236
+ def block_location(block, alternate_caller)
237
+ if block.nil?
238
+ alternate_caller[/^(.+:\d+):in .+$/, 1] || "unknown"
239
+ else
240
+ path, line = block.source_location
241
+ "#{File.basename(path)}:#{line}"
249
242
  end
250
- tag_option_matches_with_list
243
+ end
244
+
245
+ # Returns true if configuration hash is not empty and it contains the list of controls is not empty
246
+ def profile_config_exist?
247
+ !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_controls_list.empty?
248
+ end
249
+
250
+ def profile_tag_config_exist?
251
+ !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_tags_list.empty?
251
252
  end
252
253
  end
253
254
  end
data/lib/inspec/dsl.rb CHANGED
@@ -93,23 +93,38 @@ module Inspec::DSL
93
93
  context = dep_entry.profile.runner_context
94
94
  # if we don't want all the rules, then just make 1 pass to get all rule_IDs
95
95
  # that we want to keep from the original
96
- filter_included_controls(context, dep_entry.profile, &block) unless opts[:include_all]
96
+ if !opts[:include_all] || !(opts[:conf]["profile"].include_tags_list.empty?) || !opts[:conf]["profile"].include_controls_list.empty?
97
+ filter_included_controls(context, dep_entry.profile, opts, &block)
98
+ end
97
99
  # interpret the block and skip/modify as required
98
100
  context.load(block) if block_given?
99
101
  bind_context.add_subcontext(context)
100
102
  end
101
103
 
102
- def self.filter_included_controls(context, profile, &block)
104
+ def self.filter_included_controls(context, profile, opts, &block)
103
105
  mock = Inspec::Backend.create(Inspec::Config.mock)
104
106
  include_ctx = Inspec::ProfileContext.for_profile(profile, mock)
105
107
  include_ctx.load(block) if block_given?
108
+ include_ctx.control_eval_context.conf = opts[:conf]
109
+ control_eval_ctx = include_ctx.control_eval_context
106
110
  # remove all rules that were not registered
107
111
  context.all_rules.each do |r|
108
112
  id = Inspec::Rule.rule_id(r)
109
113
  fid = Inspec::Rule.profile_id(r) + "/" + id
110
- unless include_ctx.rules[id] || include_ctx.rules[fid]
114
+ if !opts[:include_all] && !(include_ctx.rules[id] || include_ctx.rules[fid])
111
115
  context.remove_rule(fid)
112
116
  end
117
+
118
+ unless control_eval_ctx.controls_list_empty?
119
+ # filter the dependent profile controls which are not in the --controls options list
120
+ context.remove_rule(fid) unless control_eval_ctx.control_exist_in_controls_list?(id)
121
+ end
122
+
123
+ unless control_eval_ctx.tags_list_empty?
124
+ # filter included controls using --tags
125
+ tag_ids = control_eval_ctx.control_tags(r)
126
+ context.remove_rule(fid) unless control_eval_ctx.tag_exist_in_control_tags?(tag_ids)
127
+ end
113
128
  end
114
129
  end
115
130
  end
@@ -0,0 +1,55 @@
1
+ # chrony_conf
2
+
3
+ require "inspec/utils/simpleconfig"
4
+ require "inspec/utils/file_reader"
5
+
6
+ module Inspec::Resources
7
+ class ChronyConf < Inspec.resource(1)
8
+ name "chrony_conf"
9
+ supports platform: "unix"
10
+ desc "Use the chrony_conf InSpec audit resource to test the synchronization settings defined in the chrony.conf file. This file is typically located at /etc/chrony.conf."
11
+ example <<~EXAMPLE
12
+ describe chrony_conf do
13
+ its('server') { should_not cmp nil }
14
+ its('restrict') { should include '-4 default kod notrap nomodify nopeer noquery' }
15
+ its('pool') { should include 'pool.ntp.org iburst' }
16
+ its('driftfile') { should cmp '/var/lib/ntp/drift' }
17
+ its('allow') { should cmp nil }
18
+ its('keyfile') { should cmp '/etc/chrony.keys' }
19
+ end
20
+ EXAMPLE
21
+
22
+ include FileReader
23
+
24
+ def initialize(path = nil)
25
+ @conf_path = path || "/etc/chrony.conf"
26
+ @content = read_file_content(@conf_path)
27
+ end
28
+
29
+ def method_missing(name)
30
+ param = read_params[name.to_s]
31
+ # extract first value if we have only one value in array
32
+ return param[0] if param.is_a?(Array) && (param.length == 1)
33
+
34
+ param
35
+ end
36
+
37
+ def to_s
38
+ "chrony.conf"
39
+ end
40
+
41
+ private
42
+
43
+ def read_params
44
+ return @params if defined?(@params)
45
+
46
+ # parse the file
47
+ conf = SimpleConfig.new(
48
+ @content,
49
+ assignment_regex: /^\s*(\S+)\s+(.*)\s*$/,
50
+ multiple_values: true
51
+ )
52
+ @params = conf.params
53
+ end
54
+ end
55
+ end
@@ -11,14 +11,28 @@ module Inspec::Resources
11
11
  describe csv('example.csv') do
12
12
  its('name') { should eq(['John', 'Alice']) }
13
13
  end
14
+
15
+ describe csv('example.csv', false).params do
16
+ its[[0]] { should eq (['name', 'col1', 'col2']) }
17
+ emd
14
18
  EXAMPLE
15
19
 
20
+ def initialize(path, headers = true)
21
+ @headers = headers
22
+ super(path)
23
+ end
24
+
16
25
  # override the parse method from JsonConfig
17
26
  # Assuming a header row of name,col1,col2, it will output an array of hashes like so:
18
27
  # [
19
28
  # { 'name' => 'row1', 'col1' => 'value1', 'col2' => 'value2' },
20
29
  # { 'name' => 'row2', 'col1' => 'value3', 'col2' => 'value4' }
21
30
  # ]
31
+ # When headers is set to false it will return data as array of array
32
+ # [
33
+ # ['name', col1', 'col2'],
34
+ # ['row2', 'value3', 'value4']
35
+ # ]
22
36
  def parse(content)
23
37
  require "csv" unless defined?(CSV)
24
38
 
@@ -28,10 +42,14 @@ module Inspec::Resources
28
42
  end
29
43
 
30
44
  # implicit conversion of values
31
- csv = CSV.new(content, headers: true, converters: %i{all blank_to_nil})
45
+ csv = CSV.new(content, headers: @headers, converters: %i{all blank_to_nil})
32
46
 
33
47
  # convert to hash
34
- csv.to_a.map(&:to_hash)
48
+ if @headers
49
+ csv.to_a.map(&:to_hash)
50
+ else
51
+ csv.to_a
52
+ end
35
53
  rescue => e
36
54
  raise Inspec::Exceptions::ResourceFailed, "Unable to parse CSV: #{e.message}"
37
55
  end
@@ -42,7 +60,12 @@ module Inspec::Resources
42
60
  # #value method from JsonConfig (which uses ObjectTraverser.extract_value)
43
61
  # doesn't make sense here.
44
62
  def value(key)
45
- @params.map { |x| x[key.first.to_s] }.compact
63
+ if @headers
64
+ @params.map { |x| x[key.first.to_s] }.compact
65
+ else
66
+ # when headers is set to false send the array as it is.
67
+ @params
68
+ end
46
69
  end
47
70
 
48
71
  private
@@ -0,0 +1,57 @@
1
+ module Inspec::Resources
2
+ class Ibmdb2Conf < Inspec.resource(1)
3
+ name "ibmdb2_conf"
4
+
5
+ supports platform: "unix"
6
+ supports platform: "windows"
7
+
8
+ desc "Use the ibmdb2_conf InSpec audit resource to test the configuration values of IBM Db2 database."
9
+ example <<~EXAMPLE
10
+ describe ibmdb2_conf(db2_executable_file_path: "path_to_db2_binary", db_instance: "db2inst1") do
11
+ its("output") { should_not be_empty }
12
+ its("output") { should include("Audit buffer size (4KB) (AUDIT_BUF_SZ) = 0")}
13
+ end
14
+ EXAMPLE
15
+
16
+ attr_reader :output
17
+
18
+ def initialize(opts = {})
19
+ if inspec.os.platform?("unix")
20
+ @db2_executable_file_path = opts[:db2_executable_file_path]
21
+ @db_instance = opts[:db_instance]
22
+ raise Inspec::Exceptions::ResourceFailed, "Can't connect to IBM DB2 without db2_executable_file_path, db_instance options provided." if @db2_executable_file_path.nil? || @db_instance.nil?
23
+ end
24
+ @output = run_command
25
+ end
26
+
27
+ def to_s
28
+ "IBM Db2 Conf"
29
+ end
30
+
31
+ private
32
+
33
+ def run_command
34
+ # attach to the db2 instance and get the configuration
35
+ if inspec.os.platform?("unix")
36
+ cmd = inspec.command("#{@db2_executable_file_path} attach to #{@db_instance}\; #{@db2_executable_file_path} get database manager configuration")
37
+ out = cmd.stdout + "\n" + cmd.stderr
38
+
39
+ # check if following specific error is there. Sourcing the db2profile to resolve the error.
40
+ if cmd.exit_status != 0 && out =~ /SQL10007N Message "-1390" could not be retrieved. Reason code: "3"/
41
+ cmd = inspec.command(". ~/sqllib/db2profile\; #{@db2_executable_file_path} attach to #{@db_instance}\; #{@db2_executable_file_path} get database manager configuration")
42
+ out = cmd.stdout + "\n" + cmd.stderr
43
+ end
44
+ elsif inspec.os.platform?("windows")
45
+ # set-item command set the powershell to run the db2 commands.
46
+ cmd = inspec.command("set-item -path env:DB2CLP -value \"**$$**\"\; db2 get database manager configuration")
47
+ out = cmd.stdout + "\n" + cmd.stderr
48
+ end
49
+
50
+ if cmd.exit_status != 0 || out =~ /Can't connect to IBM Db2 server/ || out.downcase =~ /^error:.*/
51
+ raise Inspec::Exceptions::ResourceFailed, "IBM Db2 query with error: #{out}"
52
+ else
53
+ cmd.stdout.gsub(/\n|\r/, ",").split(",").reject { |n| n.nil? || n.empty? }.map { |n| n.strip.gsub!(/\s+/, " ") }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,69 @@
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 Ibmdb2Session < Inspec.resource(1)
16
+ name "ibmdb2_session"
17
+
18
+ supports platform: "unix"
19
+ supports platform: "windows"
20
+
21
+ desc "Use the ibmdb2_session InSpec audit resource to test SQL commands run against a IBM Db2 database."
22
+ example <<~EXAMPLE
23
+ describe ibmdb2_session(db2_executable_file_path: "path_to_db2_binary", db_instance: "db2inst1", db_name: "sample").query('list database directory') do
24
+ its('output') { should_not match(/sample/) }
25
+ end
26
+ EXAMPLE
27
+
28
+ def initialize(opts = {})
29
+ @db_name = opts[:db_name]
30
+ if inspec.os.platform?("unix")
31
+ @db2_executable_file_path = opts[:db2_executable_file_path]
32
+ @db_instance = opts[:db_instance]
33
+ raise Inspec::Exceptions::ResourceFailed, "Can't run IBM DB2 queries without db2_executable_file_path, db_instance, db_name options provided." if @db2_executable_file_path.nil? || @db_instance.nil? || @db_name.nil?
34
+ elsif inspec.os.platform?("windows")
35
+ raise Inspec::Exceptions::ResourceFailed, "Can't run IBM DB2 queries without db_name option provided." if @db_name.nil?
36
+ end
37
+ end
38
+
39
+ def query(q)
40
+ raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
41
+
42
+ if inspec.os.platform?("unix")
43
+ # connect to the db and query on the database
44
+ cmd = inspec.command("#{@db2_executable_file_path} attach to #{@db_instance}\; #{@db2_executable_file_path} connect to #{@db_name}\; #{@db2_executable_file_path} #{q}\;")
45
+ out = cmd.stdout + "\n" + cmd.stderr
46
+
47
+ # check if following specific error is there. Sourcing the db2profile to resolve the error.
48
+ if cmd.exit_status != 0 && out =~ /SQL10007N Message "-1390" could not be retrieved. Reason code: "3"/
49
+ cmd = inspec.command(". ~/sqllib/db2profile\; #{@db2_executable_file_path} attach to #{@db_instance}\; #{@db2_executable_file_path} connect to #{@db_name}\; #{@db2_executable_file_path} #{q}\;")
50
+ out = cmd.stdout + "\n" + cmd.stderr
51
+ end
52
+ elsif inspec.os.platform?("windows")
53
+ # set-item command set the powershell to run the db2 commands.
54
+ cmd = inspec.command("set-item -path env:DB2CLP -value \"**$$**\"\; db2 connect to #{@db_name}\; db2 #{q}\;")
55
+ out = cmd.stdout + "\n" + cmd.stderr
56
+ end
57
+
58
+ if cmd.exit_status != 0 || out =~ /Can't connect to IBM Db2 / || out.downcase =~ /^error:.*/
59
+ raise Inspec::Exceptions::ResourceFailed, "IBM Db2 connection error: #{out}"
60
+ else
61
+ Lines.new(cmd.stdout.strip, "IBM Db2 Query: #{q}")
62
+ end
63
+ end
64
+
65
+ def to_s
66
+ "IBM Db2 Session"
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,48 @@
1
+ require "inspec/resources/mssql_session"
2
+
3
+ module Inspec::Resources
4
+ class MssqlSysConf < Inspec.resource(1)
5
+ name "mssql_sys_conf"
6
+ supports platform: "windows"
7
+ supports platform: "debian"
8
+ supports platform: "redhat"
9
+ supports platform: "suse"
10
+
11
+ desc "Use the mssql_sys_conf InSpec audit resource to test the database system configurations for Mssql DB"
12
+ example <<~EXAMPLE
13
+ describe mssql_sys_conf("clr_enabled", user: 'USER', password: 'PASSWORD') do
14
+ its("value_in_use") { should cmp "0" }
15
+ its("value_configured") { should cmp "0" }
16
+ end
17
+ EXAMPLE
18
+
19
+ attr_reader :mssql_session, :sql_query
20
+
21
+ def initialize(conf_param_name, opts = {})
22
+ opts[:username] ||= "SA"
23
+ @mssql_session = inspec.mssql_session(opts)
24
+ setting = conf_param_name.to_s.gsub("_", " ").split.map(&:capitalize).join(" ")
25
+ determine_system_configurations(setting)
26
+ end
27
+
28
+ def value_in_use
29
+ sql_query.row(0).column("value_in_use").value
30
+ end
31
+
32
+ def value_configured
33
+ sql_query.row(0).column("value_configured").value
34
+ end
35
+
36
+ def to_s
37
+ "MsSql DB Configuration"
38
+ end
39
+
40
+ private
41
+
42
+ def determine_system_configurations(setting)
43
+ @sql_query = mssql_session.query("SELECT name, CAST(value as int) as value_configured, CAST(value_in_use as int) as value_in_use FROM sys.configurations WHERE name = '#{setting}'")
44
+ rescue => e
45
+ raise Inspec::Exceptions::ResourceFailed, "Errors fetching database system configurations for Mssql database: #{e}"
46
+ end
47
+ end
48
+ end
@@ -6,12 +6,15 @@ module Inspec::Resources
6
6
  supports platform: "unix"
7
7
  supports platform: "windows"
8
8
 
9
- attr_reader :result
10
9
  def initialize(content)
11
10
  @content = content
12
11
  super({ content: @content })
13
12
  end
14
13
 
14
+ def result
15
+ @content == {} || @content["result"].empty? ? nil : @content
16
+ end
17
+
15
18
  private
16
19
 
17
20
  def parse(content)
@@ -0,0 +1,66 @@
1
+ require "inspec/resources/powershell"
2
+
3
+ module Inspec::Resources
4
+ class Oracle < Inspec.resource(1)
5
+ name "oracle"
6
+ supports platform: "unix"
7
+ supports platform: "windows"
8
+
9
+ desc "The 'oracle' resource is a helper for the 'oracledb_listener_conf'"
10
+
11
+ attr_reader :conf_path
12
+
13
+ def initialize
14
+ case inspec.os[:family]
15
+ when "debian", "redhat", "linux", "suse"
16
+ determine_conf_dir_and_path_in_linux
17
+ when "windows"
18
+ determine_conf_dir_and_path_in_windows
19
+ end
20
+ end
21
+
22
+ def to_s
23
+ "OracleDB"
24
+ end
25
+
26
+ private
27
+
28
+ def determine_conf_dir_and_path_in_linux
29
+ oracle_home = inspec.os_env("ORACLE_HOME").content
30
+
31
+ if oracle_home.nil? || oracle_home.empty?
32
+ warn "$ORACLE_HOME env value not set in the system"
33
+ nil
34
+ else
35
+ conf_path = "#{oracle_home}/network/admin/listener.ora"
36
+ if !inspec.file(conf_path).exist?
37
+ warn "No oracle listener settings found in $ORACLE_HOME/network/admin directory"
38
+ nil
39
+ else
40
+ @conf_path = conf_path
41
+ end
42
+ end
43
+ rescue => e
44
+ fail_resource "Errors reading listener settings: #{e}"
45
+ end
46
+
47
+ def determine_conf_dir_and_path_in_windows
48
+ oracle_home = inspec.os_env("ORACLE_HOME").content
49
+
50
+ if oracle_home.nil? || oracle_home.empty?
51
+ warn "ORACLE_HOME env value not set in the system"
52
+ nil
53
+ else
54
+ conf_path = "#{oracle_home}\\network\\admin\\listener.ora"
55
+ if !inspec.file(conf_path).exist?
56
+ warn "No oracle listener settings found in ORACLE_HOME\\network\\admin directory"
57
+ nil
58
+ else
59
+ @conf_path = conf_path
60
+ end
61
+ end
62
+ rescue => e
63
+ fail_resource "Errors reading listener settings: #{e}"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,40 @@
1
+ require "inspec/resources/oracledb_session"
2
+
3
+ module Inspec::Resources
4
+ class OracledbConf < Inspec.resource(1)
5
+ name "oracledb_conf"
6
+ supports platform: "unix"
7
+ supports platform: "windows"
8
+ desc "Use the oracledb_conf InSpec audit resource to test the database settings for Oracle DB"
9
+ example <<~EXAMPLE
10
+ describe oracledb_conf(user: 'USER', password: 'PASSWORD') do
11
+ its("audit_sys_operations") { should cmp "true" }
12
+ its("sql92_security") { should cmp "true" }
13
+ end
14
+ EXAMPLE
15
+
16
+ attr_reader :oracledb_session
17
+
18
+ def initialize(opts = {})
19
+ @oracledb_session = inspec.oracledb_session(opts)
20
+ end
21
+
22
+ def method_missing(name)
23
+ setting = name.to_s.upcase
24
+ determine_database_setting(setting)
25
+ end
26
+
27
+ def to_s
28
+ "Oracle DB Configuration"
29
+ end
30
+
31
+ private
32
+
33
+ def determine_database_setting(setting)
34
+ sql_query = oracledb_session.query("SELECT UPPER(VALUE) AS UPPER_VALUE FROM V$SYSTEM_PARAMETER WHERE UPPER(NAME) = '#{setting}'")
35
+ sql_query.row(0).column("UPPER_VALUE").value
36
+ rescue => e
37
+ raise Inspec::Exceptions::ResourceFailed, "Errors fetching database settings for Oracle database: #{e}"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,123 @@
1
+ require "inspec/utils/object_traversal"
2
+ require "inspec/utils/simpleconfig"
3
+ require "inspec/utils/find_files"
4
+ require "inspec/utils/file_reader"
5
+ require "inspec/resources/oracle"
6
+
7
+ module Inspec::Resources
8
+ class OracledbListenerConf < Inspec.resource(1)
9
+ name "oracledb_listener_conf"
10
+ supports platform: "unix"
11
+ supports platform: "windows"
12
+ desc "Use the oracledb_listener_conf InSpec audit resource to test the listener settings for Oracle DB"
13
+ example <<~EXAMPLE
14
+ describe oracledb_listener_conf do
15
+ its('DEFAULT_SERVICE_LISTENER') { should eq 'XE' }
16
+ end
17
+ EXAMPLE
18
+
19
+ include FindFiles
20
+ include FileReader
21
+ include ObjectTraverser
22
+
23
+ def initialize(conf_path = nil)
24
+ oracle = nil
25
+ if conf_path.nil?
26
+ oracle = inspec.oracle
27
+ @conf_path = oracle.conf_path
28
+ else
29
+ @conf_path = conf_path
30
+ end
31
+
32
+ if oracle && oracle.resource_failed?
33
+ raise oracle.resource_exception_message
34
+ elsif @conf_path.nil?
35
+ return skip_resource "Oracle Listener conf path is not set"
36
+ end
37
+
38
+ @conf_dir = File.expand_path(File.dirname(@conf_path))
39
+ @files_contents = {}
40
+ @content = nil
41
+ @params = nil
42
+ read_content
43
+ end
44
+
45
+ def content
46
+ @content ||= read_content
47
+ end
48
+
49
+ def params(*opts)
50
+ @params || read_content
51
+ res = @params
52
+ opts.each do |opt|
53
+ res = res[opt] unless res.nil?
54
+ end
55
+ res
56
+ end
57
+
58
+ def value(key)
59
+ extract_value(key, @params)
60
+ end
61
+
62
+ def method_missing(*keys)
63
+ keys.shift if keys.is_a?(Array) && keys[0] == :[]
64
+ param = value(keys)
65
+ return nil if param.nil?
66
+ # extract first value if we have only one value in array
67
+ return param[0] if param.length == 1
68
+
69
+ param
70
+ end
71
+
72
+ def to_s
73
+ "Oracle Listener Configuration"
74
+ end
75
+
76
+ private
77
+
78
+ def read_content
79
+ @content = ""
80
+ @params = {}
81
+
82
+ to_read = [@conf_path]
83
+ until to_read.empty?
84
+ base_dir = File.dirname(to_read[0])
85
+ raw_conf = read_file(to_read[0])
86
+ @content += raw_conf
87
+
88
+ opts = {
89
+ assignment_regex: /^\s*([^=]*?)\s*=\s*[']?\s*(.*?)\s*[']?\s*$/,
90
+ }
91
+ params = SimpleConfig.new(raw_conf, opts).params
92
+ @params.merge!(params)
93
+
94
+ to_read = to_read.drop(1)
95
+ # see if there is more config files to include
96
+
97
+ to_read += include_files(params, base_dir).find_all do |fp|
98
+ not @files_contents.key? fp
99
+ end
100
+ end
101
+ @content
102
+ end
103
+
104
+ def include_files(params, base_dir)
105
+ include_files = Array(params["include"]) || []
106
+ include_files += Array(params["include_if_exists"]) || []
107
+ include_files.map! do |f|
108
+ Pathname.new(f).absolute? ? f : File.join(base_dir, f)
109
+ end
110
+
111
+ dirs = Array(params["include_dir"]) || []
112
+ dirs.each do |dir|
113
+ dir = File.join(base_dir, dir) if dir[0] != "/"
114
+ include_files += find_files(dir, depth: 1, type: "file")
115
+ end
116
+ include_files
117
+ end
118
+
119
+ def read_file(path)
120
+ @files_contents[path] ||= read_file_content(path)
121
+ end
122
+ end
123
+ end
@@ -40,11 +40,12 @@ module Inspec::Resources
40
40
  end
41
41
  EXAMPLE
42
42
 
43
- def initialize(user, pass, host = nil, port = nil)
43
+ def initialize(user, pass, host = nil, port = nil, socket_path = nil)
44
44
  @user = user || "postgres"
45
45
  @pass = pass
46
46
  @host = host || "localhost"
47
47
  @port = port || 5432
48
+ @socket_path = socket_path
48
49
  raise Inspec::Exceptions::ResourceFailed, "Can't run PostgreSQL SQL checks without authentication." if @user.nil? || @pass.nil?
49
50
  end
50
51
 
@@ -69,10 +70,20 @@ module Inspec::Resources
69
70
 
70
71
  def create_psql_cmd(query, db = [])
71
72
  dbs = db.map { |x| "#{x}" }.join(" ")
72
- if inspec.os.windows?
73
- "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
73
+
74
+ if @socket_path && !inspec.os.windows?
75
+ # Socket path and empty host in the connection string establishes socket connection
76
+ # Socket connection only enabled for non-windows platforms
77
+ # Windows does not support unix domain sockets
78
+ "psql -d postgresql://#{@user}:#{@pass}@/#{dbs}?host=#{@socket_path} -A -t -w -c #{escaped_query(query)}"
74
79
  else
75
- "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
80
+ # Host in connection string establishes tcp/ip connection
81
+ if inspec.os.windows?
82
+ warn "Socket based connection not supported in windows, connecting using host" if @socket_path
83
+ "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
84
+ else
85
+ "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
86
+ end
76
87
  end
77
88
  end
78
89
  end
@@ -141,7 +141,7 @@ module Inspec::Resources
141
141
  elsif version > 0
142
142
  SysV.new(inspec, service_ctl || "/usr/sbin/service")
143
143
  end
144
- when "redhat", "fedora", "centos", "oracle", "cloudlinux", "scientific"
144
+ when "redhat", "fedora", "centos", "oracle", "cloudlinux", "scientific", "rocky", "almalinux"
145
145
  version = os[:release].to_i
146
146
 
147
147
  systemd = ((platform != "fedora" && version >= 7) ||
@@ -0,0 +1,37 @@
1
+ require "inspec/resources/sybase_session"
2
+
3
+ module Inspec::Resources
4
+ class SybaseConf < Inspec.resource(1)
5
+ name "sybase_conf"
6
+ supports platform: "unix"
7
+ # supports platform: "windows" # TODO
8
+ desc "Use the sybase_conf InSpec resource to test Sybase config settings"
9
+ example <<~EXAMPLE
10
+ describe sybase_conf("max memory", password: 'password', server: 'SYBASE') do
11
+ its("run_value") { should cmp 180224 }
12
+ end
13
+ EXAMPLE
14
+
15
+ attr_reader :conf_param, :sql_query
16
+ def initialize(conf_param_name, opts = {})
17
+ @conf_param = conf_param_name
18
+ opts[:username] ||= "sa"
19
+ opts[:database] ||= "master"
20
+ sql_session = inspec.sybase_session(opts)
21
+ @sql_query = sql_session.query("sp_configure \"#{conf_param}\"")
22
+ end
23
+
24
+ def run_value
25
+ sql_query.row(0).column("Run Value").value
26
+ end
27
+
28
+ def config_value
29
+ sql_query.row(0).column("Config Value").value
30
+ end
31
+
32
+ def to_s
33
+ "Sybase Conf #{conf_param}"
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,111 @@
1
+ require "inspec/resources/command"
2
+ require "inspec/utils/database_helpers"
3
+ require "hashie/mash"
4
+ require "csv" unless defined?(CSV)
5
+ require "tempfile" unless defined?(Tempfile)
6
+
7
+ module Inspec::Resources
8
+ # STABILITY: Experimental
9
+ # This resource needs further testing and refinement
10
+ #
11
+ class SybaseSession < Inspec.resource(1)
12
+ name "sybase_session"
13
+ supports platform: "unix"
14
+ # supports platform: "windows" # TODO
15
+ desc "Use the sybase_session InSpec resource to test commands against an Sybase database"
16
+ example <<~EXAMPLE
17
+ sql = sybase_session(username: 'my_user', password: 'password', server: 'SYBASE', database: 'pubs2')
18
+ describe sql.query(\"SELECT * FROM authors\").row(0).column('au_lname') do
19
+ its('value') { should eq 'Smith' }
20
+ end
21
+ EXAMPLE
22
+
23
+ # TODO: allow to set -I interfaces file
24
+ # TODO: allow to customize -s column separator
25
+ attr_reader :bin, :col_sep, :database, :password, :server, :sybase_home, :username
26
+
27
+ def initialize(opts = {})
28
+ @username = opts[:username]
29
+ @password = opts[:password]
30
+ @database = opts[:database]
31
+ @server = opts[:server]
32
+ @sybase_home = opts[:sybase_home] || "/opt/sap"
33
+ @bin = opts[:bin] || "isql"
34
+ @col_sep = "|"
35
+
36
+ fail_resource "Can't run Sybase checks without authentication" unless username && password
37
+ fail_resource "You must provide a server name for the session" unless server
38
+ fail_resource "You must provide a database name for the session" unless database
39
+ fail_resource "Cannot find #{bin} CLI tool" unless inspec.command(bin).exist?
40
+ end
41
+
42
+ def query(sql)
43
+ # We must write the SQl to a temp file on the remote target
44
+ # try to get a temp path
45
+ sql_file_path = upload_sql_file(sql)
46
+
47
+ # isql reuires that we have a matching locale set, but does not support C.UTF-8. en_US.UTF-8 is the least evil.
48
+ command = "LANG=en_US.UTF-8 SYBASE=#{sybase_home} #{bin} -s\"#{col_sep}\" -w80000 -S #{server} -U #{username} -D #{database} -P \"#{password}\" < #{sql_file_path}"
49
+ isql_cmd = inspec.command(command)
50
+
51
+ # Check for isql errors
52
+ res = isql_cmd.exit_status
53
+ raise Inspec::Exceptions::ResourceFailed.new("isql exited with code #{res} and stderr '#{isql_cmd.stderr}', stdout '#{isql_cmd.stdout}'") unless res == 0
54
+ # isql is ill-behaved, and returns 0 on error
55
+ raise Inspec::Exceptions::ResourceFailed.new("isql exited with error '#{isql_cmd.stderr}', stdout '#{isql_cmd.stdout}'") unless isql_cmd.stderr == ""
56
+ # check stdout for error messages when stderr is empty "Msg 102, Level 15, State 181:\nServer 'SYBASE', Line 1:\nIncorrect syntax near '.'.\n"
57
+ raise Inspec::Exceptions::ResourceFailed.new("isql exited with error #{isql_cmd.stdout}") if isql_cmd.stdout.match?(/Msg\s\d+,\sLevel\s\d+,\sState\s\d+/)
58
+
59
+ # Clean up temporary file
60
+ rm_cmd = inspec.command("rm #{sql_file_path}")
61
+ res = rm_cmd.exit_status # TODO: handle
62
+ raise Inspec::Exceptions::ResourceFailed.new("Unable to delete temproary SQL input file at #{sql_file_path}: #{rm_cmd.stderr}") unless res == 0
63
+
64
+ DatabaseHelper::SQLQueryResult.new(isql_cmd, parse_csv_result(isql_cmd.stdout))
65
+ end
66
+
67
+ def to_s
68
+ "Sybase Session"
69
+ end
70
+
71
+ private
72
+
73
+ def parse_csv_result(stdout)
74
+ output = stdout.gsub(/\r/, "").strip
75
+ lines = output.lines
76
+ # Remove second row (all dashes) and last 2 rows (blank and summary lines)
77
+ trimmed_output = ([lines[0]] << lines.slice(2..-3)).join("")
78
+ header_converter = Proc.new do |header|
79
+ # This is here to suppress a warning from Hashie::Mash when it encounters a
80
+ # header column that ends up with the name "default", which happens when using the
81
+ # sybase_conf resource. It does mean that aly query whose output field includes the name
82
+ # Default (exactly) will get renamed to default_value, but that seems unlikely.
83
+ if header.match?(/^Default\s+$/)
84
+ "default_value"
85
+ else
86
+ header.downcase.strip
87
+ end
88
+ end
89
+ field_converter = ->(field) { field&.strip }
90
+ CSV.parse(trimmed_output, headers: true, header_converters: header_converter, converters: field_converter, col_sep: col_sep).map { |row| Hashie::Mash.new(row.to_h) }
91
+ end
92
+
93
+ def upload_sql_file(sql)
94
+ remote_temp_dir = "/tmp"
95
+ remote_file_path = nil
96
+ local_temp_file = Tempfile.new(["sybase", ".sql"])
97
+ begin
98
+ local_temp_file.write("#{sql}\n")
99
+ local_temp_file.write("go\n")
100
+ local_temp_file.flush
101
+ filename = File.basename(local_temp_file.path)
102
+ remote_file_path = "#{remote_temp_dir}/#{filename}"
103
+ inspec.backend.upload([local_temp_file.path], remote_temp_dir)
104
+ ensure
105
+ local_temp_file.close
106
+ local_temp_file.unlink
107
+ end
108
+ remote_file_path
109
+ end
110
+ end
111
+ end
@@ -58,6 +58,8 @@ require "inspec/resources/groups"
58
58
  require "inspec/resources/grub_conf"
59
59
  require "inspec/resources/host"
60
60
  require "inspec/resources/http"
61
+ require "inspec/resources/ibmdb2_conf"
62
+ require "inspec/resources/ibmdb2_session"
61
63
  require "inspec/resources/iis_app"
62
64
  require "inspec/resources/iis_app_pool"
63
65
  require "inspec/resources/iis_site"
@@ -76,6 +78,7 @@ require "inspec/resources/mongodb_conf"
76
78
  require "inspec/resources/mongodb_session"
77
79
  require "inspec/resources/mount"
78
80
  require "inspec/resources/mssql_session"
81
+ require "inspec/resources/mssql_sys_conf"
79
82
  require "inspec/resources/mysql"
80
83
  require "inspec/resources/mysql_conf"
81
84
  require "inspec/resources/mysql_session"
@@ -84,6 +87,9 @@ require "inspec/resources/nginx_conf"
84
87
  require "inspec/resources/npm"
85
88
  require "inspec/resources/ntp_conf"
86
89
  require "inspec/resources/oneget"
90
+ require "inspec/resources/oracle"
91
+ require "inspec/resources/oracledb_conf"
92
+ require "inspec/resources/oracledb_listener_conf"
87
93
  require "inspec/resources/opa_cli"
88
94
  require "inspec/resources/opa_api"
89
95
  require "inspec/resources/oracledb_session"
@@ -49,7 +49,6 @@ module Inspec
49
49
  end
50
50
 
51
51
  class Profile
52
- # Good candidate for keyword_init, but that is not in 2.4
53
52
  Dependency = Struct.new(
54
53
  :name, :path, :status, :status_message, :git, :url, :compliance, :supermarket, :branch, :tag, :commit, :version, :relative_path
55
54
  ) do
@@ -71,7 +70,6 @@ module Inspec
71
70
  end
72
71
  end
73
72
 
74
- # Good candidate for keyword_init, but that is not in 2.4
75
73
  Group = Struct.new(
76
74
  :title, :controls, :id
77
75
  ) do
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.41.20".freeze
2
+ VERSION = "4.46.13".freeze
3
3
  end
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.41.20
4
+ version: 4.46.13
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-09-01 00:00:00.000000000 Z
11
+ date: 2021-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-telemetry
@@ -506,6 +506,7 @@ files:
506
506
  - lib/inspec/resources/bridge.rb
507
507
  - lib/inspec/resources/bsd_service.rb
508
508
  - lib/inspec/resources/chocolatey_package.rb
509
+ - lib/inspec/resources/chrony_conf.rb
509
510
  - lib/inspec/resources/command.rb
510
511
  - lib/inspec/resources/cpan.rb
511
512
  - lib/inspec/resources/cran.rb
@@ -535,6 +536,8 @@ files:
535
536
  - lib/inspec/resources/grub_conf.rb
536
537
  - lib/inspec/resources/host.rb
537
538
  - lib/inspec/resources/http.rb
539
+ - lib/inspec/resources/ibmdb2_conf.rb
540
+ - lib/inspec/resources/ibmdb2_session.rb
538
541
  - lib/inspec/resources/iis_app.rb
539
542
  - lib/inspec/resources/iis_app_pool.rb
540
543
  - lib/inspec/resources/iis_site.rb
@@ -559,6 +562,7 @@ files:
559
562
  - lib/inspec/resources/mongodb_session.rb
560
563
  - lib/inspec/resources/mount.rb
561
564
  - lib/inspec/resources/mssql_session.rb
565
+ - lib/inspec/resources/mssql_sys_conf.rb
562
566
  - lib/inspec/resources/mysql.rb
563
567
  - lib/inspec/resources/mysql_conf.rb
564
568
  - lib/inspec/resources/mysql_session.rb
@@ -571,6 +575,9 @@ files:
571
575
  - lib/inspec/resources/opa.rb
572
576
  - lib/inspec/resources/opa_api.rb
573
577
  - lib/inspec/resources/opa_cli.rb
578
+ - lib/inspec/resources/oracle.rb
579
+ - lib/inspec/resources/oracledb_conf.rb
580
+ - lib/inspec/resources/oracledb_listener_conf.rb
574
581
  - lib/inspec/resources/oracledb_session.rb
575
582
  - lib/inspec/resources/os.rb
576
583
  - lib/inspec/resources/os_env.rb
@@ -604,6 +611,8 @@ files:
604
611
  - lib/inspec/resources/ssh_config.rb
605
612
  - lib/inspec/resources/sshd_config.rb
606
613
  - lib/inspec/resources/ssl.rb
614
+ - lib/inspec/resources/sybase_conf.rb
615
+ - lib/inspec/resources/sybase_session.rb
607
616
  - lib/inspec/resources/sys_info.rb
608
617
  - lib/inspec/resources/systemd_service.rb
609
618
  - lib/inspec/resources/sysv_service.rb