inspec/lib/matchers/matchers.rb

303 lines
7.2 KiB
Ruby
Raw Normal View History

2015-07-14 22:50:34 +00:00
# encoding: utf-8
# copyright: 2015, Vulcano Security GmbH
2015-10-06 16:55:44 +00:00
# author: Dominik Richter
# author: Christoph Hartmann
2015-07-14 22:50:34 +00:00
# license: All rights reserved
RSpec::Matchers.define :be_readable do
match do |file|
2015-10-25 20:33:36 +00:00
file.readable?(@by, @by_user)
end
2015-10-25 20:33:36 +00:00
chain :by do |by|
@by = by
end
chain :by_user do |by_user|
@by_user = by_user
end
description do
2015-09-03 18:35:23 +00:00
res = 'be readable'
2015-10-25 20:33:36 +00:00
res += " by #{@by}" unless @by.nil?
res += " by user #{@by_user}" unless @by_user.nil?
res
end
end
RSpec::Matchers.define :be_writable do
match do |file|
2015-10-25 20:33:36 +00:00
file.writable?(@by, @by_user)
end
2015-10-25 20:33:36 +00:00
chain :by do |by|
@by = by
end
chain :by_user do |by_user|
@by_user = by_user
end
description do
2015-09-03 18:35:23 +00:00
res = 'be writable'
2015-10-25 20:33:36 +00:00
res += " by #{@by}" unless @by.nil?
res += " by user #{@by_user}" unless @by_user.nil?
res
end
end
RSpec::Matchers.define :be_executable do
match do |file|
2015-10-25 20:33:36 +00:00
file.executable?(@by, @by_user)
end
2015-10-25 20:33:36 +00:00
chain :by do |by|
@by = by
end
chain :by_user do |by_user|
@by_user = by_user
end
description do
2015-09-03 18:35:23 +00:00
res = 'be executable'
2015-10-25 20:33:36 +00:00
res += " by #{@by}" unless @by.nil?
res += " by user #{@by_user}" unless @by_user.nil?
res
end
end
2015-07-14 22:50:34 +00:00
# matcher to check /etc/passwd, /etc/shadow and /etc/group
RSpec::Matchers.define :contain_legacy_plus do
match do |file|
2016-01-15 02:59:00 +00:00
file.content =~ /^\+:/
2015-07-14 22:50:34 +00:00
end
end
# verifies that no entry in an array contains a value
RSpec::Matchers.define :contain_match do |regex|
match do |arr|
2015-09-04 07:59:30 +00:00
arr.inject { |result, i|
2015-09-25 12:40:52 +00:00
result = i.match(regex)
2015-07-14 22:50:34 +00:00
result || i.match(/$/)
2015-09-04 07:59:30 +00:00
}
2015-07-14 22:50:34 +00:00
end
end
2015-07-15 13:16:28 +00:00
RSpec::Matchers.define :contain_duplicates do
match do |arr|
2015-09-04 07:59:30 +00:00
dup = arr.select { |element| arr.count(element) > 1 }
2015-07-15 13:16:28 +00:00
!dup.uniq.empty?
end
end
2015-09-08 22:10:54 +00:00
# for packages
RSpec::Matchers.define :be_installed do
match do |package|
package.installed? == true
end
failure_message do |package|
"expected that `#{package}` is installed"
end
chain :by do
fail "[UNSUPPORTED] Please use the new resources 'gem', 'npm' or 'pip'."
end
chain :with_version do |version|
warn "[DEPRECATION] `with_version` is deprecated. Please use `its(:version) { should eq '1.4.1' }` instead."
@version = version
end
end
2015-09-14 13:01:33 +00:00
# for services
RSpec::Matchers.define :be_enabled do
match do |service|
service.enabled? == true
end
chain :with_level do |_level|
fail '[UNSUPPORTED] with level is not supported'
end
failure_message do |service|
"expected that `#{service}` is enabled"
end
end
# service resource matcher for serverspec compatibility
# Deprecated: You should not use this matcher anymore
2015-09-14 13:01:33 +00:00
RSpec::Matchers.define :be_running do
match do |service|
service.running? == true
end
chain :under do |_under|
fail '[UNSUPPORTED] under is not supported'
end
failure_message do |service|
"expected that `#{service}` is running"
end
end
# user resource matcher for serverspec compatibility
# Deprecated: You should not use this matcher anymore
RSpec::Matchers.define :belong_to_group do |compare_group|
match do |user|
warn "[DEPRECATION] `belong_to_group` is deprecated. Please use `its(:groups) { should include('root') }` instead."
user.groups.include?(compare_group)
end
failure_message do |group|
"expected that the user belongs to group `#{group}`"
end
end
# user resource matcher for serverspec compatibility
# Deprecated: You should not use this matcher anymore
RSpec::Matchers.define :belong_to_primary_group do |compare_group|
match do |user|
warn "[DEPRECATION] `belong_to_primary_group` is deprecated. Please use `its(:group) { should eq 'root' }` instead."
user.group == compare_group
end
failure_message do |group|
"expected that the user belongs to primary group `#{group}`"
end
end
2015-10-09 17:10:10 +00:00
# matcher to check if host is reachable
RSpec::Matchers.define :be_reachable do
match do |host|
host.reachable? == true
end
chain :with do |_attr|
fail '[UNSUPPORTED] `with` is not supported in combination with `be_reachable`'
end
failure_message do |host|
"expected that host #{host} is reachable"
end
end
# matcher to check if host is resolvable
RSpec::Matchers.define :be_resolvable do
match do |host|
host.resolvable? == true
end
chain :by do |_type|
2015-10-11 22:21:11 +00:00
fail "[UNSUPPORTED] `by` is not supported in combination with `be_resolvable`. Please use the following syntax `host('example.com', port: 53, proto: 'udp')`."
2015-10-09 17:10:10 +00:00
end
failure_message do |host|
"expected that host #{host} is resolvable"
end
end
2015-10-11 22:21:11 +00:00
# matcher for iptables
RSpec::Matchers.define :have_rule do |rule|
match do |tables|
tables.has_rule?(rule)
end
chain :with_table do |_table|
fail "[UNSUPPORTED] `with_table` is not supported in combination with `have_rule`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
end
chain :with_chain do |_chain|
fail "[UNSUPPORTED] `with_table` is not supported in combination with `with_chain`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
end
end
# unsupported
RSpec::Matchers.define :contain do |_rule|
match do |_resource|
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)
2016-02-18 11:07:40 +00:00
!(value =~ /\A\d+\Z/).nil?
end
def float?(value)
2016-02-18 11:07:40 +00:00
Float(value)
true
2015-12-11 16:48:05 +00:00
rescue ArgumentError => _ex
2015-12-11 16:26:46 +00:00
false
end
2015-12-16 10:32:31 +00:00
def octal?(value)
2016-02-18 11:07:40 +00:00
!(value =~ /\A0+\d+\Z/).nil?
2015-12-16 10:32:31 +00:00
end
match do |actual|
2016-02-18 11:08:57 +00:00
actual = actual[0] if actual.is_a?(Array) && !expected.is_a?(Array) && actual.length == 1
# if actual and expected are strings
2015-12-16 10:32:31 +00:00
if expected.is_a?(String) && actual.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
2015-12-16 10:32:31 +00:00
elsif octal?(expected) && actual.is_a?(Integer)
expected.to_i(8) == actual
# fallback to equal
else
actual == expected
end
end
failure_message do |actual|
2015-12-16 10:32:31 +00:00
actual = '0' + actual.to_s(8) if octal?(expected)
"\nexpected: #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
end
2015-12-11 16:17:01 +00:00
failure_message_when_negated do |actual|
2015-12-16 10:32:31 +00:00
actual = '0' + actual.to_s(8) if octal?(expected)
"\nexpected: value != #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
end
end
# user resource matcher for serverspec compatibility
# This matcher will be deprecated in future
RSpec::Matchers.define :be_mounted do
match do |path|
if !@options.nil?
path.mounted?(@options, @identical)
else
path.mounted?
end
end
chain :with do |attr|
@options = attr
@identical = false
end
chain :only_with do |attr|
@options = attr
@identical = true
end
failure_message do |path|
if !@options.nil?
"\n#{path} is not mounted with the options\n expected: #{@options}\n got: #{path.mount_options}\n"
else
"\n#{path} is not mounted\n"
end
end
end