From ddcb09666624407f4a1707d8347582a5d3978db8 Mon Sep 17 00:00:00 2001 From: Nikita Mathur Date: Tue, 31 Aug 2021 17:17:24 +0530 Subject: [PATCH 1/2] Fix control tags fetching logic which was breaking profiles with tags used Signed-off-by: Nikita Mathur --- lib/inspec/control_eval_context.rb | 19 ++++++++++++------- .../profiles/control-tags/controls/example.rb | 8 ++++++++ test/functional/inspec_exec_test.rb | 11 ++++++++++- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/inspec/control_eval_context.rb b/lib/inspec/control_eval_context.rb index a062d84a5..aa287cad8 100644 --- a/lib/inspec/control_eval_context.rb +++ b/lib/inspec/control_eval_context.rb @@ -53,19 +53,24 @@ module Inspec def control(id, opts = {}, &block) opts[:skip_only_if_eval] = @skip_only_if_eval - tag_ids = control_tags(&block) - if (controls_list_empty? && tags_list_empty?) || control_exist_in_controls_list?(id) || tag_exist_in_control_tags?(tag_ids) + if (controls_list_empty? && tags_list_empty?) || control_exist_in_controls_list?(id) register_control(Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block)) + elsif !tags_list_empty? + # Inside elsif rule is initialised before registering it because it enables fetching of control tags + inspec_rule = Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block) + tag_ids = control_tags(inspec_rule) + register_control(inspec_rule) if tag_exist_in_control_tags?(tag_ids) end end alias rule control - def control_tags(&block) - tag_source = block.source.split("\n").select { |src| src.split.first.eql?("tag") } - tag_source = tag_source.map { |src| src.sub("tag", "").strip }.map { |src| src.split(",").map { |final_src| final_src.sub(/([^:]*):/, "") } }.flatten - output = tag_source.map { |src| src.sub(/\[|\]/, "") }.map { |src| instance_eval(src) } - output.compact.uniq + def control_tags(inspec_rule) + all_tags = [] + inspec_rule.tag.each do |key, value| + value.nil? ? all_tags.push(key) : all_tags.push(value) + end + all_tags.flatten.compact.uniq.map(&:to_s) rescue [] end diff --git a/test/fixtures/profiles/control-tags/controls/example.rb b/test/fixtures/profiles/control-tags/controls/example.rb index b96cfdc2b..a91f27aa8 100644 --- a/test/fixtures/profiles/control-tags/controls/example.rb +++ b/test/fixtures/profiles/control-tags/controls/example.rb @@ -1,8 +1,16 @@ control "basic" do tag "tag1" + tag :special, :special1 tag severity: nil tag data: "tag2" tag data_arr: ["tag3", "tag4"] + tag error1: "Line with a line-feed + error" + tag error2: "Line with a comma,error" + tag cci: ['CCI-000366'] + tag legacy: [] + tag nist: ["AU-9", "AU-9 (3)", "AC-3 (4)", "AC-6 (10)"] + tag ref: "http:example.html:CIS CSC v6.0 #5.1;" describe(true) { it { should eq true } } end diff --git a/test/functional/inspec_exec_test.rb b/test/functional/inspec_exec_test.rb index b64fac272..bec77482e 100644 --- a/test/functional/inspec_exec_test.rb +++ b/test/functional/inspec_exec_test.rb @@ -258,7 +258,7 @@ Test Summary: 0 successful, 0 failures, 0 skipped it "executes only specified controls when selecting the controls by using regex on tags" do inspec("exec " + File.join(profile_path, "control-tags") + " --no-create-lockfile --tags '/\s+/'") _(stdout).must_include "true is expected to eq true\n" - _(stdout).must_include "Test Summary: 1 successful, 0 failures, 0 skipped\n" + _(stdout).must_include "Test Summary: 2 successful, 0 failures, 0 skipped\n" _(stderr).must_equal "" assert_exit_code 0, out @@ -282,6 +282,15 @@ Test Summary: 0 successful, 0 failures, 0 skipped assert_exit_code 100, out end + it "executes profile successfully when tags are used with single element array, punctuations and linefeeds" do + inspec("exec " + File.join(profile_path, "control-tags") + " --no-create-lockfile --tags tag1 'Line with a comma,error' CCI-000366") + _(stdout).must_include "true is expected to eq true\n" + _(stdout).must_include "Test Summary: 1 successful, 0 failures, 0 skipped\n" + _(stderr).must_equal "" + + assert_exit_code 0, out + end + it "reports whan a profile cannot be loaded" do inspec("exec " + File.join(profile_path, "raise_outside_control") + " --no-create-lockfile") _(stdout).must_match(/Profile:[\W]+InSpec Profile \(raise_outside_control\)/) From c85f49d0d83d65c0b5d2a9a32f090c3e6e08cdd6 Mon Sep 17 00:00:00 2001 From: Nikita Mathur Date: Tue, 31 Aug 2021 18:14:57 +0530 Subject: [PATCH 2/2] Change to filter tags on both key and value basis of hashmap style tags Signed-off-by: Nikita Mathur --- docs-chef-io/content/inspec/cli.md | 2 +- lib/inspec/control_eval_context.rb | 4 +++- test/fixtures/profiles/control-tags/controls/example.rb | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs-chef-io/content/inspec/cli.md b/docs-chef-io/content/inspec/cli.md index 43bfe77eb..4e8185ccf 100644 --- a/docs-chef-io/content/inspec/cli.md +++ b/docs-chef-io/content/inspec/cli.md @@ -337,7 +337,7 @@ This subcommand has additional options: * ``--target-id=TARGET_ID`` Provide a ID which will be included on reports * ``--tags=one two three`` - A list of tags, a list of regular expressions that match tags, or a hash map where each value is a tag. `exec` will run controls referenced by the listed or matching tags. + A list of tags, a list of regular expressions that match tags. `exec` will run controls referenced by the listed or matching tags. * ``--user=USER`` The login user for a remote scan. * ``--vendor-cache=VENDOR_CACHE`` diff --git a/lib/inspec/control_eval_context.rb b/lib/inspec/control_eval_context.rb index aa287cad8..5ad3f885f 100644 --- a/lib/inspec/control_eval_context.rb +++ b/lib/inspec/control_eval_context.rb @@ -57,6 +57,7 @@ module Inspec register_control(Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block)) elsif !tags_list_empty? # Inside elsif rule is initialised before registering it because it enables fetching of control tags + # This condition is only true when --tags option is used inspec_rule = Inspec::Rule.new(id, profile_id, resources_dsl, opts, &block) tag_ids = control_tags(inspec_rule) register_control(inspec_rule) if tag_exist_in_control_tags?(tag_ids) @@ -68,7 +69,8 @@ module Inspec def control_tags(inspec_rule) all_tags = [] inspec_rule.tag.each do |key, value| - value.nil? ? all_tags.push(key) : all_tags.push(value) + all_tags.push(key) + all_tags.push(value) unless value.nil? end all_tags.flatten.compact.uniq.map(&:to_s) rescue diff --git a/test/fixtures/profiles/control-tags/controls/example.rb b/test/fixtures/profiles/control-tags/controls/example.rb index a91f27aa8..9c140017d 100644 --- a/test/fixtures/profiles/control-tags/controls/example.rb +++ b/test/fixtures/profiles/control-tags/controls/example.rb @@ -1,6 +1,6 @@ control "basic" do tag "tag1" - tag :special, :special1 + tag :symbol_key1, :symbol_key2 tag severity: nil tag data: "tag2" tag data_arr: ["tag3", "tag4"]