diff --git a/.expeditor/verify.pipeline.yml b/.expeditor/verify.pipeline.yml index 0fb7d6d25..f4527739a 100644 --- a/.expeditor/verify.pipeline.yml +++ b/.expeditor/verify.pipeline.yml @@ -17,14 +17,6 @@ steps: docker: image: ruby:2.6 - - label: run-tests-ruby-2.4 - command: - - /workdir/.expeditor/buildkite/verify.sh - expeditor: - executor: - docker: - image: ruby:2.4 - - label: run-tests-ruby-2.5 command: - /workdir/.expeditor/buildkite/verify.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dfecbb45..3f6ee7cc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,26 @@ # Change Log - -## Unreleased + +## [v4.23.24](https://github.com/inspec/inspec/tree/v4.23.24) (2020-12-01) #### Merged Pull Requests -- Update Codeowners file for Docs [#5298](https://github.com/inspec/inspec/pull/5298) ([mjingle](https://github.com/mjingle)) +- Fix escaping of Windows package names [#5323](https://github.com/inspec/inspec/pull/5323) ([ramereth](https://github.com/ramereth)) ### Changes since 4.23.15 release +#### New Features +- InSpec Cloud: Reporting by Resource [#5241](https://github.com/inspec/inspec/pull/5241) ([Schwad](https://github.com/Schwad)) + +#### Bug Fixes +- Don't reload plugins if load_all is called repeatedly [#5308](https://github.com/inspec/inspec/pull/5308) ([clintoncwolfe](https://github.com/clintoncwolfe)) + #### Merged Pull Requests +- Fix escaping of Windows package names [#5323](https://github.com/inspec/inspec/pull/5323) ([ramereth](https://github.com/ramereth)) +- Drop EOL Ruby 2.4 from testing, Fix Ruby 2.5 Gem build [#5321](https://github.com/inspec/inspec/pull/5321) ([clintoncwolfe](https://github.com/clintoncwolfe)) +- Update Ruby to 2.7.2 [#5281](https://github.com/inspec/inspec/pull/5281) ([tas50](https://github.com/tas50)) +- grub_conf - handle no menuentry config [#5306](https://github.com/inspec/inspec/pull/5306) ([james-stocks](https://github.com/james-stocks)) - Update Codeowners file for Docs [#5298](https://github.com/inspec/inspec/pull/5298) ([mjingle](https://github.com/mjingle)) - Bumps parallel for ruby 2.4 issue [#5304](https://github.com/inspec/inspec/pull/5304) ([Schwad](https://github.com/Schwad)) - replace deprecated attributes section with inputs [#5295](https://github.com/inspec/inspec/pull/5295) ([KonradSchieban](https://github.com/KonradSchieban)) diff --git a/Gemfile b/Gemfile index 56ddae642..af32fb28f 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,11 @@ gem "inspec-bin", path: "./inspec-bin" gem "ffi", ">= 1.9.14", "!= 1.13.0" +if Gem.ruby_version.to_s.start_with?("2.5") + # 16.7.23 required ruby 2.6+ + gem "chef-utils", "< 16.7.23" # TODO: remove when we drop ruby 2.5 +end + group :omnibus do gem "rb-readline" gem "appbundler" diff --git a/VERSION b/VERSION index 9352eb456..b9dece1b1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.23.19 \ No newline at end of file +4.23.24 \ No newline at end of file diff --git a/dev-docs/plugins.md b/dev-docs/plugins.md index 6fd713f02..ee5d3360b 100644 --- a/dev-docs/plugins.md +++ b/dev-docs/plugins.md @@ -486,6 +486,7 @@ The `run_data` object contains all data from the Chef InSpec run. Here is an ove v0.1.0 - Initial version v0.2.0 - added `run_data.profiles[0].inputs[0].options.sensitive` +v0.3.0 - added resource_name && params ## Implementing Input Plugins diff --git a/inspec-bin/lib/inspec-bin/version.rb b/inspec-bin/lib/inspec-bin/version.rb index 48d1d8070..90dd76a2b 100644 --- a/inspec-bin/lib/inspec-bin/version.rb +++ b/inspec-bin/lib/inspec-bin/version.rb @@ -1,5 +1,5 @@ # This file managed by automation - do not edit manually module InspecBin INSPECBIN_ROOT = File.expand_path("../..", __FILE__) - VERSION = "4.23.19".freeze + VERSION = "4.23.24".freeze end diff --git a/lib/inspec/formatters/base.rb b/lib/inspec/formatters/base.rb index 72d99d2c0..0dabb28ea 100644 --- a/lib/inspec/formatters/base.rb +++ b/lib/inspec/formatters/base.rb @@ -159,6 +159,14 @@ module Inspec::Formatters resource_title: example.metadata[:described_class] || example.metadata[:example_group][:description], expectation_message: format_expectation_message(example), waiver_data: example.metadata[:waiver_data], + # This enforces the resource name as expected based off of the class + # name. However, if we wanted the `name` attribute against the class + # to be canonical for this case (consider edge cases!) we would use + # example.metadata[:described_class].instance_variable_get(:@__resource_name__)&.to_s + resource_class: example.metadata[:described_class].class.superclass.name, + # This is a raw grep of the text passed to the resource in any format, + # and is used to enforce near-uniqueness against the resource. + resource_params: find_resource_params(example.metadata[:described_class]), } unless (pid = example.metadata[:profile_id]).nil? @@ -174,6 +182,14 @@ module Inspec::Formatters res end + def find_resource_params(example) + if example.class.ancestors.include?(Inspec::Resource) + example.instance_variable_get(:@resource_params) + else + [] + end + end + def format_expectation_message(example) if (example.metadata[:example_group][:description_args].first == example.metadata[:example_group][:described_class]) || example.metadata[:example_group][:described_class].nil? diff --git a/lib/inspec/plugin/v2/loader.rb b/lib/inspec/plugin/v2/loader.rb index 5887625d7..4dcb689d1 100644 --- a/lib/inspec/plugin/v2/loader.rb +++ b/lib/inspec/plugin/v2/loader.rb @@ -50,6 +50,11 @@ module Inspec::Plugin::V2 # we want to allow "sidecar loading", in which case a plugin may add an entry to the registry. registry.plugin_names.dup.each do |plugin_name| plugin_details = registry[plugin_name] + + # Under some conditions (kitchen-inspec with multiple test suites, for example), this may be + # called multple times. Don't reload anything. + next if plugin_details.loaded + # We want to capture literally any possible exception here, since we are storing them. # rubocop: disable Lint/RescueException begin diff --git a/lib/inspec/reporters/json.rb b/lib/inspec/reporters/json.rb index 839bcd929..b5138c075 100644 --- a/lib/inspec/reporters/json.rb +++ b/lib/inspec/reporters/json.rb @@ -40,6 +40,8 @@ module Inspec::Reporters message: r[:message], exception: r[:exception], backtrace: r[:backtrace], + resource_class: r[:resource_class], + resource_params: r[:resource_params].to_s, }.reject { |_k, v| v.nil? } } end diff --git a/lib/inspec/resource.rb b/lib/inspec/resource.rb index a3751cfc3..4a9364b7a 100644 --- a/lib/inspec/resource.rb +++ b/lib/inspec/resource.rb @@ -108,6 +108,7 @@ module Inspec # Infrastructure / Bookkeeping def self.__register(name, resource_klass) + # This has bitten us and should be a great candidate to remove in InSpec5 cl = Class.new(resource_klass) do # TODO: remove # As best I can figure out, this anonymous class only exists # because we're trying to avoid having resources with @@ -116,6 +117,7 @@ module Inspec # documentation. def initialize(backend, name, *args) supersuper_initialize(backend, name) do + @resource_params = args super(*args) end end diff --git a/lib/inspec/resources/grub_conf.rb b/lib/inspec/resources/grub_conf.rb index 28cfad6ac..a71ddb4ed 100644 --- a/lib/inspec/resources/grub_conf.rb +++ b/lib/inspec/resources/grub_conf.rb @@ -29,7 +29,7 @@ module Inspec::Resources @content = read_file(@conf_path) @kernel = kernel || "default" rescue UnknownGrubConfig - skip_resource "The `grub_config` resource is not supported on your OS yet." + skip_resource "The `grub_conf` resource is not yet supported on the target OS #{inspec.os[:name]}." end def config_for_platform(path) @@ -77,6 +77,7 @@ module Inspec::Resources def grub2_parse_kernel_lines(content, conf) menu_entries = extract_menu_entries(content) + return {} if menu_entries.empty? if @kernel == "default" default_menu_entry(menu_entries, conf["GRUB_DEFAULT"]) diff --git a/lib/inspec/resources/package.rb b/lib/inspec/resources/package.rb index 68e4060e1..3874c091f 100644 --- a/lib/inspec/resources/package.rb +++ b/lib/inspec/resources/package.rb @@ -314,7 +314,7 @@ module Inspec::Resources # Find the package cmd = inspec.command <<-EOF.gsub(/^\s*/, "") Get-ItemProperty (@("#{search_paths.join('", "')}") | Where-Object { Test-Path $_ }) | - Where-Object { $_.DisplayName -match "^\s*#{package_name.shellescape}\.*" -or $_.PSChildName -match "^\s*#{package_name.shellescape}\.*" } | + Where-Object { $_.DisplayName -like "#{package_name}" -or $_.PSChildName -like "#{package_name}" } | Select-Object -Property DisplayName,DisplayVersion | ConvertTo-Json EOF diff --git a/lib/inspec/run_data.rb b/lib/inspec/run_data.rb index 5011efd33..3fbf1e129 100644 --- a/lib/inspec/run_data.rb +++ b/lib/inspec/run_data.rb @@ -47,7 +47,7 @@ module Inspec # core reporters have been migrated to plugins. It is probable that new data elements # and new Hash compatibility behavior will be added during the core reporter plugin # conversion process. - SCHEMA_VERSION = "0.2.0".freeze + SCHEMA_VERSION = "0.3.0".freeze def self.compatible_schema?(constraints) reqs = Gem::Requirement.create(constraints) diff --git a/lib/inspec/run_data/result.rb b/lib/inspec/run_data/result.rb index 92d1a4265..b6c8a2de9 100644 --- a/lib/inspec/run_data/result.rb +++ b/lib/inspec/run_data/result.rb @@ -8,6 +8,7 @@ module Inspec :run_time, # Float seconds execution time :skip_message, # String :start_time, # DateTime + :resource_params, # What is passed to the resource as a raw grep :status, # String :resource_title, # Ugly internals # :waiver_data, # Undocumented tramp data / not exposed in this API @@ -34,6 +35,7 @@ module Inspec end self.resource_name = raw_res_data[:resource_title].instance_variable_get(:@__resource_name__)&.to_s + self.resource_params = raw_res_data[:resource_title].instance_variable_get(:@grep)&.to_s end end end diff --git a/lib/inspec/schema.rb b/lib/inspec/schema.rb index 61dcfd3fa..32711518e 100644 --- a/lib/inspec/schema.rb +++ b/lib/inspec/schema.rb @@ -56,6 +56,7 @@ module Inspec "code_desc" => { "type" => "string" }, "run_time" => { "type" => "number" }, "start_time" => { "type" => "string" }, + "resource_class" => { "type" => "string", "optional" => true }, "skip_message" => { "type" => "string", "optional" => true }, "resource" => { "type" => "string", "optional" => true }, "message" => { "type" => "string", "optional" => true }, @@ -194,6 +195,7 @@ module Inspec "profile_sha256" => { "type" => "string" }, "status" => { "type" => "string" }, "code_desc" => { "type" => "string" }, + "resource_class" => { "type" => "string", "optional" => true }, "skip_message" => { "type" => "string", "optional" => true }, "resource" => { "type" => "string", "optional" => true }, "message" => { "type" => "string", "optional" => true }, diff --git a/lib/inspec/version.rb b/lib/inspec/version.rb index baf049807..1cccef1f3 100644 --- a/lib/inspec/version.rb +++ b/lib/inspec/version.rb @@ -1,3 +1,3 @@ module Inspec - VERSION = "4.23.19".freeze + VERSION = "4.23.24".freeze end diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb index 6296b33ec..25c836ef9 100644 --- a/omnibus_overrides.rb +++ b/omnibus_overrides.rb @@ -3,4 +3,4 @@ # grab the current train release from rubygems.org train_stable = /^train \((.*)\)/.match(`gem list ^train$ --remote`)[1] override "train", version: "v#{train_stable}" -override "ruby", version: "2.6.6" +override "ruby", version: "2.7.2" diff --git a/test/fixtures/reporters/json_merged_output b/test/fixtures/reporters/json_merged_output index 10f91b577..49dd8349d 100644 --- a/test/fixtures/reporters/json_merged_output +++ b/test/fixtures/reporters/json_merged_output @@ -61,7 +61,8 @@ "status": "passed", "code_desc": "File /etc/hosts mode should eq 420", "run_time": 0.031503, - "start_time": "2018-07-30T08:56:41-04:00" + "start_time": "2018-07-30T08:56:41-04:00", + "resource_params": "" } ] }, @@ -101,7 +102,8 @@ "status": "passed", "code_desc": "File /etc/passwd should exist", "run_time": 0.003954, - "start_time": "2018-07-30T08:56:41-04:00" + "start_time": "2018-07-30T08:56:41-04:00", + "resource_params": "" } ] }, @@ -131,7 +133,8 @@ "run_time": 2.9e-05, "start_time": "2018-07-30T08:56:41-04:00", "resource": "Operating System Detection", - "skip_message": "Skipped control due to only_if condition." + "skip_message": "Skipped control due to only_if condition.", + "resource_params": "" } ] } diff --git a/test/fixtures/reporters/json_output b/test/fixtures/reporters/json_output index 6f1168fa4..fcd0474fb 100644 --- a/test/fixtures/reporters/json_output +++ b/test/fixtures/reporters/json_output @@ -1 +1 @@ -{"platform":{"name":"mac_os_x","release":"17.2.0"},"profiles":[{"name":"long_commands","version":"0.1.0","sha256":"4f816f8cf18f165f05f1cf20936aaad06a15287de3f578891197647ca05c7df4","title":"InSpec Profile","maintainer":"The Authors","summary":"An InSpec Compliance Profile","license":"Apache-2.0","copyright":"The Authors","copyright_email":"you@example.com","supports":[{"os-family":"bds"},{"os-name":"mac_os_x","release":"17.*"}],"attributes":[],"groups":[{"id":"controls/example.rb","controls":["(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","tmp-1.0","(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)"],"title":"sample section"},{"id":"controls/run_command.rb","controls":["(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)"]}],"controls":[{"id":"(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"waiver_data":{},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500"}]},{"id":"tmp-1.0","title":"Create /tmp directory","desc":"An optional description...","descriptions":[{"label":"default","data":"An optional description..."}],"impact":0.7,"refs":[],"tags":{},"code":"control 'tmp-1.0' do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title 'Create /tmp directory' # A human-readable title\n desc 'An optional description...'\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","waiver_data":{},"source_location":{"line":12,"ref":"../inspec-demo/_test/long_commands/controls/example.rb"},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500"}]},{"id":"(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","waiver_data":{},"source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"failed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","message":"rubocop is not installed"}]},{"id":"(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","waiver_data":{},"source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500"}]}]}],"statistics":{"duration":0.039182},"version":"1.49.2"} +{"platform":{"name":"mac_os_x","release":"17.2.0"},"profiles":[{"name":"long_commands","version":"0.1.0","sha256":"4f816f8cf18f165f05f1cf20936aaad06a15287de3f578891197647ca05c7df4","title":"InSpec Profile","maintainer":"The Authors","summary":"An InSpec Compliance Profile","license":"Apache-2.0","copyright":"The Authors","copyright_email":"you@example.com","supports":[{"os-family":"bds"},{"os-name":"mac_os_x","release":"17.*"}],"attributes":[],"groups":[{"id":"controls/example.rb","controls":["(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","tmp-1.0","(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)"],"title":"sample section"},{"id":"controls/run_command.rb","controls":["(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)"]}],"controls":[{"id":"(generated from example.rb:7 871cd54043069c5c4f6e382fd5627830)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"waiver_data":{},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.002058,"start_time":"2018-01-05 11:43:04 -0500","resource_params":""}]},{"id":"tmp-1.0","title":"Create /tmp directory","desc":"An optional description...","descriptions":[{"label":"default","data":"An optional description..."}],"impact":0.7,"refs":[],"tags":{},"code":"control 'tmp-1.0' do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title 'Create /tmp directory' # A human-readable title\n desc 'An optional description...'\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","waiver_data":{},"source_location":{"line":12,"ref":"../inspec-demo/_test/long_commands/controls/example.rb"},"results":[{"status":"passed","code_desc":"File /tmp should be directory","run_time":0.000102,"start_time":"2018-01-05 11:43:04 -0500","resource_params":""}]},{"id":"(generated from example.rb:21 2ff474c5357e7070f4c3efa932032dcb)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","waiver_data":{},"source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"failed","code_desc":"gem package rubocop should be installed","run_time":0.000168,"start_time":"2018-01-05 11:43:04 -0500","message":"rubocop is not installed","resource_params":""}]},{"id":"(generated from run_command.rb:5 a411d4ded1530b2f48170840e1127584)","title":null,"desc":null,"descriptions":[],"impact":0.5,"refs":[],"tags":{},"code":"","waiver_data":{},"source_location":{"line":89,"ref":"/Users/jquick/Chef/inspec/lib/inspec/control_eval_context.rb"},"results":[{"status":"passed","code_desc":"Command whoami stdout should eq \"jquick\\n\"","run_time":0.034938,"start_time":"2018-01-05 11:43:04 -0500","resource_params":""}]}]}],"statistics":{"duration":0.039182},"version":"1.49.2"} diff --git a/test/fixtures/reporters/yaml_output b/test/fixtures/reporters/yaml_output index 7c416f5fc..b742290d6 100644 --- a/test/fixtures/reporters/yaml_output +++ b/test/fixtures/reporters/yaml_output @@ -30,6 +30,7 @@ :code_desc: File /tmp should exist :run_time: 0.001313935 :start_time: '2018-05-31T16:22:19+05:30' + :resource_params: '' :statistics: :duration: 0.002678506 :version: 2.1.83 diff --git a/test/functional/inspec_exec_json_test.rb b/test/functional/inspec_exec_json_test.rb index 7d30d4f1f..e18f81872 100644 --- a/test/functional/inspec_exec_json_test.rb +++ b/test/functional/inspec_exec_json_test.rb @@ -187,6 +187,29 @@ describe "inspec exec with json formatter" do _(ex1["impact"]).must_equal 0.7 end + describe "results" do + let(:result) { ex1["results"][0] } + let(:result2) { ex2["results"][0] } + + it "has a code_desc" do + _(result["code_desc"]).must_equal "File / is expected to be directory" + end + + it "has a resource_class" do + _(result["resource_class"]).must_equal "file" + end + + # This is a raw grep of the argument(s) passed to the resource, currently + # used by automate to identify and sort differing resources + it "has a resource_params that's empty" do + _(result["resource_params"]).must_equal "[\"/\"]" + end + + it "has a resource_params with values" do + _(result2["resource_params"]).must_equal "[\"/\"]" + end + end + it "has all the metadata" do actual = profile.dup key = actual.delete("controls") diff --git a/test/helpers/mock_loader.rb b/test/helpers/mock_loader.rb index a66fe84f2..2401b653a 100644 --- a/test/helpers/mock_loader.rb +++ b/test/helpers/mock_loader.rb @@ -271,7 +271,7 @@ class MockLoader "rmsock f0000000000000001 tcpcb" => cmd.call("rmsock-f0001"), "rmsock f0000000000000002 tcpcb" => cmd.call("rmsock-f0002"), # packages on windows - "f7718ece69188bb19cd458e2aeab0a8d968f3d40ac2f4199e21cc976f8db5ef6" => cmd.call("get-item-property-package"), + "6785190b3df7291a7622b0b75b0217a9a78bd04690bc978df51ae17ec852a282" => cmd.call("get-item-property-package"), # service status upstart on ubuntu "initctl status ssh" => cmd.call("initctl-status-ssh"), # upstart version on ubuntu diff --git a/test/unit/reporters/json_automate_test.rb b/test/unit/reporters/json_automate_test.rb index 81a16fced..a33fb8e03 100644 --- a/test/unit/reporters/json_automate_test.rb +++ b/test/unit/reporters/json_automate_test.rb @@ -15,7 +15,6 @@ describe Inspec::Reporters::JsonAutomate do report.render actual = JSON.parse(report.rendered_output, symbolize_names: true) - _(actual).must_equal output end end diff --git a/test/unit/reporters/json_test.rb b/test/unit/reporters/json_test.rb index c81bba920..f9bc20d49 100644 --- a/test/unit/reporters/json_test.rb +++ b/test/unit/reporters/json_test.rb @@ -55,6 +55,7 @@ describe Inspec::Reporters::Json do code_desc: "File /tmp should be directory", run_time: 0.002058, start_time: "2018-01-05 11:43:04 -0500", + resource_params: "", } result = report.send(:profile_results, control) _(result.first).must_equal hash @@ -68,6 +69,7 @@ describe Inspec::Reporters::Json do code_desc: "File /tmp should be directory", run_time: 0.002058, start_time: "2018-01-05 11:43:04 -0500", + resource_params: "", resource: "File", skip_message: "skipping", }