From 4a0b1129b6d1ab8ea605a2c838af5cc91e057856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Tarti=C3=A8re?= Date: Thu, 27 Apr 2023 16:40:28 -1000 Subject: [PATCH] Rewrite validate_domain_name() as a Puppet 4.x function The 3.x function rely on is_domain_name() which is deprecated. Rewrite it using the more modern puppet 4.x function to rely on data types for better parameters validation. While here, adjust the Stdlib::Fqdn data type to ensure the last component (TLD) is non-numeric as [suggested by @ekohl](https://github.com/puppetlabs/puppetlabs-stdlib/issues/1282#issuecomment-1315182022), and add a Stdlib::Dns_zone data type that is basically the same but with a trailing dot. --- lib/puppet/functions/validate_domain_name.rb | 28 +++++++++++ .../parser/functions/validate_domain_name.rb | 48 ------------------- spec/functions/validate_domain_name_spec.rb | 27 +++++------ spec/type_aliases/dns_zone_spec.rb | 39 +++++++++++++++ spec/type_aliases/fqdn_spec.rb | 7 ++- spec/type_aliases/host_spec.rb | 15 +++++- types/dns/zone.pp | 2 + 7 files changed, 101 insertions(+), 65 deletions(-) create mode 100644 lib/puppet/functions/validate_domain_name.rb delete mode 100644 lib/puppet/parser/functions/validate_domain_name.rb create mode 100644 spec/type_aliases/dns_zone_spec.rb create mode 100644 types/dns/zone.pp diff --git a/lib/puppet/functions/validate_domain_name.rb b/lib/puppet/functions/validate_domain_name.rb new file mode 100644 index 000000000..c2833043f --- /dev/null +++ b/lib/puppet/functions/validate_domain_name.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +# @summary +# Validate that all values passed are syntactically correct domain names. +# Fail compilation if any value fails this check. +Puppet::Functions.create_function(:validate_domain_name) do + # @param values A domain name or an array of domain names to check + # + # @return [Undef] + # passes when the given values are syntactically correct domain names or raise an error when they are not and fails compilation + # + # @example Passing examples + # $my_domain_name = 'server.domain.tld' + # validate_domain_name($my_domain_name) + # validate_domain_name('domain.tld', 'puppet.com', $my_domain_name) + # validate_domain_name('www.example.2com') + # + # @example Failing examples (causing compilation to abort) + # validate_domain_name(1) + # validate_domain_name(true) + # validate_domain_name('invalid domain') + # validate_domain_name('-foo.example.com') + dispatch :validate_domain_name do + repeated_param 'Variant[Stdlib::Fqdn, Stdlib::Dns::Zone]', :values + end + + def validate_domain_name(*_values); end +end diff --git a/lib/puppet/parser/functions/validate_domain_name.rb b/lib/puppet/parser/functions/validate_domain_name.rb deleted file mode 100644 index 0ed576f16..000000000 --- a/lib/puppet/parser/functions/validate_domain_name.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -# -# validate_domain_name.rb -# -module Puppet::Parser::Functions - newfunction(:validate_domain_name, doc: <<-DOC - @summary - Validate that all values passed are syntactically correct domain names. - Fail compilation if any value fails this check. - - @return - passes when the given values are syntactically correct domain names or raise an error when they are not and fails compilation - - @example **Usage** - - The following values will pass: - - $my_domain_name = 'server.domain.tld' - validate_domain_name($my_domain_name) - validate_domain_name('domain.tld', 'puppet.com', $my_domain_name) - - The following values will fail, causing compilation to abort: - - validate_domain_name(1) - validate_domain_name(true) - validate_domain_name('invalid domain') - validate_domain_name('-foo.example.com') - validate_domain_name('www.example.2com') - DOC - ) do |args| - rescuable_exceptions = [ArgumentError] - - if args.empty? - raise Puppet::ParseError, "validate_domain_name(): wrong number of arguments (#{args.length}; must be > 0)" - end - - args.each do |arg| - raise Puppet::ParseError, "#{arg.inspect} is not a string." unless arg.is_a?(String) - - begin - raise Puppet::ParseError, "#{arg.inspect} is not a syntactically correct domain name" unless function_is_domain_name([arg]) - rescue *rescuable_exceptions - raise Puppet::ParseError, "#{arg.inspect} is not a syntactically correct domain name" - end - end - end -end diff --git a/spec/functions/validate_domain_name_spec.rb b/spec/functions/validate_domain_name_spec.rb index f48d31ab5..78aea8218 100644 --- a/spec/functions/validate_domain_name_spec.rb +++ b/spec/functions/validate_domain_name_spec.rb @@ -5,7 +5,6 @@ describe 'validate_domain_name' do describe 'signature validation' do it { is_expected.not_to eq(nil) } - it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) } end describe 'valid inputs' do @@ -15,23 +14,23 @@ it { is_expected.to run.with_params('2foo.example.com', '2foo.example.com.') } it { is_expected.to run.with_params('www.2foo.example.com', 'www.2foo.example.com.') } it { is_expected.to run.with_params('domain.tld', 'puppet.com') } + it { is_expected.to run.with_params('www.example.2com') } + it { is_expected.to run.with_params('10.10.10.10.10') } end describe 'invalid inputs' do - it { is_expected.to run.with_params([]).and_raise_error(Puppet::ParseError, %r{is not a string}) } - it { is_expected.to run.with_params({}).and_raise_error(Puppet::ParseError, %r{is not a string}) } - it { is_expected.to run.with_params(1).and_raise_error(Puppet::ParseError, %r{is not a string}) } - it { is_expected.to run.with_params(true).and_raise_error(Puppet::ParseError, %r{is not a string}) } + it { is_expected.to run.with_params([]).and_raise_error(ArgumentError, %r{got Array}) } + it { is_expected.to run.with_params({}).and_raise_error(ArgumentError, %r{got Hash}) } + it { is_expected.to run.with_params(1).and_raise_error(ArgumentError, %r{got Integer}) } + it { is_expected.to run.with_params(true).and_raise_error(ArgumentError, %r{got Boolean}) } - it { is_expected.to run.with_params('foo.example.com', []).and_raise_error(Puppet::ParseError, %r{is not a string}) } - it { is_expected.to run.with_params('foo.example.com', {}).and_raise_error(Puppet::ParseError, %r{is not a string}) } - it { is_expected.to run.with_params('foo.example.com', 1).and_raise_error(Puppet::ParseError, %r{is not a string}) } - it { is_expected.to run.with_params('foo.example.com', true).and_raise_error(Puppet::ParseError, %r{is not a string}) } + it { is_expected.to run.with_params('foo.example.com', []).and_raise_error(ArgumentError, %r{got Array}) } + it { is_expected.to run.with_params('foo.example.com', {}).and_raise_error(ArgumentError, %r{got Hash}) } + it { is_expected.to run.with_params('foo.example.com', 1).and_raise_error(ArgumentError, %r{got Integer}) } + it { is_expected.to run.with_params('foo.example.com', true).and_raise_error(ArgumentError, %r{got Boolean}) } - it { is_expected.to run.with_params('').and_raise_error(Puppet::ParseError, %r{is not a syntactically correct domain name}) } - it { is_expected.to run.with_params('invalid domain').and_raise_error(Puppet::ParseError, %r{is not a syntactically correct domain name}) } - it { is_expected.to run.with_params('-foo.example.com').and_raise_error(Puppet::ParseError, %r{is not a syntactically correct domain name}) } - it { is_expected.to run.with_params('www.example.2com').and_raise_error(Puppet::ParseError, %r{is not a syntactically correct domain name}) } - it { is_expected.to run.with_params('192.168.1.1').and_raise_error(Puppet::ParseError, %r{is not a syntactically correct domain name}) } + it { is_expected.to run.with_params('').and_raise_error(ArgumentError, %r{got ''}) } + it { is_expected.to run.with_params('invalid domain').and_raise_error(ArgumentError, %r{got 'invalid domain'}) } + it { is_expected.to run.with_params('-foo.example.com').and_raise_error(ArgumentError, %r{got '-foo\.example\.com'}) } end end diff --git a/spec/type_aliases/dns_zone_spec.rb b/spec/type_aliases/dns_zone_spec.rb new file mode 100644 index 000000000..b546a3666 --- /dev/null +++ b/spec/type_aliases/dns_zone_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Stdlib::Dns::Zone' do + describe 'accepts dns zones' do + [ + '.', + 'com.', + 'example.com.', + '10.10.10.10.10.', + 'xn--5ea.pf.', + ].each do |value| + describe value.inspect do + it { is_expected.to allow_value(value) } + end + end + end + + describe 'rejects other values' do + [ + true, + false, + '', + 'iAmAString', + {}, + { 'key' => 'value' }, + { 1 => 2 }, + :undef, + 3, + 'www..com.', + '127.0.0.1', + ].each do |value| + describe value.inspect do + it { is_expected.not_to allow_value(value) } + end + end + end +end diff --git a/spec/type_aliases/fqdn_spec.rb b/spec/type_aliases/fqdn_spec.rb index 09ed393bb..f7d526ee7 100644 --- a/spec/type_aliases/fqdn_spec.rb +++ b/spec/type_aliases/fqdn_spec.rb @@ -4,7 +4,12 @@ describe 'Stdlib::Fqdn' do describe 'valid handling' do - ['example', 'example.com', 'www.example.com'].each do |value| + [ + 'example', + 'example.com', + 'www.example.com', + '10.10.10.10.10', + ].each do |value| describe value.inspect do it { is_expected.to allow_value(value) } end diff --git a/spec/type_aliases/host_spec.rb b/spec/type_aliases/host_spec.rb index cfd23ee26..6cfd3d94b 100644 --- a/spec/type_aliases/host_spec.rb +++ b/spec/type_aliases/host_spec.rb @@ -4,8 +4,19 @@ describe 'Stdlib::Host' do describe 'valid handling' do - ['example', 'example.com', 'www.example.com', '2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'fa76:8765:34ac:0823:ab76:eee9:0987:1111', '2001:0db8::1', '224.0.0.0', '255.255.255.255', - '0.0.0.0', '192.88.99.0'].each do |value| + [ + 'example', + 'example.com', + 'www.example.com', + '2001:0db8:85a3:0000:0000:8a2e:0370:7334', + 'fa76:8765:34ac:0823:ab76:eee9:0987:1111', + '2001:0db8::1', + '224.0.0.0', + '255.255.255.255', + '0.0.0.0', + '192.88.99.0', + '10.10.10.10.10', + ].each do |value| describe value.inspect do it { is_expected.to allow_value(value) } end diff --git a/types/dns/zone.pp b/types/dns/zone.pp new file mode 100644 index 000000000..bdd3220db --- /dev/null +++ b/types/dns/zone.pp @@ -0,0 +1,2 @@ +# @summary Validate a DNS zone name +type Stdlib::Dns::Zone = Pattern[/\A((([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)+|\.)\z/]