From 9f0755be99efc7d8cbc7e2778490ca9a52b6f025 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:02:48 +0100 Subject: [PATCH 1/8] add new `cmp` matcher that eases the comparison for values --- lib/matchers/matchers.rb | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/matchers/matchers.rb b/lib/matchers/matchers.rb index fd446d20a..8ae330914 100644 --- a/lib/matchers/matchers.rb +++ b/lib/matchers/matchers.rb @@ -219,3 +219,43 @@ RSpec::Matchers.define :contain do |_rule| fail "[UNSUPPORTED] `contain` matcher. Please use the following syntax `its('content') { should match('value') }`." end end + +# This matcher implements a compare feature that cannot be covered by the default +# `eq` matcher +# You can use it in the following cases: +# - compare strings case-insensitive +# - you expect a number (strings will be converted if possible) +# +RSpec::Matchers.define :cmp do |expected| + + def integer?(value) + return true if value =~ /\A\d+\Z/ + false + end + + def float?(value) + true if Float(value) rescue false + end + + match do |actual| + # if actual and expected are strings + if actual.is_a?(String) && expected.is_a?(String) + actual.casecmp(expected) == 0 + elsif expected.is_a?(Integer) && integer?(actual) + expected == actual.to_i + elsif expected.is_a?(Float) && float?(actual) + expected == actual.to_f + # fallback to equal + else + actual == expected + end + end + + failure_message do |actual| + "\nexpected: #{expected}\n got: #{actual}\n\n(compared using .casecmp?)\n" + end + + failure_message_when_negated do |actual| + "\nexpected: value != #{expected}\n got: #{actual}\n\n(compared using .casecmp?)\n" + end +end From c461ffe7e71c10b4c7132722b79401f7fb4a4718 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:03:12 +0100 Subject: [PATCH 2/8] add integration test for compare matcher --- .../default/compare_matcher_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/integration/test/integration/default/compare_matcher_spec.rb diff --git a/test/integration/test/integration/default/compare_matcher_spec.rb b/test/integration/test/integration/default/compare_matcher_spec.rb new file mode 100644 index 000000000..e527e6558 --- /dev/null +++ b/test/integration/test/integration/default/compare_matcher_spec.rb @@ -0,0 +1,19 @@ +# encoding: utf-8 + +# uses the `cmp` matcher instead of the eq matcher +describe sshd_config do + its('Port') { should eq '22' } + its('Port') { should_not eq 22 } + + its('Port') { should cmp '22' } + its('Port') { should cmp 22 } + its('Port') { should cmp 22.0 } + its('Port') { should_not cmp 22.1 } + + its('LogLevel') { should eq 'INFO' } + its('LogLevel') { should_not eq 'info'} + + its('LogLevel') { should cmp 'INFO' } + its('LogLevel') { should cmp 'info' } + its('LogLevel') { should cmp 'InfO' } +end From 82b63bbce2d40d113bd55ac4492b13ba0b0def82 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:10:17 +0100 Subject: [PATCH 3/8] update documentation for `auditd_conf` and `sshd_config` --- docs/inspec_and_friends.rst | 2 +- docs/resources.rst | 39 ++++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/docs/inspec_and_friends.rst b/docs/inspec_and_friends.rst index 7aca37376..a81047fee 100644 --- a/docs/inspec_and_friends.rst +++ b/docs/inspec_and_friends.rst @@ -64,7 +64,7 @@ One of the key differences is that InSpec targets more user groups. It is optimi insecure SSHv1 connections anymore. " describe sshd_config do - its('Protocol') { should eq('2') } + its('Protocol') { should cmp 2 } end end diff --git a/docs/resources.rst b/docs/resources.rst index ffde5b7d4..86de60dfc 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -275,6 +275,13 @@ This |inspec resource| matches any keyword that is listed in the ``auditd.conf`` its('log_format') { should eq 'raw' } +Since all option names and values are case insensitive for ``auditd_conf``, we recommend to compare values with `cmp` instead of the `eq`. + +.. code-block:: ruby + + its('log_format') { should cmp 'raw' } + its('max_log_file') { should cmp 6 } + Examples ----------------------------------------------------- The following examples show how to use this InSpec audit resource. @@ -284,20 +291,20 @@ The following examples show how to use this InSpec audit resource. .. code-block:: ruby describe auditd_conf do - its('log_file') { should eq '/full/path/to/file' } - its('log_format') { should eq 'raw' } - its('flush') { should eq 'none' } - its('freq') { should eq '1' } - its('num_logs') { should eq '0' } - its('max_log_file') { should eq '6' } - its('max_log_file_action') { should eq 'email' } - its('space_left') { should eq '2' } - its('action_mail_acct') { should eq 'root' } - its('space_left_action') { should eq 'email' } - its('admin_space_left') { should eq '1' } - its('admin_space_left_action') { should eq 'halt' } - its('disk_full_action') { should eq 'halt' } - its('disk_error_action') { should eq 'halt' } + its('log_file') { should cmp '/full/path/to/file' } + its('log_format') { should cmp 'raw' } + its('flush') { should cmp 'none' } + its('freq') { should cmp 1 } + its('num_logs') { should cmp 0 } + its('max_log_file') { should cmp 6 } + its('max_log_file_action') { should cmp 'email' } + its('space_left') { should cmp 2 } + its('action_mail_acct') { should cmp 'root' } + its('space_left_action') { should cmp 'email' } + its('admin_space_left') { should cmp 1 } + its('admin_space_left_action') { should cmp 'halt' } + its('disk_full_action') { should cmp 'halt' } + its('disk_error_action') { should cmp 'halt' } end @@ -3910,7 +3917,7 @@ The following examples show how to use this InSpec audit resource. .. code-block:: ruby describe sshd_config do - its('Protocol') { should eq '2' } + its('Protocol') { should cmp 2 } end **Test ciphers** @@ -3926,7 +3933,7 @@ The following examples show how to use this InSpec audit resource. .. code-block:: ruby describe sshd_config do - its('Port') { should eq '22' } + its('Port') { should cmp 22 } its('UsePAM') { should eq 'yes' } its('ListenAddress') { should eq nil } its('HostKey') { should eq [ From 53728ee03a2c93c6911ed0a86479ffd751a70dba Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:17:01 +0100 Subject: [PATCH 4/8] lint fix --- lib/matchers/matchers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matchers/matchers.rb b/lib/matchers/matchers.rb index 8ae330914..8aea5af12 100644 --- a/lib/matchers/matchers.rb +++ b/lib/matchers/matchers.rb @@ -255,7 +255,7 @@ RSpec::Matchers.define :cmp do |expected| "\nexpected: #{expected}\n got: #{actual}\n\n(compared using .casecmp?)\n" end - failure_message_when_negated do |actual| + failure_message_when_negated do |actual| "\nexpected: value != #{expected}\n got: #{actual}\n\n(compared using .casecmp?)\n" end end From 31f886370109aa6b2642224367a87769b6043215 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:19:28 +0100 Subject: [PATCH 5/8] update failure message for `cmp` matcher --- lib/matchers/matchers.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matchers/matchers.rb b/lib/matchers/matchers.rb index 8aea5af12..54e3813a9 100644 --- a/lib/matchers/matchers.rb +++ b/lib/matchers/matchers.rb @@ -252,10 +252,10 @@ RSpec::Matchers.define :cmp do |expected| end failure_message do |actual| - "\nexpected: #{expected}\n got: #{actual}\n\n(compared using .casecmp?)\n" + "\nexpected: #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n" end failure_message_when_negated do |actual| - "\nexpected: value != #{expected}\n got: #{actual}\n\n(compared using .casecmp?)\n" + "\nexpected: value != #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n" end end From 52cd0b38d134a86eaadbd0225babb8075b034683 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:26:46 +0100 Subject: [PATCH 6/8] update style of `float?` detection --- lib/matchers/matchers.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/matchers/matchers.rb b/lib/matchers/matchers.rb index 54e3813a9..95b1efc84 100644 --- a/lib/matchers/matchers.rb +++ b/lib/matchers/matchers.rb @@ -234,7 +234,10 @@ RSpec::Matchers.define :cmp do |expected| end def float?(value) - true if Float(value) rescue false + return true if Float(value) + false + rescue ArgumentError => ex + false end match do |actual| From 1ce1f26d768d258fb055708c4f1cc51be7fb675e Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:28:51 +0100 Subject: [PATCH 7/8] update docs for auditd_conf --- docs/resources.rst | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/resources.rst b/docs/resources.rst index 86de60dfc..3af44ec12 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -258,7 +258,7 @@ A ``auditd_conf`` |inspec resource| block declares configuration settings that s .. code-block:: ruby describe auditd_conf('path') do - its('keyword') { should eq 'value' } + its('keyword') { should cmp 'value' } end where @@ -269,13 +269,7 @@ where Matchers ----------------------------------------------------- -This |inspec resource| matches any keyword that is listed in the ``auditd.conf`` configuration file: - -.. code-block:: ruby - - its('log_format') { should eq 'raw' } - -Since all option names and values are case insensitive for ``auditd_conf``, we recommend to compare values with `cmp` instead of the `eq`. +This |inspec resource| matches any keyword that is listed in the ``auditd.conf`` configuration file. Since all option names and values are case insensitive for ``auditd_conf``, we recommend to compare values with `cmp` instead of the `eq`: .. code-block:: ruby From 0185751ff5ddd93e15606f0d95b4894108388f4d Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Fri, 11 Dec 2015 17:48:05 +0100 Subject: [PATCH 8/8] lint exception --- lib/matchers/matchers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matchers/matchers.rb b/lib/matchers/matchers.rb index 95b1efc84..b408aa224 100644 --- a/lib/matchers/matchers.rb +++ b/lib/matchers/matchers.rb @@ -236,7 +236,7 @@ RSpec::Matchers.define :cmp do |expected| def float?(value) return true if Float(value) false - rescue ArgumentError => ex + rescue ArgumentError => _ex false end