inspec 1.45.9 → 1.45.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 +4 -4
- data/.rubocop.yml +54 -32
- data/CHANGELOG.md +29 -21
- data/Gemfile +1 -1
- data/docs/resources/ini.md.erb +14 -1
- data/docs/shell.md +1 -1
- data/inspec.gemspec +2 -2
- data/lib/bundles/inspec-artifact/cli.rb +3 -8
- data/lib/bundles/inspec-compliance/configuration.rb +5 -5
- data/lib/bundles/inspec-compliance/http.rb +2 -5
- data/lib/bundles/inspec-compliance/target.rb +6 -6
- data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +1 -1
- data/lib/bundles/inspec-habitat/profile.rb +68 -74
- data/lib/bundles/inspec-supermarket/api.rb +7 -7
- data/lib/bundles/inspec-supermarket/cli.rb +1 -1
- data/lib/fetchers/git.rb +3 -8
- data/lib/fetchers/local.rb +7 -13
- data/lib/fetchers/url.rb +1 -1
- data/lib/inspec/backend.rb +0 -1
- data/lib/inspec/base_cli.rb +1 -1
- data/lib/inspec/cached_fetcher.rb +11 -12
- data/lib/inspec/cli.rb +0 -1
- data/lib/inspec/control_eval_context.rb +2 -2
- data/lib/inspec/dependencies/lockfile.rb +13 -15
- data/lib/inspec/dependencies/requirement.rb +1 -1
- data/lib/inspec/dependencies/resolver.rb +3 -5
- data/lib/inspec/dsl.rb +5 -5
- data/lib/inspec/dsl_shared.rb +1 -1
- data/lib/inspec/env_printer.rb +26 -26
- data/lib/inspec/metadata.rb +11 -10
- data/lib/inspec/objects/or_test.rb +4 -2
- data/lib/inspec/objects/test.rb +1 -1
- data/lib/inspec/profile.rb +2 -2
- data/lib/inspec/resource.rb +1 -3
- data/lib/inspec/rspec_json_formatter.rb +6 -8
- data/lib/inspec/shell.rb +51 -52
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +1 -2
- data/lib/resources/audit_policy.rb +2 -2
- data/lib/resources/auditd.rb +6 -3
- data/lib/resources/dh_params.rb +1 -2
- data/lib/resources/docker.rb +2 -2
- data/lib/resources/docker_container.rb +4 -4
- data/lib/resources/elasticsearch.rb +2 -6
- data/lib/resources/etc_group.rb +2 -4
- data/lib/resources/groups.rb +14 -14
- data/lib/resources/host.rb +2 -3
- data/lib/resources/packages.rb +1 -1
- data/lib/resources/port.rb +1 -1
- data/lib/resources/postgres.rb +6 -6
- data/lib/resources/powershell.rb +1 -1
- data/lib/resources/service.rb +4 -5
- data/lib/resources/users.rb +58 -58
- data/lib/resources/vbscript.rb +10 -10
- data/lib/resources/virtualization.rb +3 -4
- data/lib/resources/x509_certificate.rb +1 -1
- data/lib/resources/yum.rb +1 -1
- data/lib/source_readers/inspec.rb +2 -1
- data/lib/utils/command_wrapper.rb +3 -8
- data/lib/utils/filter.rb +1 -1
- data/lib/utils/json_log.rb +2 -1
- data/lib/utils/latest_version.rb +5 -4
- data/lib/utils/object_traversal.rb +1 -1
- data/lib/utils/parser.rb +2 -2
- metadata +4 -4
@@ -54,11 +54,11 @@ module Supermarket
|
|
54
54
|
|
55
55
|
def self.find(profile, supermarket_url = SUPERMARKET_URL)
|
56
56
|
profiles = Supermarket::API.profiles(supermarket_url)
|
57
|
-
if
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
return if profiles.empty?
|
58
|
+
|
59
|
+
index = profiles.index { |t| same?(profile, t, supermarket_url) }
|
60
|
+
# return profile or nil
|
61
|
+
profiles[index] if !index.nil? && index >= 0
|
62
62
|
end
|
63
63
|
|
64
64
|
# verifies that a profile exists
|
@@ -75,9 +75,9 @@ module Supermarket
|
|
75
75
|
|
76
76
|
def self.send_request(uri, req)
|
77
77
|
# send request
|
78
|
-
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https')
|
78
|
+
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
79
79
|
http.request(req)
|
80
|
-
|
80
|
+
end
|
81
81
|
[res.is_a?(Net::HTTPSuccess), res.body]
|
82
82
|
end
|
83
83
|
end
|
@@ -42,7 +42,7 @@ module Supermarket
|
|
42
42
|
# check that the profile is available
|
43
43
|
supermarket_profiles = Supermarket::API.profiles
|
44
44
|
found = supermarket_profiles.select { |p|
|
45
|
-
"#{p['tool_owner']}/#{p['slug']}"
|
45
|
+
profile == "#{p['tool_owner']}/#{p['slug']}"
|
46
46
|
}
|
47
47
|
|
48
48
|
if found.empty?
|
data/lib/fetchers/git.rb
CHANGED
@@ -24,14 +24,12 @@ module Fetchers
|
|
24
24
|
# you got to this file during debugging, you may want to look at the
|
25
25
|
# omnibus source for hints.
|
26
26
|
#
|
27
|
-
class Git < Inspec.fetcher(1)
|
27
|
+
class Git < Inspec.fetcher(1)
|
28
28
|
name 'git'
|
29
29
|
priority 200
|
30
30
|
|
31
31
|
def self.resolve(target, opts = {})
|
32
|
-
if target.respond_to?(:has_key?) &&target.key?(:git)
|
33
|
-
new(target[:git], opts.merge(target))
|
34
|
-
end
|
32
|
+
new(target[:git], opts.merge(target)) if target.respond_to?(:has_key?) && target.key?(:git)
|
35
33
|
end
|
36
34
|
|
37
35
|
def initialize(remote_url, opts = {})
|
@@ -121,10 +119,7 @@ module Fetchers
|
|
121
119
|
if tagged_commit
|
122
120
|
tagged_commit.first
|
123
121
|
else
|
124
|
-
|
125
|
-
if found
|
126
|
-
found.first
|
127
|
-
end
|
122
|
+
pairs.find { |m| m[1].end_with?(ref_name.to_s) }&.first
|
128
123
|
end
|
129
124
|
end
|
130
125
|
|
data/lib/fetchers/local.rb
CHANGED
@@ -16,19 +16,15 @@ module Fetchers
|
|
16
16
|
resolve_from_hash(target)
|
17
17
|
end
|
18
18
|
|
19
|
-
if local_path
|
20
|
-
new(local_path)
|
21
|
-
end
|
19
|
+
new(local_path) if local_path
|
22
20
|
end
|
23
21
|
|
24
22
|
def self.resolve_from_hash(target)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
local_path
|
31
|
-
end
|
23
|
+
return unless target.key?(:path)
|
24
|
+
|
25
|
+
local_path = target[:path]
|
26
|
+
local_path = File.expand_path(local_path, target[:cwd]) if target.key?(:cwd)
|
27
|
+
local_path
|
32
28
|
end
|
33
29
|
|
34
30
|
def self.resolve_from_string(target)
|
@@ -40,9 +36,7 @@ module Fetchers
|
|
40
36
|
target = target.tr('\\', '/')
|
41
37
|
end
|
42
38
|
|
43
|
-
if File.exist?(target)
|
44
|
-
target
|
45
|
-
end
|
39
|
+
target if File.exist?(target)
|
46
40
|
end
|
47
41
|
|
48
42
|
def initialize(target)
|
data/lib/fetchers/url.rb
CHANGED
@@ -141,7 +141,7 @@ module Fetchers
|
|
141
141
|
|
142
142
|
# Downloads archive to temporary file with side effect :( of setting @archive_type
|
143
143
|
def download_archive_to_temp
|
144
|
-
return @temp_archive_path if
|
144
|
+
return @temp_archive_path if !@temp_archive_path.nil?
|
145
145
|
Inspec::Log.debug("Fetching URL: #{@target}")
|
146
146
|
remote = open(@target, http_opts)
|
147
147
|
@archive_type = file_type_from_remote(remote) # side effect :(
|
data/lib/inspec/backend.rb
CHANGED
data/lib/inspec/base_cli.rb
CHANGED
@@ -48,20 +48,19 @@ module Inspec
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def assert_cache_sanity!
|
51
|
-
|
52
|
-
if fetcher.resolved_source[:sha256] != target[:sha256]
|
53
|
-
raise <<EOF
|
54
|
-
The remote source #{fetcher} no longer has the requested content:
|
51
|
+
return unless target.respond_to?(:key?) && target.key?(:sha256)
|
55
52
|
|
56
|
-
|
57
|
-
|
53
|
+
exception_message = <<~EOF
|
54
|
+
The remote source #{fetcher} no longer has the requested content:
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
56
|
+
Request Content Hash: #{target[:sha256]}
|
57
|
+
Actual Content Hash: #{fetcher.resolved_source[:sha256]}
|
58
|
+
|
59
|
+
For URL, supermarket, compliance, and other sources that do not
|
60
|
+
provide versioned artifacts, this likely means that the remote source
|
61
|
+
has changed since your lockfile was generated.
|
62
|
+
EOF
|
63
|
+
raise exception_message if fetcher.resolved_source[:sha256] != target[:sha256]
|
65
64
|
end
|
66
65
|
end
|
67
66
|
end
|
data/lib/inspec/cli.rb
CHANGED
@@ -40,7 +40,7 @@ module Inspec
|
|
40
40
|
profile_context_owner = profile_context
|
41
41
|
profile_id = profile_context.profile_id
|
42
42
|
|
43
|
-
Class.new do
|
43
|
+
Class.new do # rubocop:disable Metrics/BlockLength
|
44
44
|
include Inspec::DSL
|
45
45
|
include Inspec::DSL::RequireOverride
|
46
46
|
include resources_dsl
|
@@ -80,7 +80,7 @@ module Inspec
|
|
80
80
|
# the describe block in the context of that control.
|
81
81
|
#
|
82
82
|
define_method :describe do |*args, &block|
|
83
|
-
loc = block_location(block, caller
|
83
|
+
loc = block_location(block, caller(1..1).first)
|
84
84
|
id = "(generated from #{loc} #{SecureRandom.hex})"
|
85
85
|
|
86
86
|
res = nil
|
@@ -31,22 +31,22 @@ module Inspec
|
|
31
31
|
# rubocop:disable Style/GuardClause
|
32
32
|
def self.validate_lockfile_version!(version)
|
33
33
|
if version < MINIMUM_SUPPORTED_VERSION
|
34
|
-
raise
|
35
|
-
This lockfile specifies a lockfile_version of #{version} which is
|
36
|
-
lower than the minimum supported version #{MINIMUM_SUPPORTED_VERSION}.
|
34
|
+
raise <<~EOF
|
35
|
+
This lockfile specifies a lockfile_version of #{version} which is
|
36
|
+
lower than the minimum supported version #{MINIMUM_SUPPORTED_VERSION}.
|
37
37
|
|
38
|
-
Please create a new lockfile for this project by running:
|
38
|
+
Please create a new lockfile for this project by running:
|
39
39
|
|
40
|
-
|
41
|
-
EOF
|
40
|
+
inspec vendor
|
41
|
+
EOF
|
42
42
|
elsif version > CURRENT_LOCKFILE_VERSION
|
43
|
-
raise
|
44
|
-
This lockfile claims to be version #{version} which is greater than
|
45
|
-
the most recent lockfile version(#{CURRENT_LOCKFILE_VERSION}).
|
43
|
+
raise <<~EOF
|
44
|
+
This lockfile claims to be version #{version} which is greater than
|
45
|
+
the most recent lockfile version(#{CURRENT_LOCKFILE_VERSION}).
|
46
46
|
|
47
|
-
This may happen if you are using an older version of inspec than was
|
48
|
-
used to create the lockfile.
|
49
|
-
EOF
|
47
|
+
This may happen if you are using an older version of inspec than was
|
48
|
+
used to create the lockfile.
|
49
|
+
EOF
|
50
50
|
end
|
51
51
|
end
|
52
52
|
# rubocop:enable Style/GuardClause
|
@@ -87,9 +87,7 @@ EOF
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def parse_content_hash_1(lockfile_content_hash)
|
90
|
-
@deps =
|
91
|
-
lockfile_content_hash['depends'].map { |i| symbolize_keys(i) }
|
92
|
-
end
|
90
|
+
@deps = lockfile_content_hash['depends']&.map { |i| symbolize_keys(i) }
|
93
91
|
end
|
94
92
|
|
95
93
|
def mutate_hash_keys_with(hash, fun)
|
@@ -64,11 +64,9 @@ module Inspec
|
|
64
64
|
path_string + " -> #{dep.name}"
|
65
65
|
end
|
66
66
|
|
67
|
-
if new_seen_items.key?(dep.resolved_source)
|
68
|
-
|
69
|
-
|
70
|
-
new_seen_items[dep.resolved_source] = true
|
71
|
-
end
|
67
|
+
raise Inspec::CyclicDependencyError, "Dependency #{dep} would cause a dependency cycle (#{new_path_string})" if new_seen_items.key?(dep.resolved_source)
|
68
|
+
|
69
|
+
new_seen_items[dep.resolved_source] = true
|
72
70
|
|
73
71
|
if !dep.source_satisfies_spec?
|
74
72
|
raise Inspec::UnsatisfiedVersionSpecification, "The profile #{dep.name} from #{dep.resolved_source} has a version #{dep.source_version} which doesn't match #{dep.version_constraints}"
|
data/lib/inspec/dsl.rb
CHANGED
@@ -33,12 +33,12 @@ module Inspec::DSL
|
|
33
33
|
|
34
34
|
dep_entry = dependencies.list[profile_id]
|
35
35
|
if dep_entry.nil?
|
36
|
-
raise
|
37
|
-
Cannot load #{profile_id} since it is not listed as a dependency of #{bind_context.profile_name}.
|
36
|
+
raise <<~EOF
|
37
|
+
Cannot load #{profile_id} since it is not listed as a dependency of #{bind_context.profile_name}.
|
38
38
|
|
39
|
-
Dependencies available from this context are:
|
40
|
-
|
41
|
-
EOF
|
39
|
+
Dependencies available from this context are:
|
40
|
+
#{dependencies.list.keys.join("\n ")}
|
41
|
+
EOF
|
42
42
|
end
|
43
43
|
|
44
44
|
context = dep_entry.profile.runner_context
|
data/lib/inspec/dsl_shared.rb
CHANGED
@@ -18,7 +18,7 @@ module Inspec
|
|
18
18
|
# We cannot rely on libraries residing on disk however.
|
19
19
|
# TODO: Sandboxing.
|
20
20
|
content, path, line = @require_loader.load(rbpath)
|
21
|
-
eval(content, TOPLEVEL_BINDING, path, line) # rubocop:disable
|
21
|
+
eval(content, TOPLEVEL_BINDING, path, line) # rubocop:disable Security/Eval
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
data/lib/inspec/env_printer.rb
CHANGED
@@ -41,7 +41,7 @@ module Inspec
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def have_shell?
|
44
|
-
!
|
44
|
+
!(@shell.nil? || @shell.empty?)
|
45
45
|
end
|
46
46
|
|
47
47
|
def have_shell_completion?
|
@@ -61,26 +61,26 @@ module Inspec
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def print_usage_guidance
|
64
|
-
puts
|
65
|
-
# To use this, eval it in your shell
|
66
|
-
#
|
67
|
-
# #{EVAL_COMMANDS[shell]}
|
68
|
-
#
|
69
|
-
#
|
70
|
-
EOF
|
64
|
+
puts <<~EOF
|
65
|
+
# To use this, eval it in your shell
|
66
|
+
#
|
67
|
+
# #{EVAL_COMMANDS[shell]}
|
68
|
+
#
|
69
|
+
#
|
70
|
+
EOF
|
71
71
|
end
|
72
72
|
|
73
73
|
def print_detection_warning(device)
|
74
|
-
device.puts
|
75
|
-
#
|
76
|
-
# The shell #{@shell} was auto-detected. If this is incorrect, please
|
77
|
-
# specify a shell explicitly by running:
|
78
|
-
#
|
79
|
-
# inspec env SHELLNAME
|
80
|
-
#
|
81
|
-
# Currently supported shells are: #{shells_with_completions.join(', ')}
|
82
|
-
#
|
83
|
-
EOF
|
74
|
+
device.puts <<~EOF
|
75
|
+
#
|
76
|
+
# The shell #{@shell} was auto-detected. If this is incorrect, please
|
77
|
+
# specify a shell explicitly by running:
|
78
|
+
#
|
79
|
+
# inspec env SHELLNAME
|
80
|
+
#
|
81
|
+
# Currently supported shells are: #{shells_with_completions.join(', ')}
|
82
|
+
#
|
83
|
+
EOF
|
84
84
|
end
|
85
85
|
|
86
86
|
def exit_no_completion
|
@@ -93,14 +93,14 @@ EOF
|
|
93
93
|
if @detected
|
94
94
|
$stderr.puts '# Unable to automatically detect shell and no shell was provided.'
|
95
95
|
end
|
96
|
-
$stderr.puts
|
97
|
-
#
|
98
|
-
# Please provide the name of your shell via the command line:
|
99
|
-
#
|
100
|
-
# inspec env SHELLNAME
|
101
|
-
#
|
102
|
-
# Currently supported shells are: #{shells_with_completions.join(', ')}
|
103
|
-
EOF
|
96
|
+
$stderr.puts <<~EOF
|
97
|
+
#
|
98
|
+
# Please provide the name of your shell via the command line:
|
99
|
+
#
|
100
|
+
# inspec env SHELLNAME
|
101
|
+
#
|
102
|
+
# Currently supported shells are: #{shells_with_completions.join(', ')}
|
103
|
+
EOF
|
104
104
|
exit 1
|
105
105
|
end
|
106
106
|
|
data/lib/inspec/metadata.rb
CHANGED
@@ -110,7 +110,7 @@ module Inspec
|
|
110
110
|
errors = []
|
111
111
|
warnings = []
|
112
112
|
|
113
|
-
%w{
|
113
|
+
%w{name version}.each do |field|
|
114
114
|
next unless params[field.to_sym].nil?
|
115
115
|
errors.push("Missing profile #{field} in #{ref}")
|
116
116
|
end
|
@@ -126,7 +126,7 @@ module Inspec
|
|
126
126
|
errors.push('Version needs to be in SemVer format')
|
127
127
|
end
|
128
128
|
|
129
|
-
%w{
|
129
|
+
%w{title summary maintainer copyright license}.each do |field|
|
130
130
|
next unless params[field.to_sym].nil?
|
131
131
|
warnings.push("Missing profile #{field} in #{ref}")
|
132
132
|
end
|
@@ -165,11 +165,11 @@ module Inspec
|
|
165
165
|
return obj.map { |i| symbolize_keys(i) } if obj.is_a?(Array)
|
166
166
|
return obj unless obj.is_a?(Hash)
|
167
167
|
|
168
|
-
obj.each_with_object({})
|
168
|
+
obj.each_with_object({}) do |(k, v), h|
|
169
169
|
v = symbolize_keys(v) if v.is_a?(Hash)
|
170
170
|
v = symbolize_keys(v) if v.is_a?(Array)
|
171
171
|
h[k.to_sym] = v
|
172
|
-
|
172
|
+
end
|
173
173
|
end
|
174
174
|
|
175
175
|
def self.finalize_supports_elem(elem, logger)
|
@@ -188,7 +188,8 @@ module Inspec
|
|
188
188
|
logger ||= Logger.new(nil)
|
189
189
|
logger.warn(
|
190
190
|
"Do not use deprecated `supports: #{x}` syntax. Instead use:\n"\
|
191
|
-
"supports:\n - os-family: #{x}\n\n"
|
191
|
+
"supports:\n - os-family: #{x}\n\n",
|
192
|
+
)
|
192
193
|
{ :'os-family' => x } # rubocop:disable Style/HashSyntax
|
193
194
|
end
|
194
195
|
end
|
@@ -202,7 +203,8 @@ module Inspec
|
|
202
203
|
logger ||= Logger.new(nil)
|
203
204
|
logger.warn(
|
204
205
|
"Do not use deprecated `supports: #{x}` syntax. Instead use:\n"\
|
205
|
-
"supports:\n - os-family: #{x}\n\n"
|
206
|
+
"supports:\n - os-family: #{x}\n\n",
|
207
|
+
)
|
206
208
|
[{ :'os-family' => x }] # rubocop:disable Style/HashSyntax
|
207
209
|
end
|
208
210
|
end
|
@@ -223,10 +225,9 @@ module Inspec
|
|
223
225
|
# create a new name based on the original target if it exists
|
224
226
|
# Crudely slug the target to not contain slashes, to avoid breaking
|
225
227
|
# unit tests that look for warning sequences
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
end
|
228
|
+
return if original_target.to_s.empty?
|
229
|
+
metadata.params[:title] = "tests from #{original_target}"
|
230
|
+
metadata.params[:name] = metadata.params[:title].gsub(%r{[\\\/]}, '.')
|
230
231
|
end
|
231
232
|
|
232
233
|
def self.finalize(metadata, profile_id, options, logger = nil)
|
@@ -24,10 +24,12 @@ module Inspec
|
|
24
24
|
test.negate!
|
25
25
|
test
|
26
26
|
}.map(&:to_ruby).join("\n")
|
27
|
-
|
27
|
+
|
28
|
+
all_tests
|
28
29
|
else
|
29
30
|
all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
|
30
|
-
|
31
|
+
|
32
|
+
format("describe.one do\n %s\nend", all_tests)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|