inspec-core 4.38.9 → 4.41.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/inspec/base_cli.rb +2 -0
- data/lib/inspec/cli.rb +2 -0
- data/lib/inspec/control_eval_context.rb +41 -2
- data/lib/inspec/profile.rb +26 -1
- data/lib/inspec/resources.rb +3 -0
- data/lib/inspec/resources/mongodb_session.rb +88 -0
- data/lib/inspec/resources/opa.rb +23 -0
- data/lib/inspec/resources/opa_api.rb +39 -0
- data/lib/inspec/resources/opa_cli.rb +43 -0
- data/lib/inspec/runner.rb +2 -0
- data/lib/inspec/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccadabfe4c0ecceecb305842e1874255ce4797a8df92e9d1d940bfe52f4b2dbb
|
4
|
+
data.tar.gz: 8bed2e86c15c05fcd6ee5974e1167aab1f2ab6c2d321a6f802af738594fafe5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9a9e7a80179eaa6f1a77ff4fd4aa4505a39ce389a655bdf853caeece477c58ea7ef46db749cf54a11c2e5dff5e62b09fdd950caac396ffbab4640183549924
|
7
|
+
data.tar.gz: 613c20973b4b10202fe0d0aac0e53b65cb0cb201150b93665304f0a5f7d4341981768cc799865bb3d7b9ad6b9afa93f782a9651d88001001b899d85b4521e1b6
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -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
|
-
|
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)
|
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
|
data/lib/inspec/profile.rb
CHANGED
@@ -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
|
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
|
|
data/lib/inspec/resources.rb
CHANGED
@@ -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
|
|
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.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-
|
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
|