inspec-core 4.7.24 → 4.10.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -2
- data/lib/fetchers/git.rb +49 -10
- data/lib/inspec/cli.rb +23 -34
- data/lib/inspec/resources/windows_task.rb +5 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +0 -12
- data/lib/plugins/inspec-habitat/templates/habitat/plan.sh.erb +1 -78
- data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +106 -69
- metadata +2 -6
- data/lib/inspec/utils/latest_version.rb +0 -13
- data/lib/plugins/inspec-habitat/templates/habitat/config/inspec_exec_config.json.erb +0 -25
- data/lib/plugins/inspec-habitat/templates/habitat/default.toml.erb +0 -9
- data/lib/plugins/inspec-habitat/templates/habitat/hooks/run.erb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 431744ec266e2ed0cbde565cc232ee4bb944ff76076d8c10d381c73346796337
|
4
|
+
data.tar.gz: a8a844283829729c5a886a9e324e7fc22b31a986eb25e36c0a01fe7a26fbda78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3678f2a31c972d7e6e08c3352249ce9bc72b82b7989a1758b70a3bdc41912cc0eb048bd70cc4da0794b929f53aacdfe6227e5defc13aeb3465cc5cc744393a8c
|
7
|
+
data.tar.gz: 5ded1f1c7315194f7ae8a791aea4e21221b524debdc4136fe2e60911b9c050c9e948af0529aca1eff1dcfd1e68a8f3ab17be448b65aab202bf16c789d0e7b4a1
|
data/README.md
CHANGED
@@ -7,8 +7,7 @@
|
|
7
7
|
For more information on project states and SLAs, see [this documentation](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md).
|
8
8
|
|
9
9
|
[![Slack](https://community-slack.chef.io/badge.svg)](https://community-slack.chef.io/)
|
10
|
-
[![Build
|
11
|
-
[![Build Status Master](https://ci.appveyor.com/api/projects/status/github/inspec/inspec?branch=master&svg=true&passingText=master%20-%20Ok&pendingText=master%20-%20Pending&failingText=master%20-%20Failing)](https://ci.appveyor.com/project/Chef/inspec/branch/master)
|
10
|
+
[![Build status](https://badge.buildkite.com/bf4c5fdc3858cc9f8c8bab8376e8e40d625ad046df9d4d8619.svg?branch=master)](https://buildkite.com/chef-oss/inspec-inspec-master-verify)
|
12
11
|
[![Coverage Status](https://coveralls.io/repos/github/inspec/inspec/badge.svg?branch=master)](https://coveralls.io/github/inspec/inspec?branch=master)
|
13
12
|
|
14
13
|
Chef InSpec is an open-source testing framework for infrastructure with a human- and machine-readable language for specifying compliance, security and policy requirements.
|
data/lib/fetchers/git.rb
CHANGED
@@ -39,28 +39,65 @@ module Fetchers
|
|
39
39
|
@branch = opts[:branch]
|
40
40
|
@tag = opts[:tag]
|
41
41
|
@ref = opts[:ref]
|
42
|
-
@remote_url = remote_url
|
42
|
+
@remote_url = expand_local_path(remote_url)
|
43
43
|
@repo_directory = nil
|
44
|
+
@relative_path = opts[:relative_path] if opts[:relative_path] && !opts[:relative_path].empty?
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
47
|
+
def expand_local_path(url_or_file_path)
|
48
|
+
# This paths to local on-disk repos, not relative paths within repos.
|
49
|
+
# This is especially needed with testing.
|
50
|
+
|
51
|
+
# We could try to do something clever with URI
|
52
|
+
# processing, but then again, if you passed a relative path
|
53
|
+
# to an on-disk repo, you probably expect it to exist.
|
54
|
+
return url_or_file_path unless File.exist?(url_or_file_path)
|
55
|
+
# It's important to expand this path, because it may be specified
|
56
|
+
# locally in the metadata files, and when we clone, we will be
|
57
|
+
# in a temp dir.
|
58
|
+
File.expand_path(url_or_file_path)
|
59
|
+
end
|
60
|
+
|
61
|
+
def fetch(destination_path)
|
62
|
+
@repo_directory = destination_path # Might be the cache, or vendoring, or something else
|
63
|
+
FileUtils.mkdir_p(destination_path) unless Dir.exist?(destination_path)
|
49
64
|
|
50
65
|
if cloned?
|
51
66
|
checkout
|
52
67
|
else
|
53
|
-
Dir.mktmpdir do |
|
54
|
-
checkout(
|
55
|
-
|
56
|
-
|
68
|
+
Dir.mktmpdir do |working_dir|
|
69
|
+
checkout(working_dir)
|
70
|
+
if @relative_path
|
71
|
+
perform_relative_path_fetch(destination_path, working_dir)
|
72
|
+
else
|
73
|
+
Inspec::Log.debug("Checkout of #{resolved_ref} successful. " \
|
74
|
+
"Moving checkout to #{destination_path}")
|
75
|
+
FileUtils.cp_r(working_dir + "/.", destination_path)
|
76
|
+
end
|
57
77
|
end
|
58
78
|
end
|
59
79
|
@repo_directory
|
60
80
|
end
|
61
81
|
|
82
|
+
def perform_relative_path_fetch(destination_path, working_dir)
|
83
|
+
Inspec::Log.debug("Checkout of #{resolved_ref} successful. " \
|
84
|
+
"Moving #{@relative_path} to #{destination_path}")
|
85
|
+
unless File.exist?("#{working_dir}/#{@relative_path}")
|
86
|
+
# Cleanup the destination path - otherwise we'll have an empty dir
|
87
|
+
# in the cache, which is enough to confuse the cache reader
|
88
|
+
# This is a courtesy, assuming we're writing to the cache; if we're
|
89
|
+
# vendoring to something more complex, don't bother.
|
90
|
+
FileUtils.rmdir(destination_path) if Dir.empty?(destination_path)
|
91
|
+
|
92
|
+
raise ArgumentError, "Cannot find relative path '#{@relative_path}' " \
|
93
|
+
"within profile in git repo specified by '#{@remote_url}'"
|
94
|
+
end
|
95
|
+
FileUtils.cp_r("#{working_dir}/#{@relative_path}", destination_path)
|
96
|
+
end
|
97
|
+
|
62
98
|
def cache_key
|
63
|
-
resolved_ref
|
99
|
+
return resolved_ref unless @relative_path
|
100
|
+
OpenSSL::Digest::SHA256.hexdigest(resolved_ref + @relative_path)
|
64
101
|
end
|
65
102
|
|
66
103
|
def archive_path
|
@@ -68,7 +105,9 @@ module Fetchers
|
|
68
105
|
end
|
69
106
|
|
70
107
|
def resolved_source
|
71
|
-
{ git: @remote_url, ref: resolved_ref }
|
108
|
+
source = { git: @remote_url, ref: resolved_ref }
|
109
|
+
source[:relative_path] = @relative_path if @relative_path
|
110
|
+
source
|
72
111
|
end
|
73
112
|
|
74
113
|
private
|
data/lib/inspec/cli.rb
CHANGED
@@ -123,36 +123,32 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
123
123
|
puts JSON.generate(result)
|
124
124
|
else
|
125
125
|
%w{location profile controls timestamp valid}.each do |item|
|
126
|
-
|
127
|
-
|
126
|
+
prepared_string = format("%-12s %s",
|
127
|
+
"#{item.to_s.capitalize} :",
|
128
|
+
result[:summary][item.to_sym])
|
129
|
+
ui.plain_line(prepared_string)
|
128
130
|
end
|
129
131
|
puts
|
130
132
|
|
131
133
|
if result[:errors].empty? && result[:warnings].empty?
|
132
|
-
|
134
|
+
ui.plain_line("No errors or warnings")
|
133
135
|
else
|
134
|
-
red = "\033[31m"
|
135
|
-
yellow = "\033[33m"
|
136
|
-
rst = "\033[0m"
|
137
|
-
|
138
136
|
item_msg = lambda { |item|
|
139
137
|
pos = [item[:file], item[:line], item[:column]].compact.join(":")
|
140
138
|
pos.empty? ? item[:msg] : pos + ": " + item[:msg]
|
141
139
|
}
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
result[:warnings].each do |item|
|
146
|
-
puts "#{yellow} ! #{item_msg.call(item)}#{rst}"
|
147
|
-
end
|
140
|
+
|
141
|
+
result[:errors].each { |item| ui.red " #{Inspec::UI::GLYPHS[:script_x]} #{item_msg.call(item)}\n" }
|
142
|
+
result[:warnings].each { |item| ui.yellow " ! #{item_msg.call(item)}\n" }
|
148
143
|
|
149
144
|
puts
|
150
|
-
|
151
|
-
|
152
|
-
|
145
|
+
|
146
|
+
errors = ui.red("#{result[:errors].length} errors", print: false)
|
147
|
+
warnings = ui.yellow("#{result[:warnings].length} warnings", print: false)
|
148
|
+
ui.plain_line("Summary: #{errors}, #{warnings}")
|
153
149
|
end
|
154
150
|
end
|
155
|
-
exit
|
151
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless result[:summary][:valid]
|
156
152
|
rescue StandardError => e
|
157
153
|
pretty_handle_exception(e)
|
158
154
|
end
|
@@ -203,11 +199,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
203
199
|
|
204
200
|
if result && !o[:ignore_errors] == false
|
205
201
|
o[:logger].info "Profile check failed. Please fix the profile before generating an archive."
|
206
|
-
return exit
|
202
|
+
return ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
207
203
|
end
|
208
204
|
|
209
205
|
# generate archive
|
210
|
-
exit
|
206
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless profile.archive(o)
|
211
207
|
rescue StandardError => e
|
212
208
|
pretty_handle_exception(e)
|
213
209
|
end
|
@@ -294,10 +290,10 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
294
290
|
runner = Inspec::Runner.new(o)
|
295
291
|
targets.each { |target| runner.add_target(target) }
|
296
292
|
|
297
|
-
exit runner.run
|
293
|
+
ui.exit runner.run
|
298
294
|
rescue ArgumentError, RuntimeError, Train::UserError => e
|
299
295
|
$stderr.puts e.message
|
300
|
-
exit
|
296
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
301
297
|
rescue StandardError => e
|
302
298
|
pretty_handle_exception(e)
|
303
299
|
end
|
@@ -312,12 +308,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
312
308
|
if o["format"] == "json"
|
313
309
|
puts res.to_json
|
314
310
|
else
|
315
|
-
headline("Platform Details")
|
316
|
-
|
311
|
+
ui.headline("Platform Details")
|
312
|
+
ui.plain Inspec::BaseCLI.format_platform_info(params: res, indent: 0, color: 36)
|
317
313
|
end
|
318
314
|
rescue ArgumentError, RuntimeError, Train::UserError => e
|
319
315
|
$stderr.puts e.message
|
320
|
-
exit
|
316
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
321
317
|
rescue StandardError => e
|
322
318
|
pretty_handle_exception(e)
|
323
319
|
end
|
@@ -348,12 +344,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
348
344
|
end
|
349
345
|
|
350
346
|
run_type, res = run_command(o)
|
351
|
-
exit res unless run_type == :ruby_eval
|
347
|
+
ui.exit res unless run_type == :ruby_eval
|
352
348
|
|
353
349
|
# No InSpec tests - just print evaluation output.
|
354
350
|
res = (res.respond_to?(:to_json) ? res.to_json : JSON.dump(res)) if o["reporter"]&.keys&.include?("json")
|
355
351
|
puts res
|
356
|
-
exit
|
352
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
357
353
|
rescue RuntimeError, Train::UserError => e
|
358
354
|
$stderr.puts e.message
|
359
355
|
rescue StandardError => e
|
@@ -385,14 +381,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
385
381
|
v = { version: Inspec::VERSION }
|
386
382
|
puts v.to_json
|
387
383
|
else
|
388
|
-
require "inspec/utils/latest_version"
|
389
384
|
puts Inspec::VERSION
|
390
|
-
# display outdated version
|
391
|
-
# TODO: remove this. Don't notify of update to a gem when they install omnibus
|
392
|
-
latest = LatestInSpecVersion.new.latest || Inspec::VERSION
|
393
|
-
if Gem::Version.new(Inspec::VERSION) < Gem::Version.new(latest)
|
394
|
-
puts "\nYour version of #{Inspec::Dist::PRODUCT_NAME} is out of date! The latest version is #{latest}."
|
395
|
-
end
|
396
385
|
end
|
397
386
|
end
|
398
387
|
map %w{-v --version} => :version
|
@@ -470,5 +459,5 @@ rescue Inspec::Plugin::V2::Exception => v2ex
|
|
470
459
|
else
|
471
460
|
Inspec::Log.error "Run again with --debug for a stacktrace."
|
472
461
|
end
|
473
|
-
exit
|
462
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
474
463
|
end
|
@@ -88,6 +88,11 @@ module Inspec::Resources
|
|
88
88
|
return nil
|
89
89
|
end
|
90
90
|
|
91
|
+
# If multiple triggers are defined, `schtasks` returns a list.
|
92
|
+
# This merges that list with the latest item taking precedence.
|
93
|
+
# This is the same behavior as `Get-ScheduledTask`.
|
94
|
+
params = params.reduce(:merge) if params.is_a?(Array)
|
95
|
+
|
91
96
|
@cache = {
|
92
97
|
uri: params["URI"],
|
93
98
|
state: params["State"],
|
data/lib/inspec/version.rb
CHANGED
@@ -64,18 +64,6 @@ module InspecPlugins
|
|
64
64
|
habitat_origin: read_habitat_config["origin"],
|
65
65
|
}
|
66
66
|
create_file_from_template(plan_file, "plan.sh.erb", vars)
|
67
|
-
|
68
|
-
run_hook_file = File.join(path, "habitat", "hooks", "run")
|
69
|
-
logger.info("Generating a Habitat run hook at #{run_hook_file}...")
|
70
|
-
create_file_from_template(run_hook_file, "hooks/run.erb")
|
71
|
-
|
72
|
-
default_toml = File.join(path, "habitat", "default.toml")
|
73
|
-
logger.info("Generating a Habitat default.toml at #{default_toml}...")
|
74
|
-
create_file_from_template(default_toml, "default.toml.erb")
|
75
|
-
|
76
|
-
config = File.join(path, "habitat", "config", "inspec_exec_config.json")
|
77
|
-
logger.info("Generating #{config} for `#{EXEC_NAME} exec`...")
|
78
|
-
create_file_from_template(config, "config/inspec_exec_config.json.erb")
|
79
67
|
end
|
80
68
|
|
81
69
|
def upload
|
@@ -5,81 +5,4 @@ pkg_deps=(chef/inspec)
|
|
5
5
|
pkg_build_deps=(chef/inspec core/jq-static)
|
6
6
|
pkg_svc_user=root
|
7
7
|
<%= "pkg_license='#{profile.metadata.params[:license]}'" if profile.metadata.params[:license]%>
|
8
|
-
|
9
|
-
do_before() {
|
10
|
-
# Exit with error if not in the directory with 'inspec.yml'.
|
11
|
-
# This can happen if someone does 'hab studio enter' from within the
|
12
|
-
# 'habitat/' directory.
|
13
|
-
if [ ! -f "$PLAN_CONTEXT/../inspec.yml" ]; then
|
14
|
-
message="ERROR: Cannot find inspec.yml."
|
15
|
-
message="$message Please build from the profile root"
|
16
|
-
build_line "$message"
|
17
|
-
|
18
|
-
return 1
|
19
|
-
fi
|
20
|
-
|
21
|
-
# Execute an '<%= Inspec::Dist::EXEC_NAME %> compliance login' if a profile needs to be fetched from
|
22
|
-
# the Automate server
|
23
|
-
if [ "$(grep "compliance: " "$PLAN_CONTEXT/../inspec.yml")" ]; then
|
24
|
-
_do_compliance_login;
|
25
|
-
fi
|
26
|
-
}
|
27
|
-
|
28
|
-
do_setup_environment() {
|
29
|
-
set_buildtime_env PROFILE_CACHE_DIR "$HAB_CACHE_SRC_PATH/$pkg_dirname"
|
30
|
-
set_buildtime_env ARCHIVE_NAME "$pkg_name-$pkg_version.tar.gz"
|
31
|
-
|
32
|
-
# <%= Inspec::Dist::PRODUCT_NAME %> loads `pry` which tries to expand `~`. This fails if HOME isn't set.
|
33
|
-
set_runtime_env HOME "$pkg_svc_var_path"
|
34
|
-
|
35
|
-
# <%= Inspec::Dist::PRODUCT_NAME %> will create a `.inspec` directory in the user's home directory.
|
36
|
-
# This overrides that to write to a place within the running service's path.
|
37
|
-
# NOTE: Setting HOME does the same currently. This is here to be explicit.
|
38
|
-
set_runtime_env INSPEC_CONFIG_DIR "$pkg_svc_var_path"
|
39
|
-
}
|
40
|
-
|
41
|
-
do_unpack() {
|
42
|
-
# Change directory to where the profile files are
|
43
|
-
pushd "$PLAN_CONTEXT/../" > /dev/null
|
44
|
-
|
45
|
-
# Get a list of all files in the profile except those that are Habitat related
|
46
|
-
profile_files=($(ls -I habitat -I results -I "*.hart"))
|
47
|
-
|
48
|
-
mkdir -p "$PROFILE_CACHE_DIR" > /dev/null
|
49
|
-
|
50
|
-
# Copy just the profile files to the profile cache directory
|
51
|
-
cp -r ${profile_files[@]} "$PROFILE_CACHE_DIR"
|
52
|
-
}
|
53
|
-
|
54
|
-
do_build() {
|
55
|
-
<%= Inspec::Dist::EXEC_NAME %> archive "$PROFILE_CACHE_DIR" \
|
56
|
-
--overwrite \
|
57
|
-
-o "$PROFILE_CACHE_DIR/$ARCHIVE_NAME"
|
58
|
-
}
|
59
|
-
|
60
|
-
do_install() {
|
61
|
-
cp "$PROFILE_CACHE_DIR/$ARCHIVE_NAME" "$pkg_prefix"
|
62
|
-
}
|
63
|
-
|
64
|
-
_do_compliance_login() {
|
65
|
-
if [ -z $COMPLIANCE_CREDS ]; then
|
66
|
-
message="ERROR: Please perform an '<%= Inspec::Dist::EXEC_NAME %> compliance login' and set"
|
67
|
-
message="$message \$HAB_STUDIO_SECRET_COMPLIANCE_CREDS to the contents of"
|
68
|
-
message="$message '~/.inspec/compliance/config.json'"
|
69
|
-
build_line "$message"
|
70
|
-
return 1
|
71
|
-
fi
|
72
|
-
|
73
|
-
user=$(echo $COMPLIANCE_CREDS | jq .user | sed 's/"//g')
|
74
|
-
token=$(echo $COMPLIANCE_CREDS | jq .token | sed 's/"//g')
|
75
|
-
automate_server=$(echo $COMPLIANCE_CREDS | \
|
76
|
-
jq .server | \
|
77
|
-
sed 's/\/api\/v0//' | \
|
78
|
-
sed 's/"//g'
|
79
|
-
)
|
80
|
-
insecure=$(echo $COMPLIANCE_CREDS | jq .insecure)
|
81
|
-
<%= Inspec::Dist::EXEC_NAME %> compliance login --insecure $insecure \
|
82
|
-
--user $user \
|
83
|
-
--token $token \
|
84
|
-
$automate_server
|
85
|
-
}
|
8
|
+
pkg_scaffolding="chef/scaffolding-chef-inspec"
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require "term/ansicolor"
|
2
1
|
require "pathname"
|
3
2
|
require "inspec/plugin/v2"
|
4
3
|
require "inspec/plugin/v2/installer"
|
@@ -7,7 +6,6 @@ require "inspec/dist"
|
|
7
6
|
module InspecPlugins
|
8
7
|
module PluginManager
|
9
8
|
class CliCommand < Inspec.plugin(2, :cli_command)
|
10
|
-
include Term::ANSIColor
|
11
9
|
include Inspec::Dist
|
12
10
|
|
13
11
|
subcommand_desc "plugin SUBCOMMAND", "Manage #{PRODUCT_NAME} and Train plugins"
|
@@ -22,15 +20,17 @@ module InspecPlugins
|
|
22
20
|
plugin_statuses = Inspec::Plugin::V2::Registry.instance.plugin_statuses
|
23
21
|
plugin_statuses.reject! { |s| %i{core bundle}.include?(s.installation_type) } unless options[:all]
|
24
22
|
|
25
|
-
# TODO: ui object support
|
26
23
|
puts
|
27
|
-
|
28
|
-
|
24
|
+
ui.bold(format(" %-30s%-10s%-8s%-6s", "Plugin Name", "Version", "Via", "ApiVer"))
|
25
|
+
ui.line
|
29
26
|
plugin_statuses.sort_by(&:name).each do |status|
|
30
|
-
|
27
|
+
ui.plain(format(" %-30s%-10s%-8s%-6s", status.name,
|
28
|
+
make_pretty_version(status),
|
29
|
+
status.installation_type,
|
30
|
+
status.api_generation.to_s))
|
31
31
|
end
|
32
|
-
|
33
|
-
|
32
|
+
ui.line
|
33
|
+
ui.plain(" #{plugin_statuses.count} plugin(s) total")
|
34
34
|
puts
|
35
35
|
end
|
36
36
|
|
@@ -59,23 +59,22 @@ module InspecPlugins
|
|
59
59
|
search_results.delete("train-test-fixture")
|
60
60
|
end
|
61
61
|
|
62
|
-
# TODO: ui object support
|
63
62
|
puts
|
64
|
-
|
65
|
-
|
63
|
+
ui.bold(format(" %-30s%-50s", "Plugin Name", "Versions Available"))
|
64
|
+
ui.line
|
66
65
|
search_results.keys.sort.each do |plugin_name|
|
67
66
|
versions = options[:all] ? search_results[plugin_name] : [search_results[plugin_name].first]
|
68
67
|
versions = "(" + versions.join(", ") + ")"
|
69
|
-
|
68
|
+
ui.plain(format(" %-30s%-50s", plugin_name, versions))
|
70
69
|
end
|
71
|
-
|
72
|
-
|
70
|
+
ui.line
|
71
|
+
ui.plain(" #{search_results.count} plugin(s) found")
|
73
72
|
puts
|
74
73
|
|
75
|
-
exit
|
74
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR if search_results.empty?
|
76
75
|
rescue Inspec::Plugin::V2::SearchError => ex
|
77
76
|
Inspec::Log.error ex.message
|
78
|
-
exit
|
77
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
79
78
|
end
|
80
79
|
|
81
80
|
#==================================================================#
|
@@ -119,13 +118,14 @@ module InspecPlugins
|
|
119
118
|
begin
|
120
119
|
installer.update(plugin_name)
|
121
120
|
rescue Inspec::Plugin::V2::UpdateError => ex
|
122
|
-
|
123
|
-
exit
|
121
|
+
ui.plain("#{ui.red('Update error:')} #{ex.message} - update failed")
|
122
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
124
123
|
end
|
125
124
|
post_update_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
|
126
125
|
new_version = (post_update_versions - pre_update_versions).first
|
127
126
|
|
128
|
-
|
127
|
+
ui.bold(plugin_name + " plugin, version #{old_version} -> " \
|
128
|
+
"#{new_version}, updated from rubygems.org")
|
129
129
|
end
|
130
130
|
|
131
131
|
#--------------------------
|
@@ -144,9 +144,9 @@ module InspecPlugins
|
|
144
144
|
def uninstall(plugin_name)
|
145
145
|
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
|
146
146
|
unless status
|
147
|
-
|
148
|
-
|
149
|
-
exit
|
147
|
+
ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} is not " \
|
148
|
+
"installed - uninstall failed")
|
149
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
150
150
|
end
|
151
151
|
installer = Inspec::Plugin::V2::Installer.instance
|
152
152
|
|
@@ -156,11 +156,13 @@ module InspecPlugins
|
|
156
156
|
installer.uninstall(plugin_name)
|
157
157
|
|
158
158
|
if status.installation_type == :path
|
159
|
-
|
159
|
+
ui.bold(plugin_name + " path-based plugin install has been " \
|
160
|
+
"uninstalled")
|
160
161
|
else
|
161
|
-
|
162
|
+
ui.bold(plugin_name + " plugin, version #{old_version}, has " \
|
163
|
+
"been uninstalled")
|
162
164
|
end
|
163
|
-
exit
|
165
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
164
166
|
end
|
165
167
|
|
166
168
|
private
|
@@ -172,8 +174,8 @@ module InspecPlugins
|
|
172
174
|
|
173
175
|
def install_from_gemfile(gem_file)
|
174
176
|
unless File.exist? gem_file
|
175
|
-
|
176
|
-
exit
|
177
|
+
ui.red("No such plugin gem file #{gem_file} - installation failed.")
|
178
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
177
179
|
end
|
178
180
|
|
179
181
|
plugin_name_parts = File.basename(gem_file, ".gem").split("-")
|
@@ -183,14 +185,15 @@ module InspecPlugins
|
|
183
185
|
|
184
186
|
installer.install(plugin_name, gem_file: gem_file)
|
185
187
|
|
186
|
-
|
187
|
-
|
188
|
+
ui.bold("#{plugin_name} plugin, version #{version}, installed from " \
|
189
|
+
"local .gem file")
|
190
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
188
191
|
end
|
189
192
|
|
190
193
|
def install_from_path(path)
|
191
194
|
unless File.exist? path
|
192
|
-
|
193
|
-
exit
|
195
|
+
ui.red("No such source code path #{path} - installation failed.")
|
196
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
194
197
|
end
|
195
198
|
|
196
199
|
plugin_name = File.basename(path, ".rb")
|
@@ -204,8 +207,10 @@ module InspecPlugins
|
|
204
207
|
|
205
208
|
# Already installed?
|
206
209
|
if registry.known_plugin?(plugin_name.to_sym)
|
207
|
-
|
208
|
-
|
210
|
+
ui.red("Plugin already installed - #{plugin_name} - Use '#{EXEC_NAME} " \
|
211
|
+
"plugin list' to see previously installed plugin - " \
|
212
|
+
"installation failed.")
|
213
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
209
214
|
end
|
210
215
|
|
211
216
|
# Can we figure out how to load it?
|
@@ -217,8 +222,9 @@ module InspecPlugins
|
|
217
222
|
# OK, install it!
|
218
223
|
installer.install(plugin_name, path: entry_point)
|
219
224
|
|
220
|
-
|
221
|
-
|
225
|
+
ui.bold("#{plugin_name} plugin installed via source path reference, " \
|
226
|
+
"resolved to entry point #{entry_point}")
|
227
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
222
228
|
end
|
223
229
|
|
224
230
|
# Rationale for rubocop variances: It's a heuristics method, and will be full of
|
@@ -229,6 +235,7 @@ module InspecPlugins
|
|
229
235
|
given = given.expand_path # Resolve any relative paths
|
230
236
|
name_regex = /^(inspec|train)-/
|
231
237
|
versioned_regex = /^(inspec|train)-[a-z0-9\-\_]+-\d+\.\d+\.\d+$/
|
238
|
+
sha_ref_regex = /^(inspec|train)-[a-z0-9\-\_]+-[0-9a-f]{5,40}$/
|
232
239
|
|
233
240
|
# What are the last four things like?
|
234
241
|
parts = [
|
@@ -257,14 +264,14 @@ module InspecPlugins
|
|
257
264
|
# In that case, we'll have a version on the plugin name in part 0
|
258
265
|
# /home/you/.gems/2.4.0/gems/inspec-something-3.45.1/lib/inspec-something.rb
|
259
266
|
# parts index: ^0^ ^1^ ^2^ ^3^
|
260
|
-
if parts[0] =~ versioned_regex && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3] == ".rb"
|
267
|
+
if (parts[0] =~ versioned_regex || parts[0] =~ sha_ref_regex) && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3] == ".rb"
|
261
268
|
return given.to_s
|
262
269
|
end
|
263
270
|
|
264
271
|
# Case 4: Like case 3, but missing the .rb
|
265
272
|
# /home/you/.gems/2.4.0/gems/inspec-something-3.45.1/lib/inspec-something
|
266
273
|
# parts index: ^0^ ^1^ ^2^ ^3^ (empty)
|
267
|
-
if parts[0] =~ versioned_regex && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3].empty?
|
274
|
+
if (parts[0] =~ versioned_regex || parts[0] =~ sha_ref_regex) && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3].empty?
|
268
275
|
return given.to_s + ".rb"
|
269
276
|
end
|
270
277
|
|
@@ -279,8 +286,10 @@ module InspecPlugins
|
|
279
286
|
|
280
287
|
# Well, if we got here, parts[2] matches an inspec/train prefix, but we have no idea about anything.
|
281
288
|
# Give up.
|
282
|
-
|
283
|
-
|
289
|
+
ui.red("Unrecognizable plugin structure - #{parts[2]} - When " \
|
290
|
+
"installing from a path, please provide the path of the " \
|
291
|
+
"entry point file - installation failed.")
|
292
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
284
293
|
end
|
285
294
|
|
286
295
|
def install_from_path__probe_load(entry_point, plugin_name)
|
@@ -288,9 +297,11 @@ module InspecPlugins
|
|
288
297
|
begin
|
289
298
|
require entry_point
|
290
299
|
rescue LoadError => ex
|
291
|
-
|
292
|
-
|
293
|
-
|
300
|
+
ui.red("Plugin contains errors - #{plugin_name} - Encountered " \
|
301
|
+
"errors while trying to test load the plugin entry point, " \
|
302
|
+
"resolved to #{entry_point} - installation failed")
|
303
|
+
ui.plain ex.message
|
304
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
294
305
|
end
|
295
306
|
|
296
307
|
# OK, the wheels didn't fall off. But is it a plugin?
|
@@ -299,13 +310,19 @@ module InspecPlugins
|
|
299
310
|
# And the registry is keyed on Strings
|
300
311
|
registry_key = plugin_name.to_s.sub(/^train-/, "")
|
301
312
|
unless Train::Plugins.registry.key?(registry_key)
|
302
|
-
|
303
|
-
|
313
|
+
ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
|
314
|
+
"probe-loading the supposed plugin, it did not register " \
|
315
|
+
"itself to Train. Ensure something inherits from " \
|
316
|
+
"'Train.plugin(1)' - installation failed.")
|
317
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
304
318
|
end
|
305
319
|
else
|
306
320
|
unless registry.known_plugin?(plugin_name.to_sym)
|
307
|
-
|
308
|
-
|
321
|
+
ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
|
322
|
+
"probe-loading the supposed plugin, it did not register " \
|
323
|
+
"itself to InSpec. Ensure something inherits from " \
|
324
|
+
"'Inspec.plugin(2)' - installation failed.")
|
325
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
309
326
|
end
|
310
327
|
end
|
311
328
|
end
|
@@ -325,8 +342,9 @@ module InspecPlugins
|
|
325
342
|
post_installed_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
|
326
343
|
new_version = (post_installed_versions - pre_installed_versions).first
|
327
344
|
|
328
|
-
|
329
|
-
|
345
|
+
ui.bold("#{plugin_name} plugin, version #{new_version}, installed " \
|
346
|
+
"from rubygems.org")
|
347
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
330
348
|
end
|
331
349
|
|
332
350
|
def install_from_remote_gem_verson_preflight_check(plugin_name, requested_version, pre_installed_versions)
|
@@ -348,38 +366,50 @@ module InspecPlugins
|
|
348
366
|
they_explicitly_asked_for_a_version = !options[:version].nil?
|
349
367
|
what_we_would_install_is_already_installed = pre_installed_versions.include?(requested_version)
|
350
368
|
if what_we_would_install_is_already_installed && they_explicitly_asked_for_a_version
|
351
|
-
|
369
|
+
ui.red("Plugin already installed at requested version - plugin " \
|
370
|
+
"#{plugin_name} #{requested_version} - refusing to install.")
|
352
371
|
elsif what_we_would_install_is_already_installed && !they_explicitly_asked_for_a_version
|
353
|
-
|
372
|
+
ui.red("Plugin already installed at latest version - plugin " \
|
373
|
+
"#{plugin_name} #{requested_version} - refusing to install.")
|
354
374
|
else
|
355
375
|
# There are existing versions installed, but none of them are what was requested
|
356
|
-
|
376
|
+
ui.red("Update required - plugin #{plugin_name}, requested " \
|
377
|
+
"#{requested_version}, have " \
|
378
|
+
"#{pre_installed_versions.join(', ')}; use `inspec " \
|
379
|
+
"plugin update` - refusing to install.")
|
357
380
|
end
|
358
381
|
|
359
|
-
exit
|
382
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
360
383
|
end
|
361
384
|
|
362
385
|
# Rationale for RuboCop variance: This is a one-line method with heavy UX-focused error handling.
|
363
386
|
def install_attempt_install(plugin_name) # rubocop: disable Metrics/AbcSize
|
364
387
|
installer.install(plugin_name, version: options[:version])
|
365
388
|
rescue Inspec::Plugin::V2::PluginExcludedError => ex
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
389
|
+
ui.red("Plugin on Exclusion List - #{plugin_name} is listed as an " \
|
390
|
+
"incompatible gem - refusing to install.")
|
391
|
+
ui.plain("Rationale: #{ex.details.rationale}")
|
392
|
+
ui.plain("Exclusion list location: " +
|
393
|
+
File.join(Inspec.src_root, "etc", "plugin_filters.json"))
|
394
|
+
ui.plain("If you disagree with this determination, please accept " \
|
395
|
+
"our apologies for the misunderstanding, and open an issue " \
|
396
|
+
"at https://github.com/inspec/inspec/issues/new")
|
397
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
371
398
|
rescue Inspec::Plugin::V2::InstallError
|
372
399
|
raise if Inspec::Log.level == :debug
|
373
400
|
|
374
401
|
results = installer.search(plugin_name, exact: true)
|
375
402
|
if results.empty?
|
376
|
-
|
403
|
+
ui.red("No such plugin gem #{plugin_name} could be found on " \
|
404
|
+
"rubygems.org - installation failed.")
|
377
405
|
elsif options[:version] && !results[plugin_name].include?(options[:version])
|
378
|
-
|
406
|
+
ui.red("No such version - #{plugin_name} exists, but no such " \
|
407
|
+
"version #{options[:version]} found on rubygems.org - " \
|
408
|
+
"installation failed.")
|
379
409
|
else
|
380
|
-
|
410
|
+
ui.red("Unknown error occured - installation failed.")
|
381
411
|
end
|
382
|
-
exit
|
412
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
383
413
|
end
|
384
414
|
|
385
415
|
#==================================================================#
|
@@ -390,11 +420,14 @@ module InspecPlugins
|
|
390
420
|
# Check for path install
|
391
421
|
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
|
392
422
|
if !status
|
393
|
-
|
394
|
-
exit
|
423
|
+
ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} - update failed")
|
424
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
395
425
|
elsif status.installation_type == :path
|
396
|
-
|
397
|
-
|
426
|
+
ui.plain("#{ui.red('Cannot update path-based install:')} " \
|
427
|
+
"#{plugin_name} is installed via path reference; " \
|
428
|
+
"use `inspec plugin uninstall` to remove - refusing to" \
|
429
|
+
"update")
|
430
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
398
431
|
end
|
399
432
|
end
|
400
433
|
|
@@ -403,8 +436,10 @@ module InspecPlugins
|
|
403
436
|
latest_version = latest_version[plugin_name]&.last
|
404
437
|
|
405
438
|
if pre_update_versions.include?(latest_version)
|
406
|
-
|
407
|
-
|
439
|
+
ui.plain("#{ui.red('Already installed at latest version:')} " \
|
440
|
+
"#{plugin_name} is at #{latest_version}, which the " \
|
441
|
+
"latest - refusing to update")
|
442
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
408
443
|
end
|
409
444
|
end
|
410
445
|
|
@@ -421,8 +456,10 @@ module InspecPlugins
|
|
421
456
|
|
422
457
|
def check_plugin_name(plugin_name, action)
|
423
458
|
unless plugin_name =~ /^(inspec|train)-/
|
424
|
-
|
425
|
-
|
459
|
+
ui.red("Invalid plugin name - #{plugin_name} - All inspec " \
|
460
|
+
"plugins must begin with either 'inspec-' or 'train-' " \
|
461
|
+
"- #{action} failed.")
|
462
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
426
463
|
end
|
427
464
|
end
|
428
465
|
|
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.10.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Richter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: train-core
|
@@ -598,7 +598,6 @@ files:
|
|
598
598
|
- lib/inspec/utils/find_files.rb
|
599
599
|
- lib/inspec/utils/hash.rb
|
600
600
|
- lib/inspec/utils/json_log.rb
|
601
|
-
- lib/inspec/utils/latest_version.rb
|
602
601
|
- lib/inspec/utils/modulator.rb
|
603
602
|
- lib/inspec/utils/nginx_parser.rb
|
604
603
|
- lib/inspec/utils/object_traversal.rb
|
@@ -633,9 +632,6 @@ files:
|
|
633
632
|
- lib/plugins/inspec-habitat/lib/inspec-habitat.rb
|
634
633
|
- lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb
|
635
634
|
- lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb
|
636
|
-
- lib/plugins/inspec-habitat/templates/habitat/config/inspec_exec_config.json.erb
|
637
|
-
- lib/plugins/inspec-habitat/templates/habitat/default.toml.erb
|
638
|
-
- lib/plugins/inspec-habitat/templates/habitat/hooks/run.erb
|
639
635
|
- lib/plugins/inspec-habitat/templates/habitat/plan.sh.erb
|
640
636
|
- lib/plugins/inspec-init/README.md
|
641
637
|
- lib/plugins/inspec-init/lib/inspec-init.rb
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
require "open-uri"
|
3
|
-
|
4
|
-
class LatestInSpecVersion
|
5
|
-
# fetches the latest version from rubygems server
|
6
|
-
def latest
|
7
|
-
uri = URI("https://rubygems.org/api/v1/gems/inspec.json")
|
8
|
-
inspec_info = JSON.parse(uri.read(open_timeout: 1.5, read_timeout: 1.5))
|
9
|
-
inspec_info["version"]
|
10
|
-
rescue StandardError
|
11
|
-
nil
|
12
|
-
end
|
13
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"target_id": "{{ sys.member_id }}",
|
3
|
-
"reporter": {
|
4
|
-
"cli": {
|
5
|
-
"stdout": {{cfg.report_to_stdout}}
|
6
|
-
},
|
7
|
-
"json": {
|
8
|
-
"file": "{{pkg.svc_path}}/logs/inspec_last_run.json"
|
9
|
-
}{{#if cfg.automate.token ~}},
|
10
|
-
"automate" : {
|
11
|
-
"url": "{{cfg.automate.url}}/data-collector/v0/",
|
12
|
-
"token": "{{cfg.automate.token}}",
|
13
|
-
"node_name": "{{ sys.hostname }}",
|
14
|
-
"verify_ssl": false
|
15
|
-
}{{/if ~}}
|
16
|
-
}
|
17
|
-
{{#if cfg.automate.token }},
|
18
|
-
"compliance": {
|
19
|
-
"server" : "{{cfg.automate.url}}",
|
20
|
-
"token" : "{{cfg.automate.token}}",
|
21
|
-
"user" : "{{cfg.automate.user}}",
|
22
|
-
"insecure" : true,
|
23
|
-
"ent" : "automate"
|
24
|
-
}{{/if }}
|
25
|
-
}
|
@@ -1,32 +0,0 @@
|
|
1
|
-
#!/bin/sh
|
2
|
-
|
3
|
-
exec 2>&1
|
4
|
-
|
5
|
-
CONFIG="{{pkg.svc_config_path}}/inspec_exec_config.json"
|
6
|
-
INTERVAL="{{cfg.interval}}"
|
7
|
-
LOG_FILE="{{pkg.svc_path}}/logs/inspec_log.txt"
|
8
|
-
PROFILE_IDENT="{{pkg.origin}}/{{pkg.name}}"
|
9
|
-
PROFILE_PATH="{{pkg.path}}/{{pkg.name}}-{{pkg.version}}.tar.gz"
|
10
|
-
|
11
|
-
while true; do
|
12
|
-
echo "Executing ${PROFILE_IDENT}"
|
13
|
-
exec <%= Inspec::Dist::EXEC_NAME %> exec ${PROFILE_PATH} --json-config ${CONFIG} 2>&1 | tee ${LOG_FILE}
|
14
|
-
|
15
|
-
exit_code=$?
|
16
|
-
if [ $exit_code -eq 1 ]; then
|
17
|
-
echo "<%= Inspec::Dist::PRODUCT_NAME %> run failed."
|
18
|
-
else
|
19
|
-
echo "<%= Inspec::Dist::PRODUCT_NAME %> run completed successfully."
|
20
|
-
if [ $exit_code -eq 0 ]; then
|
21
|
-
echo "No controls failed or were skipped."
|
22
|
-
elif [ $exit_code -eq 100 ]; then
|
23
|
-
echo "At least 1 control failed."
|
24
|
-
elif [ $exit_code -eq 101 ]; then
|
25
|
-
echo "No controls failed but at least 1 skipped."
|
26
|
-
fi
|
27
|
-
fi
|
28
|
-
echo "Results are logged here: ${LOG_FILE}"
|
29
|
-
|
30
|
-
echo "Sleeping for ${INTERVAL} seconds"
|
31
|
-
sleep ${INTERVAL}
|
32
|
-
done
|