inspec-core 4.56.17 → 5.10.5
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/etc/deprecations.json +12 -16
- data/inspec-core.gemspec +1 -1
- data/lib/inspec/base_cli.rb +14 -2
- data/lib/inspec/cli.rb +15 -0
- data/lib/inspec/dependency_installer.rb +74 -0
- data/lib/inspec/dependency_loader.rb +97 -0
- data/lib/inspec/dsl.rb +11 -2
- data/lib/inspec/errors.rb +7 -0
- data/lib/inspec/formatters/base.rb +23 -0
- data/lib/inspec/metadata.rb +36 -0
- data/lib/inspec/plugin/v2/installer.rb +9 -2
- data/lib/inspec/plugin/v2/loader.rb +13 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +44 -1
- data/lib/inspec/plugin/v2/status.rb +2 -1
- data/lib/inspec/profile.rb +63 -0
- data/lib/inspec/reporters/automate.rb +1 -1
- data/lib/inspec/reporters/cli.rb +1 -1
- data/lib/inspec/reporters/json.rb +31 -11
- data/lib/inspec/resource.rb +6 -0
- data/lib/inspec/resources/apt.rb +12 -6
- data/lib/inspec/resources/cgroup.rb +101 -0
- data/lib/inspec/resources/cron.rb +49 -0
- data/lib/inspec/resources/ipfilter.rb +59 -0
- data/lib/inspec/resources/ipnat.rb +58 -0
- data/lib/inspec/resources/lxc.rb +57 -0
- data/lib/inspec/resources/oracledb_session.rb +7 -3
- data/lib/inspec/resources/postgres_session.rb +4 -2
- data/lib/inspec/resources/virtualization.rb +9 -3
- data/lib/inspec/resources.rb +3 -16
- data/lib/inspec/runner.rb +18 -1
- data/lib/inspec/runner_rspec.rb +15 -0
- data/lib/inspec/schema/exec_json.rb +59 -58
- data/lib/inspec/schema/exec_json_min.rb +16 -16
- data/lib/inspec/schema/primitives.rb +68 -51
- data/lib/inspec/schema/profile_json.rb +27 -27
- data/lib/inspec/schema.rb +1 -0
- data/lib/inspec/ui.rb +10 -0
- data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec.rb +3 -0
- data/lib/plugins/inspec-artifact/inspec-artifact.gemspec +9 -0
- data/lib/plugins/inspec-compliance/inspec-compliance.gemspec +9 -0
- data/lib/plugins/inspec-habitat/inspec-habitat.gemspec +9 -0
- data/lib/plugins/inspec-init/inspec-init.gemspec +9 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
- data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
- data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
- data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
- data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
- data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
- data/lib/plugins/inspec-plugin-manager-cli/inspec-plugin-manager-cli.gemspec +10 -0
- data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +15 -11
- data/lib/plugins/inspec-reporter-html2/inspec-reporter-html2.gemspec +9 -0
- data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +2 -0
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
- data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
- data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
- data/lib/plugins/inspec-reporter-json-min/inspec-reporter-json-min.gemspec +9 -0
- data/lib/plugins/inspec-reporter-junit/inspec-reporter-junit.gemspec +9 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/inspec-streaming-reporter-progress-bar.gemspec +9 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
- metadata +31 -3
data/lib/inspec/profile.rb
CHANGED
@@ -13,6 +13,8 @@ require "inspec/dependencies/cache"
|
|
13
13
|
require "inspec/dependencies/lockfile"
|
14
14
|
require "inspec/dependencies/dependency_set"
|
15
15
|
require "inspec/utils/json_profile_summary"
|
16
|
+
require "inspec/dependency_loader"
|
17
|
+
require "inspec/dependency_installer"
|
16
18
|
|
17
19
|
module Inspec
|
18
20
|
class Profile
|
@@ -378,6 +380,66 @@ module Inspec
|
|
378
380
|
@runner_context
|
379
381
|
end
|
380
382
|
|
383
|
+
def collect_gem_dependencies(profile_context)
|
384
|
+
gem_dependencies = []
|
385
|
+
all_profiles = []
|
386
|
+
profile_context.dependencies.list.values.each do |requirement|
|
387
|
+
all_profiles << requirement.profile
|
388
|
+
end
|
389
|
+
all_profiles << self
|
390
|
+
all_profiles.each do |profile|
|
391
|
+
gem_dependencies << profile.metadata.gem_dependencies unless profile.metadata.gem_dependencies.empty?
|
392
|
+
end
|
393
|
+
gem_dependencies.flatten.uniq
|
394
|
+
end
|
395
|
+
|
396
|
+
# Loads the required gems specified in the Profile's metadata file from default inspec gems path i.e. ~/.inspec/gems
|
397
|
+
# else installs and loads them.
|
398
|
+
def load_gem_dependencies
|
399
|
+
gem_dependencies = collect_gem_dependencies(load_libraries)
|
400
|
+
gem_dependencies.each do |gem_data|
|
401
|
+
dependency_loader = DependencyLoader.new
|
402
|
+
if dependency_loader.gem_version_installed?(gem_data[:name], gem_data[:version]) ||
|
403
|
+
dependency_loader.gem_installed?(gem_data[:name])
|
404
|
+
load_gem_dependency(gem_data)
|
405
|
+
else
|
406
|
+
if Inspec::Config.cached[:auto_install_gems]
|
407
|
+
install_gem_dependency(gem_data)
|
408
|
+
load_gem_dependency(gem_data)
|
409
|
+
else
|
410
|
+
ui = Inspec::UI.new
|
411
|
+
gem_dependencies.each { |gem_dependency| ui.list_item("#{gem_dependency[:name]} #{gem_dependency[:version]}") }
|
412
|
+
choice = ui.prompt.select("Would you like to install profile gem dependencies listed above?", %w{Yes No})
|
413
|
+
if choice == "Yes"
|
414
|
+
Inspec::Config.cached[:auto_install_gems] = true
|
415
|
+
load_gem_dependencies
|
416
|
+
else
|
417
|
+
ui.error "Unable to resolve above listed profile gem dependencies."
|
418
|
+
Inspec::UI.new.exit(:gem_dependency_load_error)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
# Requires gem_data as argument.
|
426
|
+
# gem_dta example: { name: "gem_name", version: "0.0.1"}
|
427
|
+
def load_gem_dependency(gem_data)
|
428
|
+
dependency_loader = DependencyLoader.new(nil, [gem_data])
|
429
|
+
dependency_loader.load
|
430
|
+
rescue Inspec::GemDependencyLoadError => e
|
431
|
+
raise e.message
|
432
|
+
end
|
433
|
+
|
434
|
+
# Requires gem_data as argument.
|
435
|
+
# gem_dta example: { name: "gem_name", version: "0.0.1"}
|
436
|
+
def install_gem_dependency(gem_data)
|
437
|
+
gem_dependency = DependencyInstaller.new(nil, [gem_data])
|
438
|
+
gem_dependency.install
|
439
|
+
rescue Inspec::GemDependencyInstallError => e
|
440
|
+
raise e.message
|
441
|
+
end
|
442
|
+
|
381
443
|
def to_s
|
382
444
|
"Inspec::Profile<#{name}>"
|
383
445
|
end
|
@@ -774,6 +836,7 @@ module Inspec
|
|
774
836
|
end
|
775
837
|
|
776
838
|
def load_checks_params(params)
|
839
|
+
load_gem_dependencies
|
777
840
|
load_libraries
|
778
841
|
tests = collect_tests
|
779
842
|
params[:controls] = controls = {}
|
@@ -21,7 +21,7 @@ module Inspec::Reporters
|
|
21
21
|
final_report[:type] = "inspec_report"
|
22
22
|
|
23
23
|
final_report[:end_time] = Time.now.utc.strftime("%FT%TZ")
|
24
|
-
final_report[:node_uuid] =
|
24
|
+
final_report[:node_uuid] = @config["node_uuid"] || report[:platform][:target_id]
|
25
25
|
raise Inspec::ReporterError, "Cannot find a UUID for your node. Please specify one via json-config." if final_report[:node_uuid].nil?
|
26
26
|
|
27
27
|
final_report[:report_uuid] = @config["report_uuid"] || uuid_from_string(final_report[:end_time] + final_report[:node_uuid])
|
data/lib/inspec/reporters/cli.rb
CHANGED
@@ -76,7 +76,7 @@ module Inspec::Reporters
|
|
76
76
|
}
|
77
77
|
header["Failure Message"] = profile[:status_message] if profile[:status] == "failed"
|
78
78
|
header["Target"] = run_data[:platform][:target] unless run_data[:platform][:target].nil?
|
79
|
-
header["Target ID"] =
|
79
|
+
header["Target ID"] = run_data[:platform][:target_id] || ""
|
80
80
|
|
81
81
|
pad = header.keys.max_by(&:length).length + 1
|
82
82
|
header.each do |title, value|
|
@@ -29,28 +29,48 @@ module Inspec::Reporters
|
|
29
29
|
{
|
30
30
|
name: run_data[:platform][:name],
|
31
31
|
release: run_data[:platform][:release],
|
32
|
-
target_id: run_data[:platform][:target_id] ||
|
32
|
+
target_id: run_data[:platform][:target_id] || "",
|
33
33
|
}.reject { |_k, v| v.nil? }
|
34
34
|
end
|
35
35
|
|
36
36
|
def profile_results(control)
|
37
37
|
(control[:results] || []).map { |r|
|
38
38
|
{
|
39
|
-
status:
|
40
|
-
code_desc:
|
41
|
-
run_time:
|
42
|
-
start_time:
|
43
|
-
resource:
|
44
|
-
skip_message:
|
45
|
-
message:
|
46
|
-
exception:
|
47
|
-
backtrace:
|
48
|
-
resource_class:
|
39
|
+
status: r[:status],
|
40
|
+
code_desc: r[:code_desc],
|
41
|
+
run_time: r[:run_time],
|
42
|
+
start_time: r[:start_time],
|
43
|
+
resource: r[:resource],
|
44
|
+
skip_message: r[:skip_message],
|
45
|
+
message: r[:message],
|
46
|
+
exception: r[:exception],
|
47
|
+
backtrace: r[:backtrace],
|
48
|
+
resource_class: r[:resource_class],
|
49
49
|
resource_params: r[:resource_params].to_s,
|
50
|
+
resource_id: extract_resource_id(r),
|
50
51
|
}.reject { |_k, v| v.nil? }
|
51
52
|
}
|
52
53
|
end
|
53
54
|
|
55
|
+
def extract_resource_id(r)
|
56
|
+
# According to the RunData API, this is supposed to be an anonymous
|
57
|
+
# class that represents a resource, with embedded instance methods....
|
58
|
+
resource_obj = r[:resource_title]
|
59
|
+
return resource_obj.resource_id if resource_obj.respond_to?(:resource_id)
|
60
|
+
|
61
|
+
# But sometimes, it isn't, and has been collapsed into the to_s stringification of the resource.
|
62
|
+
if resource_obj.is_a?(String)
|
63
|
+
orig_str = resource_obj
|
64
|
+
# Try to trim off the resource class - eg "File /some/path" => "/some/path"
|
65
|
+
trimmed_str = orig_str.sub(/^#{r[:resource_class]}/i, "").strip
|
66
|
+
trimmed_str.empty? ? orig_str : trimmed_str
|
67
|
+
else
|
68
|
+
# Boo, InSpec is crazy, and we don't know what it possibly could be.
|
69
|
+
# Failsafe for resource_id is empty string.
|
70
|
+
""
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
54
74
|
def profiles
|
55
75
|
run_data[:profiles].map do |p|
|
56
76
|
res = {
|
data/lib/inspec/resource.rb
CHANGED
@@ -34,6 +34,12 @@ module Inspec
|
|
34
34
|
Inspec::Resource.support_registry[key].push(criteria)
|
35
35
|
end
|
36
36
|
|
37
|
+
def resource_id(value = nil)
|
38
|
+
@resource_id = value if value
|
39
|
+
@resource_id = "" if @resource_id.nil?
|
40
|
+
@resource_id
|
41
|
+
end
|
42
|
+
|
37
43
|
# TODO: this is pretty terrible and is only here to work around
|
38
44
|
# the idea that we've trained resource authors to make initialize
|
39
45
|
# methods w/o calling super.
|
data/lib/inspec/resources/apt.rb
CHANGED
@@ -135,19 +135,25 @@ module Inspec::Resources
|
|
135
135
|
|
136
136
|
class PpaRepository < AptRepository
|
137
137
|
name "ppa"
|
138
|
+
desc "Use the ppa InSpec audit resource to verify PPA repositories on the Debian-based linux platforms."
|
139
|
+
example <<~EXAMPLE
|
140
|
+
describe ppa('ubuntu-wine/ppa') do
|
141
|
+
it { should exist }
|
142
|
+
it { should be_enabled }
|
143
|
+
end
|
144
|
+
|
145
|
+
describe ppa('ppa:ubuntu-wine/ppa') do
|
146
|
+
it { should exist }
|
147
|
+
it { should be_enabled }
|
148
|
+
end
|
149
|
+
EXAMPLE
|
138
150
|
|
139
151
|
def exists?
|
140
|
-
deprecated
|
141
152
|
super()
|
142
153
|
end
|
143
154
|
|
144
155
|
def enabled?
|
145
|
-
deprecated
|
146
156
|
super()
|
147
157
|
end
|
148
|
-
|
149
|
-
def deprecated
|
150
|
-
Inspec.deprecate(:resource_ppa, "The `ppa` resource is deprecated. Please use `apt`")
|
151
|
-
end
|
152
158
|
end
|
153
159
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
module Inspec::Resources
|
3
|
+
class Cgroup < Inspec.resource(1)
|
4
|
+
name "cgroup"
|
5
|
+
# Restrict to only run on the below platform
|
6
|
+
supports platform: "linux"
|
7
|
+
desc "Use the cgroup InSpec audit resource to test cgroup subsytem's parameters."
|
8
|
+
|
9
|
+
example <<~EXAMPLE
|
10
|
+
describe cgroup("foo") do
|
11
|
+
its("cpuset.cpus") { should eq 0 }
|
12
|
+
its("memory.limit_in_bytes") { should eq 499712 }
|
13
|
+
its("memory.limit_in_bytes") { should be <= 500000 }
|
14
|
+
its("memory.numa_stat") { should match /total=0/ }
|
15
|
+
end
|
16
|
+
EXAMPLE
|
17
|
+
|
18
|
+
# Resource initialization.
|
19
|
+
def initialize(cgroup_name)
|
20
|
+
raise Inspec::Exceptions::ResourceSkipped, "The `cgroup` resource is not supported on your OS yet." unless inspec.os.linux?
|
21
|
+
|
22
|
+
@cgroup_name = cgroup_name
|
23
|
+
@valid_queries, @valid_queries_split = [], []
|
24
|
+
find_valid_queries
|
25
|
+
# Used to track the method calls in an "its" query
|
26
|
+
@cgroup_info_query = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def resource_id
|
30
|
+
@cgroup_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"cgroup #{resource_id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(param)
|
38
|
+
# Add the latest param we've seen to the list and form the query with all the params we've seen so far.
|
39
|
+
@cgroup_info_query << param.to_s
|
40
|
+
query = @cgroup_info_query.join(".")
|
41
|
+
|
42
|
+
# The ith level param must match with atleast one row's ith column of @valid_queries_split
|
43
|
+
# Else there is no way, we would find any valid query in further iteration, so raise exception.
|
44
|
+
if @valid_queries_split.map { |e| e[@cgroup_info_query.length - 1] }.include?(param.to_s)
|
45
|
+
# If the query form so far is part of @valid_queries, we are good to trigger find_cgroup_info
|
46
|
+
# else go for next level of param
|
47
|
+
if @valid_queries.include?(query)
|
48
|
+
@cgroup_info_query = []
|
49
|
+
find_cgroup_info(query)
|
50
|
+
else
|
51
|
+
self
|
52
|
+
end
|
53
|
+
else
|
54
|
+
@cgroup_info_query = []
|
55
|
+
|
56
|
+
raise Inspec::Exceptions::ResourceFailed, "The query #{query} does not appear to be valid."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Method to find cgget tool
|
63
|
+
def find_cgget_or_error
|
64
|
+
%w{/usr/sbin/cgget /sbin/cgget cgget}.each do |cmd|
|
65
|
+
return cmd if inspec.command(cmd).exist?
|
66
|
+
end
|
67
|
+
|
68
|
+
raise Inspec::Exceptions::ResourceFailed, "Could not find `cgget`"
|
69
|
+
end
|
70
|
+
|
71
|
+
# find the cgroup info of the query which is given as input by the user
|
72
|
+
def find_cgroup_info(query)
|
73
|
+
bin = find_cgget_or_error
|
74
|
+
cgget_cmd = "#{bin} -n -r #{query} #{@cgroup_name}"
|
75
|
+
cmd = inspec.command(cgget_cmd)
|
76
|
+
|
77
|
+
raise Inspec::Exceptions::ResourceFailed, "Executing cgget failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
|
78
|
+
|
79
|
+
# For complex returns the user must use match /the_regex/
|
80
|
+
param_value = cmd.stdout.split(":")
|
81
|
+
return nil if param_value.nil? || param_value.empty?
|
82
|
+
|
83
|
+
param_value = param_value[1].strip.split("\t").join
|
84
|
+
param_value.match(/^\d+$/) ? param_value.to_i : param_value
|
85
|
+
end
|
86
|
+
|
87
|
+
# find all the information about all relevant controllers for the current cgroup
|
88
|
+
def find_valid_queries
|
89
|
+
bin = find_cgget_or_error
|
90
|
+
cgget_all_cmd = "#{bin} -n -a #{@cgroup_name}"
|
91
|
+
cmd = inspec.command(cgget_all_cmd)
|
92
|
+
|
93
|
+
raise Inspec::Exceptions::ResourceFailed, "Executing cgget failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
|
94
|
+
|
95
|
+
queries = cmd.stdout.to_s.gsub(/:.*/, "").gsub(/^\s+.*/, "").split("\n")
|
96
|
+
# store the relevant controller parameters in @valid_queries and the dot splitted paramters into @valid_queries_split
|
97
|
+
@valid_queries = queries.map { |q| q if q.length > 0 }.compact
|
98
|
+
@valid_queries_split = @valid_queries.map { |q| q.split(".") }.compact
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "inspec/resources/crontab"
|
2
|
+
|
3
|
+
module Inspec::Resources
|
4
|
+
class Cron < Crontab
|
5
|
+
name "cron"
|
6
|
+
supports platform: "unix"
|
7
|
+
desc "Use the cron InSpec audit resource to test entires in the crontab file for a given user. This also can be used as alias to crontab resource."
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe cron do
|
10
|
+
it { should have_entry '* * * * * /usr/local/bin/foo' }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe cron(user: "username") do
|
14
|
+
its(:table) { should match /you can use regexp/ }
|
15
|
+
end
|
16
|
+
EXAMPLE
|
17
|
+
|
18
|
+
def initialize(opts = nil)
|
19
|
+
super
|
20
|
+
@params = read_cron_contents
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_cron_contents
|
24
|
+
result = inspec.command(crontab_cmd)
|
25
|
+
if result.exit_status == 0
|
26
|
+
result.stdout.lines.map { |l| parse_comment_line(l, comment_char: "#", standalone_comments: false)[0].strip }
|
27
|
+
else
|
28
|
+
error = result.stdout + "\n" + result.stderr
|
29
|
+
raise Inspec::Exceptions::ResourceFailed, "Error while executing #{crontab_cmd} command: #{error}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def table
|
34
|
+
@params.reject(&:empty?).join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_entry?(rule)
|
38
|
+
@params.include?(rule)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
if is_user_crontab?
|
43
|
+
"cron for user #{@user}"
|
44
|
+
else
|
45
|
+
"cron for current user"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
module Inspec::Resources
|
3
|
+
class IpFilter < Inspec.resource(1)
|
4
|
+
name "ipfilter"
|
5
|
+
supports platform: "bsd"
|
6
|
+
supports platform: "solaris"
|
7
|
+
desc "Use the ipfilter InSpec audit resource to test rules that are defined for ipfilter, which maintains the IP rule set"
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe ipfilter do
|
10
|
+
it { should have_rule("pass in quick on lo0 all") }
|
11
|
+
end
|
12
|
+
EXAMPLE
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
# checks if the instance is either bsd or solaris
|
16
|
+
return if (inspec.os.bsd? && !inspec.os.darwin?) || inspec.os.solaris?
|
17
|
+
|
18
|
+
# ensures, all calls are aborted for non-supported os
|
19
|
+
@ipfilter_cache = []
|
20
|
+
skip_resource "The `ipfilter` resource is not supported on your OS yet."
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_rule?(rule = nil)
|
24
|
+
# checks if the rule is part of the ruleset
|
25
|
+
retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def retrieve_rules
|
29
|
+
# this would be true if the OS family was not bsd/solaris when checked in initliaze
|
30
|
+
return @ipfilter_cache if defined?(@ipfilter_cache)
|
31
|
+
|
32
|
+
# construct ipfstat command to read all rules
|
33
|
+
bin = find_ipfstat_or_error
|
34
|
+
ipfstat_cmd = "#{bin} -io"
|
35
|
+
cmd = inspec.command(ipfstat_cmd)
|
36
|
+
|
37
|
+
# Return empty array when command is not executed successfully
|
38
|
+
# or there is no output since no rules are active
|
39
|
+
return [] if cmd.exit_status.to_i != 0 || cmd.stdout == ""
|
40
|
+
|
41
|
+
# split rules, returns array or rules
|
42
|
+
@ipfilter_cache = cmd.stdout.split("\n").map(&:strip)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"Ipfilter"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def find_ipfstat_or_error
|
52
|
+
%w{/usr/sbin/ipfstat /sbin/ipfstat ipfstat}.each do |cmd|
|
53
|
+
return cmd if inspec.command(cmd).exist?
|
54
|
+
end
|
55
|
+
|
56
|
+
raise Inspec::Exceptions::ResourceFailed, "Could not find `ipfstat`"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
module Inspec::Resources
|
3
|
+
class IpNat < Inspec.resource(1)
|
4
|
+
name "ipnat"
|
5
|
+
supports platform: "bsd"
|
6
|
+
supports platform: "solaris"
|
7
|
+
desc "Use the ipnat InSpec audit resource to test rules that are defined for IP NAT"
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe ipnat do
|
10
|
+
it { should have_rule("map net1 192.168.0.0/24 -> 0/32") }
|
11
|
+
end
|
12
|
+
EXAMPLE
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
# checks if the instance is either bsd or solaris
|
16
|
+
return if (inspec.os.bsd? && !inspec.os.darwin?) || inspec.os.solaris?
|
17
|
+
|
18
|
+
# ensures, all calls are aborted for non-supported os
|
19
|
+
@ipnat_cache = []
|
20
|
+
skip_resource "The `ipnat` resource is not supported on your OS yet."
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_rule?(rule = nil)
|
24
|
+
# checks if the rule is part of the ruleset
|
25
|
+
retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def retrieve_rules
|
29
|
+
# this would be true if the OS family was not bsd/solaris when checked in initliaze
|
30
|
+
return @ipnat_cache if defined?(@ipnat_cache)
|
31
|
+
|
32
|
+
# construct ipnat command to show the list of current IP NAT table entry mappings
|
33
|
+
bin = find_ipnat_or_error
|
34
|
+
ipnat_cmd = "#{bin} -l"
|
35
|
+
cmd = inspec.command(ipnat_cmd)
|
36
|
+
|
37
|
+
# Return empty array when command is not executed successfully
|
38
|
+
return [] if cmd.exit_status.to_i != 0
|
39
|
+
|
40
|
+
# split rules, returns array or rules
|
41
|
+
@ipnat_cache = cmd.stdout.split("\n").map(&:strip)
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"Ipnat"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def find_ipnat_or_error
|
51
|
+
%w{/usr/sbin/ipnat /sbin/ipnat ipnat}.each do |cmd|
|
52
|
+
return cmd if inspec.command(cmd).exist?
|
53
|
+
end
|
54
|
+
|
55
|
+
raise Inspec::Exceptions::ResourceFailed, "Could not find `ipnat`"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
module Inspec::Resources
|
3
|
+
class Lxc < Inspec.resource(1)
|
4
|
+
name "lxc"
|
5
|
+
# Restrict to only run on the below platforms
|
6
|
+
supports platform: "linux"
|
7
|
+
desc "Use the lxc InSpec audit resource to test if container exists and/or is running for linux container"
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe lxc("ubuntu-container") do
|
10
|
+
it { should exist }
|
11
|
+
it { should be_running }
|
12
|
+
end
|
13
|
+
EXAMPLE
|
14
|
+
|
15
|
+
# Resource initialization.
|
16
|
+
def initialize(container_name)
|
17
|
+
@container_name = container_name
|
18
|
+
|
19
|
+
raise Inspec::Exceptions::ResourceSkipped, "The `lxc` resource is not supported on your OS yet." unless inspec.os.linux?
|
20
|
+
end
|
21
|
+
|
22
|
+
def resource_id
|
23
|
+
@container_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"lxc #{resource_id}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def exists?
|
31
|
+
lxc_info_cmd.exit_status.to_i == 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def running?
|
35
|
+
container_info = lxc_info_cmd.stdout.split(":").map(&:strip)
|
36
|
+
container_info[0] == "Status" && container_info[1] == "Running"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Method to find lxc
|
42
|
+
def find_lxc_or_error
|
43
|
+
%w{/usr/sbin/lxc /sbin/lxc lxc}.each do |cmd|
|
44
|
+
return cmd if inspec.command(cmd).exist?
|
45
|
+
end
|
46
|
+
|
47
|
+
raise Inspec::Exceptions::ResourceFailed, "Could not find `lxc`"
|
48
|
+
end
|
49
|
+
|
50
|
+
def lxc_info_cmd
|
51
|
+
bin = find_lxc_or_error
|
52
|
+
info_cmd = "info #{@container_name} | grep -i Status"
|
53
|
+
lxc_cmd = format("%s %s", bin, info_cmd).strip
|
54
|
+
inspec.command(lxc_cmd)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -61,9 +61,13 @@ module Inspec::Resources
|
|
61
61
|
raise Inspec::Exceptions::ResourceFailed, "Oracle query with errors: #{out}"
|
62
62
|
else
|
63
63
|
begin
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
unless inspec_cmd.stdout.empty?
|
65
|
+
DatabaseHelper::SQLQueryResult.new(inspec_cmd, parse_csv_result(inspec_cmd.stdout))
|
66
|
+
else
|
67
|
+
inspec_cmd.stdout
|
68
|
+
end
|
69
|
+
rescue Exception => ex
|
70
|
+
raise Inspec::Exceptions::ResourceFailed, "Oracle query with exception: #{ex}"
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
@@ -55,8 +55,10 @@ module Inspec::Resources
|
|
55
55
|
psql_cmd = create_psql_cmd(query, db)
|
56
56
|
cmd = inspec.command(psql_cmd, redact_regex: %r{(:\/\/[a-z]*:).*(@)})
|
57
57
|
out = cmd.stdout + "\n" + cmd.stderr
|
58
|
-
if cmd.exit_status != 0
|
59
|
-
raise Inspec::Exceptions::ResourceFailed, "PostgreSQL
|
58
|
+
if cmd.exit_status != 0 && ( out =~ /could not connect to/ || out =~ /password authentication failed/ ) && out.downcase =~ /error:/
|
59
|
+
raise Inspec::Exceptions::ResourceFailed, "PostgreSQL connection error: #{out}"
|
60
|
+
elsif cmd.exit_status != 0 && out.downcase =~ /error:/
|
61
|
+
Lines.new(out, "PostgreSQL query with error: #{query}")
|
60
62
|
else
|
61
63
|
Lines.new(cmd.stdout.strip, "PostgreSQL query: #{query}")
|
62
64
|
end
|
@@ -190,7 +190,7 @@ module Inspec::Resources
|
|
190
190
|
true
|
191
191
|
end
|
192
192
|
|
193
|
-
# Detect LXC/Docker
|
193
|
+
# Detect LXC/Docker/k8s/podman
|
194
194
|
#
|
195
195
|
# /proc/self/cgroup will look like this inside a docker container:
|
196
196
|
# <index #>:<subsystem>:/lxc/<hexadecimal container id>
|
@@ -208,7 +208,7 @@ module Inspec::Resources
|
|
208
208
|
#
|
209
209
|
# Full notes, https://tickets.opscode.com/browse/OHAI-551
|
210
210
|
# Kernel docs, https://www.kernel.org/doc/Documentation/cgroups
|
211
|
-
def
|
211
|
+
def detect_container
|
212
212
|
return false unless inspec.file("/proc/self/cgroup").exist?
|
213
213
|
|
214
214
|
cgroup_content = inspec.file("/proc/self/cgroup").content
|
@@ -216,6 +216,12 @@ module Inspec::Resources
|
|
216
216
|
cgroup_content =~ %r{^\d+:[^:]+:/[^/]+/(lxc|docker)-.+$} # rubocop:disable Layout/MultilineOperationIndentation
|
217
217
|
@virtualization_data[:system] = $1 # rubocop:disable Style/PerlBackrefs
|
218
218
|
@virtualization_data[:role] = "guest"
|
219
|
+
elsif cgroup_content =~ %r{^\d+:[^:]+:/(kubepods)/.+$}
|
220
|
+
@virtualization_data[:system] = $1
|
221
|
+
@virtualization_data[:role] = "guest"
|
222
|
+
elsif /container=podman/.match?(file_read("/proc/1/environ"))
|
223
|
+
@virtualization_data[:system] = "podman"
|
224
|
+
@virtualization_data[:role] = "guest"
|
219
225
|
elsif lxc_version_exists? && cgroup_content =~ %r{\d:[^:]+:/$}
|
220
226
|
# lxc-version shouldn't be installed by default
|
221
227
|
# Even so, it is likely we are on an LXC capable host that is not being used as such
|
@@ -297,7 +303,7 @@ module Inspec::Resources
|
|
297
303
|
return if detect_docker
|
298
304
|
return if detect_virtualbox
|
299
305
|
return if detect_lxd
|
300
|
-
return if
|
306
|
+
return if detect_container
|
301
307
|
return if detect_linux_vserver
|
302
308
|
return if detect_kvm_from_cpuinfo
|
303
309
|
return if detect_kvm_from_sys
|
data/lib/inspec/resources.rb
CHANGED
@@ -8,21 +8,6 @@
|
|
8
8
|
# glob so this remains a sort of manifest for our resources.
|
9
9
|
|
10
10
|
require "inspec/resource"
|
11
|
-
|
12
|
-
# Detect if we are running the stripped-down inspec-core
|
13
|
-
# This relies on AWS being stripped from the inspec-core gem
|
14
|
-
inspec_core_only = ENV["NO_AWS"] || !File.exist?(File.join(File.dirname(__FILE__), "..", "resource_support", "aws.rb"))
|
15
|
-
|
16
|
-
# Do not attempt to load cloud resources if we are in inspec-core mode
|
17
|
-
unless inspec_core_only
|
18
|
-
require "resource_support/aws"
|
19
|
-
require "resources/azure/azure_backend"
|
20
|
-
require "resources/azure/azure_generic_resource"
|
21
|
-
require "resources/azure/azure_resource_group"
|
22
|
-
require "resources/azure/azure_virtual_machine"
|
23
|
-
require "resources/azure/azure_virtual_machine_data_disk"
|
24
|
-
end
|
25
|
-
|
26
11
|
require "inspec/resources/aide_conf"
|
27
12
|
require "inspec/resources/apache"
|
28
13
|
require "inspec/resources/apache_conf"
|
@@ -41,6 +26,7 @@ require "inspec/resources/cassandradb_session"
|
|
41
26
|
require "inspec/resources/cassandradb_conf"
|
42
27
|
require "inspec/resources/cassandra"
|
43
28
|
require "inspec/resources/crontab"
|
29
|
+
require "inspec/resources/cron"
|
44
30
|
require "inspec/resources/timezone"
|
45
31
|
require "inspec/resources/dh_params"
|
46
32
|
require "inspec/resources/directory"
|
@@ -138,7 +124,8 @@ require "inspec/resources/xinetd_conf"
|
|
138
124
|
require "inspec/resources/yum"
|
139
125
|
require "inspec/resources/zfs_dataset"
|
140
126
|
require "inspec/resources/zfs_pool"
|
141
|
-
|
127
|
+
require "inspec/resources/ipnat"
|
128
|
+
require "inspec/resources/ipfilter"
|
142
129
|
# file formats, depend on json implementation
|
143
130
|
require "inspec/resources/json"
|
144
131
|
require "inspec/resources/yaml"
|