inspec-core 4.38.9 → 4.41.2

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: 17449ad4c9680511a8fc11c6fdb11d9ece550a7942c9e734c95eac0d41913d9f
4
- data.tar.gz: ae5055ccc9bebd1aed4f22da4ad4dcd1be31e1bd2b5707e7b5fb088c916eda08
3
+ metadata.gz: ccadabfe4c0ecceecb305842e1874255ce4797a8df92e9d1d940bfe52f4b2dbb
4
+ data.tar.gz: 8bed2e86c15c05fcd6ee5974e1167aab1f2ab6c2d321a6f802af738594fafe5b
5
5
  SHA512:
6
- metadata.gz: 6cec299ca48d7ca4c3fb9b3eecc79c8687541fbd83fc79e837ed13d2abb4bcb861f747782a68bf90f7e1083443a671079a1368a97e9f552e249e456616a92059
7
- data.tar.gz: 287e2d79dbc494c83d6f8b8046e0f9c54632c5a13ec75ac69b603bdf9fe9b6a89ff86c9c8f025f7e04372490adb1ffa5a5a7fc10f3ecab1e7fabd70f71f6767d
6
+ metadata.gz: ac9a9e7a80179eaa6f1a77ff4fd4aa4505a39ce389a655bdf853caeece477c58ea7ef46db749cf54a11c2e5dff5e62b09fdd950caac396ffbab4640183549924
7
+ data.tar.gz: 613c20973b4b10202fe0d0aac0e53b65cb0cb201150b93665304f0a5f7d4341981768cc799865bb3d7b9ad6b9afa93f782a9651d88001001b899d85b4521e1b6
@@ -136,6 +136,8 @@ module Inspec
136
136
  profile_options
137
137
  option :controls, type: :array,
138
138
  desc: "A list of control names to run, or a list of /regexes/ to match against control names. Ignore all other tests."
139
+ option :tags, type: :array,
140
+ desc: "A list of tags names that are part of controls to filter and run controls, or a list of /regexes/ to match against tags names of controls. Ignore all other tests."
139
141
  option :reporter, type: :array,
140
142
  banner: "one two:/output/file/path",
141
143
  desc: "Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit, yaml"
data/lib/inspec/cli.rb CHANGED
@@ -65,6 +65,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
65
65
  desc: "Save the created profile to a path"
66
66
  option :controls, type: :array,
67
67
  desc: "A list of controls to include. Ignore all other tests."
68
+ option :tags, type: :array,
69
+ desc: "A list of tags to filter controls and include only those. Ignore all other tests."
68
70
  profile_options
69
71
  def json(target)
70
72
  require "json" unless defined?(JSON)
@@ -53,12 +53,23 @@ module Inspec
53
53
 
54
54
  def control(id, opts = {}, &block)
55
55
  opts[:skip_only_if_eval] = @skip_only_if_eval
56
- if control_exist_in_controls_list?(id) || controls_list_empty?
56
+ tag_ids = control_tags(&block)
57
+ if (controls_list_empty? && tags_list_empty?) || control_exist_in_controls_list?(id) || tag_exist_in_control_tags?(tag_ids)
57
58
  register_control(Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block))
58
59
  end
59
60
  end
61
+
60
62
  alias rule control
61
63
 
64
+ def control_tags(&block)
65
+ tag_source = block.source.split("\n").select { |src| src.split.first.eql?("tag") }
66
+ tag_source = tag_source.map { |src| src.sub("tag", "").strip }.map { |src| src.split(",").map { |final_src| final_src.sub(/([^:]*):/, "") } }.flatten
67
+ output = tag_source.map { |src| src.sub(/\[|\]/, "") }.map { |src| instance_eval(src) }
68
+ output.compact.uniq
69
+ rescue
70
+ []
71
+ end
72
+
62
73
  # Describe allows users to write rspec-like bare describe
63
74
  # blocks without declaring an inclosing control. Here, we
64
75
  # generate a control for them automatically and then execute
@@ -74,7 +85,7 @@ module Inspec
74
85
  res = describe(*args, &block)
75
86
  end
76
87
 
77
- if control_exist_in_controls_list?(id) || controls_list_empty?
88
+ if controls_list_empty? || control_exist_in_controls_list?(id)
78
89
  register_control(rule, &block)
79
90
  end
80
91
 
@@ -187,11 +198,19 @@ module Inspec
187
198
  !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_controls_list.empty?
188
199
  end
189
200
 
201
+ def profile_tag_config_exist?
202
+ !@conf.empty? && @conf.key?("profile") && !@conf["profile"].include_tags_list.empty?
203
+ end
204
+
190
205
  # Returns true if configuration hash is empty or configuration hash does not have the list of controls that needs to be included
191
206
  def controls_list_empty?
192
207
  !@conf.empty? && @conf.key?("profile") && @conf["profile"].include_controls_list.empty? || @conf.empty?
193
208
  end
194
209
 
210
+ def tags_list_empty?
211
+ !@conf.empty? && @conf.key?("profile") && @conf["profile"].include_tags_list.empty? || @conf.empty?
212
+ end
213
+
195
214
  # Check if the given control exist in the --controls option
196
215
  def control_exist_in_controls_list?(id)
197
216
  id_exist_in_list = false
@@ -203,5 +222,25 @@ module Inspec
203
222
  end
204
223
  id_exist_in_list
205
224
  end
225
+
226
+ # Check if the given control exist in the --tags option
227
+ def tag_exist_in_control_tags?(tag_ids)
228
+ tag_option_matches_with_list = false
229
+ if !tag_ids.empty? && !tag_ids.nil? && profile_tag_config_exist?
230
+ tag_option_matches_with_list = !(tag_ids & @conf["profile"].include_tags_list).empty?
231
+ unless tag_option_matches_with_list
232
+ @conf["profile"].include_tags_list.any? do |inclusion|
233
+ # Try to see if the inclusion is a regex, and if it matches
234
+ if inclusion.is_a?(Regexp)
235
+ tag_ids.each do |id|
236
+ tag_option_matches_with_list = (inclusion =~ id)
237
+ break if tag_option_matches_with_list
238
+ end
239
+ end
240
+ end
241
+ end
242
+ end
243
+ tag_option_matches_with_list
244
+ end
206
245
  end
207
246
  end
@@ -87,6 +87,7 @@ module Inspec
87
87
  @logger = options[:logger] || Logger.new(nil)
88
88
  @locked_dependencies = options[:dependencies]
89
89
  @controls = options[:controls] || []
90
+ @tags = options[:tags] || []
90
91
  @writable = options[:writable] || false
91
92
  @profile_id = options[:id]
92
93
  @profile_name = options[:profile_name]
@@ -206,7 +207,7 @@ module Inspec
206
207
  @params ||= load_params
207
208
  end
208
209
 
209
- def collect_tests(include_list = @controls)
210
+ def collect_tests
210
211
  unless @tests_collected || failed?
211
212
  return unless supports_platform?
212
213
 
@@ -253,6 +254,30 @@ module Inspec
253
254
  included_controls
254
255
  end
255
256
 
257
+ # This creates the list of controls to be filtered by tag values provided in the --tags options
258
+ def include_tags_list
259
+ return [] if @tags.nil? || @tags.empty?
260
+
261
+ included_tags = @tags
262
+ # Check for anything that might be a regex in the list, and make it official
263
+ included_tags.each_with_index do |inclusion, index|
264
+ next if inclusion.is_a?(Regexp)
265
+ # Insist the user wrap the regex in slashes to demarcate it as a regex
266
+ next unless inclusion.start_with?("/") && inclusion.end_with?("/")
267
+
268
+ inclusion = inclusion[1..-2] # Trim slashes
269
+ begin
270
+ re = Regexp.new(inclusion)
271
+ included_tags[index] = re
272
+ rescue RegexpError => e
273
+ warn "Ignoring unparseable regex '/#{inclusion}/' in --control CLI option: #{e.message}"
274
+ included_tags[index] = nil
275
+ end
276
+ end
277
+ included_tags.compact!
278
+ included_tags
279
+ end
280
+
256
281
  def load_libraries
257
282
  return @runner_context if @libraries_loaded
258
283
 
@@ -73,6 +73,7 @@ require "inspec/resources/limits_conf"
73
73
  require "inspec/resources/login_defs"
74
74
  require "inspec/resources/mongodb"
75
75
  require "inspec/resources/mongodb_conf"
76
+ require "inspec/resources/mongodb_session"
76
77
  require "inspec/resources/mount"
77
78
  require "inspec/resources/mssql_session"
78
79
  require "inspec/resources/mysql"
@@ -83,6 +84,8 @@ require "inspec/resources/nginx_conf"
83
84
  require "inspec/resources/npm"
84
85
  require "inspec/resources/ntp_conf"
85
86
  require "inspec/resources/oneget"
87
+ require "inspec/resources/opa_cli"
88
+ require "inspec/resources/opa_api"
86
89
  require "inspec/resources/oracledb_session"
87
90
  require "inspec/resources/os"
88
91
  require "inspec/resources/os_env"
@@ -0,0 +1,88 @@
1
+ require "mongo"
2
+
3
+ module Inspec::Resources
4
+ class Lines
5
+ attr_reader :params
6
+
7
+ def initialize(raw, desc)
8
+ @params = raw
9
+ @desc = desc
10
+ end
11
+
12
+ def to_s
13
+ @desc
14
+ end
15
+ end
16
+
17
+ class MongodbSession < Inspec.resource(1)
18
+ name "mongodb_session"
19
+ supports platform: "unix"
20
+ supports platform: "windows"
21
+
22
+ desc "Use the mongodb_session InSpec audit resource to run MongoDB command against a MongoDB Database."
23
+ example <<~EXAMPLE
24
+ # default values:
25
+ # host: "127.0.0.1"
26
+ # port: "27017"
27
+ # auth_source - default to database name
28
+ # auth_mech - :scram
29
+
30
+ describe mongodb_session(user: "foo", password: "bar", database: "test").query(usersInfo: "ian").params["users"].first["roles"].first do
31
+ its(["role"]) { should eq "readWrite" }
32
+ end
33
+ EXAMPLE
34
+ attr_reader :user, :host, :port, :database, :params
35
+
36
+ def initialize(opts = {})
37
+ @user = opts[:user] || nil
38
+ @password = opts[:password] || nil
39
+ @host = opts[:host] || "127.0.0.1"
40
+ @port = opts[:port] || "27017"
41
+ @database = opts[:database] || nil
42
+ @auth_mech = opts[:auth_mech] || :scram
43
+ @auth_source = opts[:auth_source] || @database
44
+ @ssl = opts[:ssl] || false
45
+ @ssl_cert = opts[:ssl_cert] || nil
46
+ @ssl_key = opts[:ssl_key] || nil
47
+ @ssl_ca_cert = opts[:ssl_ca_cert] || nil
48
+ @auth_mech_properties = opts[:auth_mech_properties] || {}
49
+ @client = nil
50
+
51
+ fail_resource "Can't run MongoDB checks without authentication." unless user && @password
52
+ fail_resource "You must provide a database name for the session." unless database
53
+
54
+ create_session
55
+ end
56
+
57
+ def query(command)
58
+ raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
59
+
60
+ Lines.new(@client.command(command).documents.first, "MongoDB query: #{command}")
61
+ rescue => e
62
+ raise Inspec::Exceptions::ResourceFailed, "Can't run MongoDB command Error: #{e.message}"
63
+ end
64
+
65
+ private
66
+
67
+ def create_session
68
+ raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
69
+
70
+ options = { user: "#{user}",
71
+ password: "#{@password}",
72
+ database: "#{database}",
73
+ auth_source: "#{@auth_source}",
74
+ auth_mech: @auth_mech,
75
+ }
76
+ options[:auth_mech_properties] = @auth_mech_properties unless @auth_mech_properties.empty?
77
+ options[:ssl] = @ssl
78
+ opitons[:ssl_key] = @ssl_key unless @ssl_key.nil?
79
+ options[:ssl_cert] = @ssl_cert unless @ssl_cert.nil?
80
+ options[:ssl_ca_cert] = @ssl_ca_cert unless @ssl_ca_cert.nil?
81
+
82
+ @client = Mongo::Client.new([ "#{host}:#{port}" ], options)
83
+
84
+ rescue => e
85
+ raise Inspec::Exceptions::ResourceFailed, "Can't run MongoDB command. Error: #{e.message}"
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,23 @@
1
+ require "inspec/resources/json"
2
+
3
+ module Inspec::Resources
4
+ class Opa < JsonConfig
5
+ name "opa"
6
+ supports platform: "unix"
7
+ supports platform: "windows"
8
+
9
+ attr_reader :result
10
+ def initialize(content)
11
+ @content = content
12
+ super({ content: @content })
13
+ end
14
+
15
+ private
16
+
17
+ def parse(content)
18
+ @content = YAML.load(content)
19
+ rescue => e
20
+ raise Inspec::Exceptions::ResourceFailed, "Unable to parse OPA query output: #{e.message}"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ require "inspec/resources/opa"
2
+
3
+ module Inspec::Resources
4
+ class OpaApi < Opa
5
+ name "opa_api"
6
+ supports platform: "unix"
7
+ supports platform: "windows"
8
+
9
+ def initialize(opts = {})
10
+ @url = opts[:url] || nil
11
+ @data = opts[:data] || nil
12
+ fail_resource "OPA url and data are mandatory." if @url.nil? || @url.empty? || @data.nil? || @data.empty?
13
+ @content = load_result
14
+ super(@content)
15
+ end
16
+
17
+ def allow
18
+ @content["result"]
19
+ end
20
+
21
+ def to_s
22
+ "OPA api"
23
+ end
24
+
25
+ private
26
+
27
+ def load_result
28
+ raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
29
+
30
+ result = inspec.command("curl -X POST #{@url} -d @#{@data} -H 'Content-Type: application/json'")
31
+ if result.exit_status == 0
32
+ result.stdout.gsub("\n", "")
33
+ else
34
+ error = result.stdout + "\n" + result.stderr
35
+ raise Inspec::Exceptions::ResourceFailed, "Error while executing OPA query: #{error}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ require "inspec/resources/opa"
2
+
3
+ module Inspec::Resources
4
+ class OpaCli < Opa
5
+ name "opa_cli"
6
+ supports platform: "unix"
7
+ supports platform: "windows"
8
+
9
+ def initialize(opts = {})
10
+ @opa_executable_path = opts[:opa_executable_path] || "opa" # if this path is not provided then we will assume that it's been set in the ENV PATH
11
+ @policy = opts[:policy] || nil
12
+ @data = opts[:data] || nil
13
+ @query = opts[:query] || nil
14
+ if (@policy.nil? || @policy.empty?) || (@data.nil? || @data.empty?) || (@query.nil? || @query.empty?)
15
+ fail_resource "OPA policy, data and query are mandatory."
16
+ end
17
+ @content = load_result
18
+ super(@content)
19
+ end
20
+
21
+ def allow
22
+ @content["result"][0]["expressions"][0]["value"] if @content["result"][0]["expressions"][0]["text"].include?("allow")
23
+ end
24
+
25
+ def to_s
26
+ "OPA cli"
27
+ end
28
+
29
+ private
30
+
31
+ def load_result
32
+ raise Inspec::Exceptions::ResourceFailed, "#{resource_exception_message}" if resource_failed?
33
+
34
+ result = inspec.command("#{@opa_executable_path} eval -i '#{@data}' -d '#{@policy}' '#{@query}'")
35
+ if result.exit_status == 0
36
+ result.stdout.gsub("\n", "")
37
+ else
38
+ error = result.stdout + "\n" + result.stderr
39
+ raise Inspec::Exceptions::ResourceFailed, "Error while executing OPA query: #{error}"
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/inspec/runner.rb CHANGED
@@ -50,6 +50,7 @@ module Inspec
50
50
  @conf[:logger] ||= Logger.new(nil)
51
51
  @target_profiles = []
52
52
  @controls = @conf[:controls] || []
53
+ @tags = @conf[:tags] || []
53
54
  @depends = @conf[:depends] || []
54
55
  @create_lockfile = @conf[:create_lockfile]
55
56
  @cache = Inspec::Cache.new(@conf[:vendor_cache])
@@ -199,6 +200,7 @@ module Inspec
199
200
  vendor_cache: @cache,
200
201
  backend: @backend,
201
202
  controls: @controls,
203
+ tags: @tags,
202
204
  runner_conf: @conf)
203
205
  raise "Could not resolve #{target} to valid input." if profile.nil?
204
206
 
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.38.9".freeze
2
+ VERSION = "4.41.2".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.38.9
4
+ version: 4.41.2
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-07-22 00:00:00.000000000 Z
11
+ date: 2021-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-telemetry
@@ -556,6 +556,7 @@ files:
556
556
  - lib/inspec/resources/login_defs.rb
557
557
  - lib/inspec/resources/mongodb.rb
558
558
  - lib/inspec/resources/mongodb_conf.rb
559
+ - lib/inspec/resources/mongodb_session.rb
559
560
  - lib/inspec/resources/mount.rb
560
561
  - lib/inspec/resources/mssql_session.rb
561
562
  - lib/inspec/resources/mysql.rb
@@ -567,6 +568,9 @@ files:
567
568
  - lib/inspec/resources/npm.rb
568
569
  - lib/inspec/resources/ntp_conf.rb
569
570
  - lib/inspec/resources/oneget.rb
571
+ - lib/inspec/resources/opa.rb
572
+ - lib/inspec/resources/opa_api.rb
573
+ - lib/inspec/resources/opa_cli.rb
570
574
  - lib/inspec/resources/oracledb_session.rb
571
575
  - lib/inspec/resources/os.rb
572
576
  - lib/inspec/resources/os_env.rb