inspec-core 2.2.102 → 2.2.112

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -7
  3. data/docs/profiles.md +9 -0
  4. data/docs/resources/gem.md.erb +24 -5
  5. data/docs/resources/mssql_session.md.erb +8 -0
  6. data/lib/inspec/plugin/v2/loader.rb +33 -7
  7. data/lib/inspec/reporters/json_automate.rb +1 -1
  8. data/lib/inspec/version.rb +1 -1
  9. data/lib/plugins/README.md +16 -0
  10. data/lib/plugins/inspec-artifact/lib/inspec-artifact/base.rb +162 -0
  11. data/lib/plugins/inspec-artifact/lib/inspec-artifact/cli.rb +114 -0
  12. data/lib/plugins/inspec-artifact/lib/inspec-artifact.rb +12 -0
  13. data/lib/plugins/inspec-artifact/test/functional/inspec_artifact_test.rb +46 -0
  14. data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +39 -0
  15. data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +394 -0
  16. data/lib/plugins/inspec-habitat/lib/inspec-habitat.rb +11 -0
  17. data/lib/plugins/inspec-habitat/test/unit/profile_test.rb +184 -0
  18. data/lib/{bundles → plugins}/inspec-init/README.md +0 -0
  19. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +28 -0
  20. data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +81 -0
  21. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/README.md +0 -0
  22. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/controls/example.rb +0 -0
  23. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/inspec.yml +0 -0
  24. data/lib/{bundles → plugins/inspec-init/lib}/inspec-init/templates/profile/libraries/.gitkeep +0 -0
  25. data/lib/plugins/inspec-init/lib/inspec-init.rb +12 -0
  26. data/lib/plugins/inspec-init/test/functional/inspec_init_test.rb +30 -0
  27. data/lib/plugins/shared/core_plugin_test_helper.rb +50 -0
  28. data/lib/resources/gem.rb +7 -1
  29. data/lib/resources/mssql_session.rb +4 -2
  30. metadata +21 -17
  31. data/lib/bundles/inspec-artifact/README.md +0 -1
  32. data/lib/bundles/inspec-artifact/cli.rb +0 -278
  33. data/lib/bundles/inspec-artifact.rb +0 -7
  34. data/lib/bundles/inspec-habitat/cli.rb +0 -37
  35. data/lib/bundles/inspec-habitat/log.rb +0 -10
  36. data/lib/bundles/inspec-habitat/profile.rb +0 -391
  37. data/lib/bundles/inspec-habitat.rb +0 -12
  38. data/lib/bundles/inspec-init/cli.rb +0 -39
  39. data/lib/bundles/inspec-init/renderer.rb +0 -79
  40. data/lib/bundles/inspec-init.rb +0 -12
@@ -1,391 +0,0 @@
1
- # encoding: utf-8
2
- # author: Adam Leff
3
-
4
- require 'inspec/profile_vendor'
5
- require 'mixlib/shellout'
6
- require 'tomlrb'
7
-
8
- module Habitat
9
- class Profile
10
- attr_reader :options, :path, :profile
11
-
12
- def self.create(path, options = {})
13
- creator = new(path, options)
14
- hart_file = creator.create
15
- creator.copy(hart_file)
16
- ensure
17
- creator.delete_work_dir
18
- end
19
-
20
- def self.setup(path)
21
- new(path).setup
22
- end
23
-
24
- def self.upload(path, options = {})
25
- uploader = new(path, options)
26
- uploader.upload
27
- ensure
28
- uploader.delete_work_dir
29
- end
30
-
31
- def initialize(path, options = {})
32
- @path = path
33
- @options = options
34
- @cli_config = nil
35
-
36
- log_level = options.fetch('log_level', 'info')
37
- Habitat::Log.level(log_level.to_sym)
38
- end
39
-
40
- def create
41
- Habitat::Log.info("Creating a Habitat artifact for profile: #{path}")
42
-
43
- validate_habitat_installed
44
- validate_habitat_origin
45
- create_profile_object
46
- verify_profile
47
- vendor_profile_dependencies
48
- copy_profile_to_work_dir
49
- create_habitat_directories(work_dir)
50
- create_plan(work_dir)
51
- create_run_hook(work_dir)
52
- create_settings_file(work_dir)
53
- create_default_config(work_dir)
54
-
55
- # returns the path to the .hart file in the work directory
56
- build_hart
57
- rescue => e
58
- Habitat::Log.debug(e.backtrace.join("\n"))
59
- exit_with_error(
60
- 'Unable to generate Habitat artifact.',
61
- "#{e.class} -- #{e.message}",
62
- )
63
- end
64
-
65
- def copy(hart_file)
66
- validate_output_dir
67
-
68
- Habitat::Log.info("Copying artifact to #{output_dir}...")
69
- copy_hart(hart_file)
70
- end
71
-
72
- def upload
73
- validate_habitat_auth_token
74
- hart_file = create
75
- upload_hart(hart_file)
76
- rescue => e
77
- Habitat::Log.debug(e.backtrace.join("\n"))
78
- exit_with_error(
79
- 'Unable to upload Habitat artifact.',
80
- "#{e.class} -- #{e.message}",
81
- )
82
- end
83
-
84
- def delete_work_dir
85
- Habitat::Log.debug("Deleting work directory #{work_dir}")
86
- FileUtils.rm_rf(work_dir) if Dir.exist?(work_dir)
87
- end
88
-
89
- def setup
90
- Habitat::Log.info("Setting up profile at #{path} for Habitat...")
91
- create_profile_object
92
- verify_profile
93
- vendor_profile_dependencies
94
- create_habitat_directories(path)
95
- create_plan(path)
96
- create_run_hook(path)
97
- create_settings_file(path)
98
- create_default_config(path)
99
- end
100
-
101
- private
102
-
103
- def create_profile_object
104
- @profile = Inspec::Profile.for_target(
105
- path,
106
- backend: Inspec::Backend.create(target: 'mock://'),
107
- )
108
- end
109
-
110
- def verify_profile
111
- Habitat::Log.info('Checking to see if the profile is valid...')
112
-
113
- unless profile.check[:summary][:valid]
114
- exit_with_error('Profile check failed. Please fix the profile before creating a Habitat artifact.')
115
- end
116
-
117
- Habitat::Log.info('Profile is valid.')
118
- end
119
-
120
- def vendor_profile_dependencies
121
- profile_vendor = Inspec::ProfileVendor.new(path)
122
- if profile_vendor.lockfile.exist? && profile_vendor.cache_path.exist?
123
- Habitat::Log.info("Profile's dependencies are already vendored, skipping vendor process.")
124
- else
125
- Habitat::Log.info("Vendoring the profile's dependencies...")
126
- profile_vendor.vendor!
127
-
128
- Habitat::Log.info('Ensuring all vendored content has read permissions...')
129
- profile_vendor.make_readable
130
-
131
- # refresh the profile object since the profile now has new files
132
- create_profile_object
133
- end
134
- end
135
-
136
- def validate_habitat_installed
137
- Habitat::Log.info('Checking to see if Habitat is installed...')
138
- cmd = Mixlib::ShellOut.new('hab --version')
139
- cmd.run_command
140
- exit_with_error('Unable to run Habitat commands.', cmd.stderr) if cmd.error?
141
- end
142
-
143
- def validate_habitat_origin
144
- exit_with_error(
145
- 'Unable to determine Habitat origin name.',
146
- 'Run `hab setup` or set the HAB_ORIGIN environment variable.',
147
- ) if habitat_origin.nil?
148
- end
149
-
150
- def validate_habitat_auth_token
151
- exit_with_error(
152
- 'Unable to determine Habitat auth token for publishing.',
153
- 'Run `hab setup` or set the HAB_AUTH_TOKEN environment variable.',
154
- ) if habitat_auth_token.nil?
155
- end
156
-
157
- def validate_output_dir
158
- exit_with_error("Output directory #{output_dir} is not a directory or does not exist.") unless
159
- File.directory?(output_dir)
160
- end
161
-
162
- def work_dir
163
- return @work_dir if @work_dir
164
-
165
- @work_dir ||= Dir.mktmpdir('inspec-habitat-exporter')
166
- Habitat::Log.debug("Generated work directory #{@work_dir}")
167
-
168
- @work_dir
169
- end
170
-
171
- def create_habitat_directories(parent_directory)
172
- [
173
- File.join(parent_directory, 'habitat'),
174
- File.join(parent_directory, 'habitat', 'config'),
175
- File.join(parent_directory, 'habitat', 'hooks'),
176
- ].each do |dir|
177
- Dir.mkdir(dir) unless Dir.exist?(dir)
178
- end
179
- end
180
-
181
- def copy_profile_to_work_dir
182
- Habitat::Log.info('Copying profile contents to the work directory...')
183
- profile.files.each do |f|
184
- src = File.join(profile.root_path, f)
185
- dst = File.join(work_dir, f)
186
- if File.directory?(f)
187
- Habitat::Log.debug("Creating directory #{dst}")
188
- FileUtils.mkdir_p(dst)
189
- else
190
- Habitat::Log.debug("Copying file #{src} to #{dst}")
191
- FileUtils.cp_r(src, dst)
192
- end
193
- end
194
- end
195
-
196
- def create_plan(directory)
197
- plan_file = File.join(directory, 'habitat', 'plan.sh')
198
- Habitat::Log.info("Generating Habitat plan at #{plan_file}...")
199
- File.write(plan_file, plan_contents)
200
- end
201
-
202
- def create_run_hook(directory)
203
- run_hook_file = File.join(directory, 'habitat', 'hooks', 'run')
204
- Habitat::Log.info("Generating a Habitat run hook at #{run_hook_file}...")
205
- File.write(run_hook_file, run_hook_contents)
206
- end
207
-
208
- def create_settings_file(directory)
209
- settings_file = File.join(directory, 'habitat', 'config', 'settings.sh')
210
- Habitat::Log.info("Generating a settings file at #{settings_file}...")
211
- File.write(settings_file, "SLEEP_TIME={{cfg.sleep_time}}\n")
212
- end
213
-
214
- def create_default_config(directory)
215
- default_toml = File.join(directory, 'habitat', 'default.toml')
216
- Habitat::Log.info("Generating Habitat's default.toml configuration...")
217
- File.write(default_toml, 'sleep_time = 300')
218
- end
219
-
220
- def build_hart
221
- Habitat::Log.info('Building our Habitat artifact...')
222
-
223
- env = {
224
- 'TERM' => 'vt100',
225
- 'HAB_ORIGIN' => habitat_origin,
226
- 'HAB_NONINTERACTIVE' => 'true',
227
- }
228
-
229
- env['RUST_LOG'] = 'debug' if Habitat::Log.level == :debug
230
-
231
- # TODO: Would love to use Mixlib::ShellOut here, but it doesn't
232
- # seem to preserve the STDIN tty, and docker gets angry.
233
- Dir.chdir(work_dir) do
234
- unless system(env, 'hab pkg build .')
235
- exit_with_error('Unable to build the Habitat artifact.')
236
- end
237
- end
238
-
239
- hart_files = Dir.glob(File.join(work_dir, 'results', '*.hart'))
240
-
241
- if hart_files.length > 1
242
- exit_with_error('More than one Habitat artifact was created which was not expected.')
243
- elsif hart_files.empty?
244
- exit_with_error('No Habitat artifact was created.')
245
- end
246
-
247
- hart_files.first
248
- end
249
-
250
- def copy_hart(working_dir_hart)
251
- hart_basename = File.basename(working_dir_hart)
252
- dst = File.join(output_dir, hart_basename)
253
- FileUtils.cp(working_dir_hart, dst)
254
-
255
- dst
256
- end
257
-
258
- def upload_hart(hart_file)
259
- Habitat::Log.info('Uploading the Habitat artifact to our Depot...')
260
-
261
- env = {
262
- 'TERM' => 'vt100',
263
- 'HAB_AUTH_TOKEN' => habitat_auth_token,
264
- 'HAB_NONINTERACTIVE' => 'true',
265
- }
266
-
267
- env['HAB_DEPOT_URL'] = ENV['HAB_DEPOT_URL'] if ENV['HAB_DEPOT_URL']
268
-
269
- cmd = Mixlib::ShellOut.new("hab pkg upload #{hart_file}", env: env)
270
- cmd.run_command
271
- if cmd.error?
272
- exit_with_error(
273
- 'Unable to upload Habitat artifact to the Depot.',
274
- cmd.stdout,
275
- cmd.stderr,
276
- )
277
- end
278
-
279
- Habitat::Log.info('Upload complete!')
280
- end
281
-
282
- def habitat_origin
283
- ENV['HAB_ORIGIN'] || habitat_cli_config['origin']
284
- end
285
-
286
- def habitat_auth_token
287
- ENV['HAB_AUTH_TOKEN'] || habitat_cli_config['auth_token']
288
- end
289
-
290
- def habitat_cli_config
291
- return @cli_config if @cli_config
292
-
293
- config_file = File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')
294
- return {} unless File.exist?(config_file)
295
-
296
- @cli_config = Tomlrb.load_file(config_file)
297
- end
298
-
299
- def output_dir
300
- options[:output_dir] || Dir.pwd
301
- end
302
-
303
- def exit_with_error(*errors)
304
- errors.each do |error_msg|
305
- Habitat::Log.error(error_msg)
306
- end
307
-
308
- exit 1
309
- end
310
-
311
- def package_name
312
- "inspec-profile-#{profile.name}"
313
- end
314
-
315
- def plan_contents
316
- plan = <<~EOL
317
- pkg_name=#{package_name}
318
- pkg_version=#{profile.version}
319
- pkg_origin=#{habitat_origin}
320
- pkg_deps=(chef/inspec core/ruby core/hab)
321
- pkg_svc_user=root
322
- EOL
323
-
324
- plan += "pkg_license='#{profile.metadata.params[:license]}'\n\n" if profile.metadata.params[:license]
325
-
326
- plan += <<~EOL
327
-
328
- do_build() {
329
- cp -vr $PLAN_CONTEXT/../* $HAB_CACHE_SRC_PATH/$pkg_dirname
330
- }
331
-
332
- do_install() {
333
- local profile_contents
334
- local excludes
335
- profile_contents=($(ls))
336
- excludes=(habitat results *.hart)
337
-
338
- for item in ${excludes[@]}; do
339
- profile_contents=(${profile_contents[@]/$item/})
340
- done
341
-
342
- mkdir ${pkg_prefix}/dist
343
- cp -r ${profile_contents[@]} ${pkg_prefix}/dist/
344
- }
345
- EOL
346
-
347
- plan
348
- end
349
-
350
- def run_hook_contents
351
- <<~EOL
352
- #!/bin/sh
353
-
354
- # redirect stderr to stdout
355
- # ultimately, we'd like to log this somewhere useful, but due to
356
- # https://github.com/habitat-sh/habitat/issues/2395, we need to
357
- # avoid doing that for now.
358
- exec 2>&1
359
-
360
- # InSpec will try to create a .cache directory in the user's home directory
361
- # so this needs to be someplace writeable by the hab user
362
- export HOME={{pkg.svc_var_path}}
363
-
364
- PROFILE_IDENT="{{pkg.origin}}/{{pkg.name}}"
365
- RESULTS_DIR="{{pkg.svc_var_path}}/inspec_results"
366
- RESULTS_FILE="${RESULTS_DIR}/{{pkg.name}}.json"
367
-
368
- # Create a directory for inspec formatter output
369
- mkdir -p {{pkg.svc_var_path}}/inspec_results
370
-
371
- while true; do
372
- echo "Executing InSpec for ${PROFILE_IDENT}"
373
- inspec exec {{pkg.path}}/dist --format=json > ${RESULTS_FILE}
374
-
375
- if [ $? -eq 0 ]; then
376
- echo "InSpec run completed successfully."
377
- else
378
- echo "InSpec run did not complete successfully. If you do not see any errors above,"
379
- echo "control failures were detected. Check the InSpec results here for details:"
380
- echo ${RESULTS_FILE}
381
- echo "Otherwise, troubleshoot any errors shown above."
382
- fi
383
-
384
- source {{pkg.svc_config_path}}/settings.sh
385
- echo "sleeping for ${SLEEP_TIME} seconds"
386
- sleep ${SLEEP_TIME}
387
- done
388
- EOL
389
- end
390
- end
391
- end
@@ -1,12 +0,0 @@
1
- # encoding: utf-8
2
- # author: Adam Leff
3
-
4
- libdir = File.dirname(__FILE__)
5
- $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
6
-
7
- module Habitat
8
- autoload :Log, 'inspec-habitat/log'
9
- autoload :Profile, 'inspec-habitat/profile'
10
- end
11
-
12
- require 'inspec-habitat/cli'
@@ -1,39 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'pathname'
4
- require_relative 'renderer'
5
- require 'inspec/base_cli'
6
-
7
- module Init
8
- class CLI < Inspec::BaseCLI
9
- namespace 'init'
10
-
11
- # TODO: find another solution, once https://github.com/erikhuda/thor/issues/261 is fixed
12
- def self.banner(command, _namespace = nil, _subcommand = false)
13
- "#{basename} #{subcommand_prefix} #{command.usage}"
14
- end
15
-
16
- def self.subcommand_prefix
17
- namespace
18
- end
19
-
20
- # Look in the 'template' directory, and register a subcommand
21
- # for each template directory found there.
22
- template_dir = File.join(File.dirname(__FILE__), 'templates')
23
- Dir.glob(File.join(template_dir, '*')) do |template|
24
- template_name = Pathname.new(template).relative_path_from(Pathname.new(template_dir)).to_s
25
-
26
- # register command for the template
27
- desc "#{template_name} NAME", "Create a new #{template_name}"
28
- option :overwrite, type: :boolean, default: false,
29
- desc: 'Overwrites existing directory'
30
- define_method template_name.to_sym do |name_for_new_structure|
31
- renderer = Init::Renderer.new(self, options)
32
- renderer.render_with_values(template_name, name: name_for_new_structure)
33
- end
34
- end
35
- end
36
-
37
- # register the subcommand to Inspec CLI registry
38
- Inspec::Plugins::CLI.add_subcommand(Init::CLI, 'init', 'init TEMPLATE ...', 'Scaffolds a new project', {})
39
- end
@@ -1,79 +0,0 @@
1
- require 'fileutils'
2
- require 'erb'
3
-
4
- module Init
5
- class Renderer
6
- # Creates a renderer able to render the given template type
7
- # 1. iterate over all files
8
- # 2. read content in erb
9
- # 3. write to full_destination_root_path
10
-
11
- attr_reader :overwrite_mode, :ui
12
- def initialize(cli_ui, cli_options = {})
13
- @ui = cli_ui
14
- @overwrite_mode = cli_options['overwrite']
15
- end
16
-
17
- # rubocop: disable Metrics/AbcSize
18
- def render_with_values(template_type, template_values = {})
19
- # look for template directory
20
- base_dir = File.join(File.dirname(__FILE__), 'templates', template_type)
21
- # prepare glob for all subdirectories and files
22
- template_glob = File.join(base_dir, '**', '{*,.*}')
23
- # Use the name attribute to define the path to the profile.
24
- profile_path = template_values[:name]
25
- # Use slashes (\, /) to split up the name into an Array then use the last entry
26
- # to reset the name of the profile.
27
- template_values[:name] = template_values[:name].split(%r{\\|\/}).last
28
- # Generate the full full_destination_root_path path on disk
29
- full_destination_root_path = Pathname.new(Dir.pwd).join(profile_path)
30
- ui.plain_text "Create new #{template_type} at #{ui.mark_text(full_destination_root_path)}"
31
-
32
- # check that the directory does not exist
33
- if File.exist?(full_destination_root_path) && !overwrite_mode
34
- ui.plain_text "#{ui.mark_text(full_destination_root_path)} exists already, use --overwrite"
35
- ui.exit(1)
36
- end
37
-
38
- # ensure that full_destination_root_path directory is available
39
- FileUtils.mkdir_p(full_destination_root_path)
40
-
41
- # iterate over files and write to full_destination_root_path
42
- Dir.glob(template_glob) do |file|
43
- relative_destination_item_path = Pathname.new(file).relative_path_from(Pathname.new(base_dir))
44
- full_destination_item_path = Pathname.new(full_destination_root_path).join(relative_destination_item_path)
45
- if File.directory?(file)
46
- ui.li "Create directory #{ui.mark_text(relative_destination_item_path)}"
47
- FileUtils.mkdir_p(full_destination_item_path)
48
- elsif File.file?(file)
49
- ui.li "Create file #{ui.mark_text(relative_destination_item_path)}"
50
- # read & render content
51
- content = render(File.read(file), template_values)
52
- # write file content
53
- File.write(full_destination_item_path, content)
54
- else
55
- ui.plain_text "Ignore #{file}, because its not an file or directoy"
56
- end
57
- end
58
- end
59
- # rubocop: enable Metrics/AbcSize
60
-
61
- # This is a render helper to bind hash values to a ERB template
62
- # ERB provides result_with_hash in ruby 2.5.0+, which does exactly this
63
- def render(template_content, hash)
64
- # create a new binding class
65
- cls = Class.new do
66
- hash.each do |key, value|
67
- define_method key.to_sym do
68
- value
69
- end
70
- end
71
- # expose binding
72
- define_method :bind do
73
- binding
74
- end
75
- end
76
- ERB.new(template_content).result(cls.new.bind)
77
- end
78
- end
79
- end
@@ -1,12 +0,0 @@
1
- # encoding: utf-8
2
- # author: Christoph Hartmann
3
- # author: Dominik Richter
4
-
5
- libdir = File.dirname(__FILE__)
6
- $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
7
-
8
- module Init
9
- autoload :Profile, 'inspec-init/profile'
10
- end
11
-
12
- require 'inspec-init/cli'