diff --git a/REFERENCE.md b/REFERENCE.md index 428f5fa9a3..b03fc8aca3 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -64,9 +64,9 @@ _Private Classes_ _Public Functions_ * [`postgresql::default`](#postgresqldefault): This function pull default values from the `params` class or `globals` class if the value is not present in `params`. -* [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape): This function safely escapes a string using a consistent random tag +* [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape): This function escapes a string using [Dollar Quoting](https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING) using a randomly generated tag if required. * [`postgresql::postgresql_password`](#postgresqlpostgresql_password): This function returns the postgresql password hash from the clear text username / password -* [`postgresql_escape`](#postgresql_escape): This function safely escapes a string using a consistent random tag +* [`postgresql_escape`](#postgresql_escape): DEPRECATED. Use the namespaced function [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape) instead. * [`postgresql_password`](#postgresql_password): DEPRECATED. Use the namespaced function [`postgresql::postgresql_password`](#postgresqlpostgresql_password) instead. _Private Functions_ @@ -2787,26 +2787,19 @@ Data type: `String` Type: Ruby 4.x API -postgresql_escape.rb ----- original file header ---- +This function escapes a string using [Dollar Quoting](https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING) using a randomly generated tag if required. - @return Safely escapes a string using $$ using a random tag which should be consistent +#### `postgresql::postgresql_escape(String[1] $input_string)` -#### `postgresql::postgresql_escape(Any *$args)` +The postgresql::postgresql_escape function. -postgresql_escape.rb ----- original file header ---- +Returns: `String` A `Dollar Quoted` string - @return Safely escapes a string using $$ using a random tag which should be consistent +##### `input_string` -Returns: `Data type` Describe what the function returns here - -##### `*args` - -Data type: `Any` +Data type: `String[1]` -The original array of arguments. Port this to individually managed params -to get the full benefit of the modern function API. +The unescaped string you want to escape using `dollar quoting` ### postgresql::postgresql_password @@ -2834,15 +2827,21 @@ The clear text `password` ### postgresql_escape -Type: Ruby 3.x API +Type: Ruby 4.x API + +DEPRECATED. Use the namespaced function [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape) instead. -This function safely escapes a string using a consistent random tag +#### `postgresql_escape(Any *$args)` -#### `postgresql_escape()` +The postgresql_escape function. + +Returns: `Any` + +##### `*args` + +Data type: `Any` -This function safely escapes a string using a consistent random tag -Returns: `Any` Safely escapes a string using $$ using a random tag which should be consistent ### postgresql_password diff --git a/lib/puppet/functions/postgresql/postgresql_escape.rb b/lib/puppet/functions/postgresql/postgresql_escape.rb index 1555af0783..223ad7018f 100644 --- a/lib/puppet/functions/postgresql/postgresql_escape.rb +++ b/lib/puppet/functions/postgresql/postgresql_escape.rb @@ -1,52 +1,30 @@ -# This is an autogenerated function, ported from the original legacy version. -# It /should work/ as is, but will not have all the benefits of the modern -# function API. You should see the function docs to learn how to add function -# signatures for type safety and to document this function using puppet-strings. -# -# https://puppet.com/docs/puppet/latest/custom_functions_ruby.html -# -# ---- original file header ---- require 'digest/md5' -# postgresql_escape.rb -# ---- original file header ---- -# -# @summary -# This function safely escapes a string using a consistent random tag -# @return Safely escapes a string using $$ using a random tag which should be consistent -# -# +# @summary This function escapes a string using [Dollar Quoting](https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING) using a randomly generated tag if required. Puppet::Functions.create_function(:'postgresql::postgresql_escape') do - # @param args - # The original array of arguments. Port this to individually managed params - # to get the full benefit of the modern function API. - # - # @return [Data type] - # Describe what the function returns here + # @param input_string + # The unescaped string you want to escape using `dollar quoting` # + # @return [String] + # A `Dollar Quoted` string dispatch :default_impl do - # Call the method named 'default_impl' when this is matched - # Port this to match individual params for better type safety - repeated_param 'Any', :args + param 'String[1]', :input_string end - def default_impl(*args) - if args.size != 1 - raise(Puppet::ParseError, 'postgresql_escape(): Wrong number of arguments ' \ - "given (#{args.size} for 1)") + def default_impl(input_string) + # Where allowed, just return the original string wrapped in `$$` + return "$$#{input_string}$$" unless tag_needed?(input_string) + + # Keep generating possible values for tag until we find one that doesn't appear in the input string + tag = Digest::MD5.hexdigest(input_string)[0..5].gsub(%r{\d}, '') + until input_string !~ %r{#{tag}} + tag = Digest::MD5.hexdigest(tag)[0..5].gsub(%r{\d}, '') end - password = args[0] + "$#{tag}$#{input_string}$#{tag}$" + end - if password !~ %r{\$\$} && password[-1] != '$' - retval = "$$#{password}$$" - else - escape = Digest::MD5.hexdigest(password)[0..5].gsub(%r{\d}, '') - until password !~ %r{#{escape}} - escape = Digest::MD5.hexdigest(escape)[0..5].gsub(%r{\d}, '') - end - retval = "$#{escape}$#{password}$#{escape}$" - end - retval + def tag_needed?(input_string) + input_string =~ %r{\$\$} || input_string.end_with?('$') end end diff --git a/lib/puppet/functions/postgresql_escape.rb b/lib/puppet/functions/postgresql_escape.rb new file mode 100644 index 0000000000..1e366d2d06 --- /dev/null +++ b/lib/puppet/functions/postgresql_escape.rb @@ -0,0 +1,10 @@ +# @summary DEPRECATED. Use the namespaced function [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape) instead. +Puppet::Functions.create_function(:postgresql_escape) do + dispatch :deprecation_gen do + repeated_param 'Any', :args + end + def deprecation_gen(*args) + call_function('deprecation', 'postgresql_escape', 'This method is deprecated, please use postgresql::postgresql_escape instead.') + call_function('postgresql::postgresql_escape', *args) + end +end diff --git a/lib/puppet/parser/functions/postgresql_escape.rb b/lib/puppet/parser/functions/postgresql_escape.rb deleted file mode 100644 index f7e6f33add..0000000000 --- a/lib/puppet/parser/functions/postgresql_escape.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'digest/md5' - -# postgresql_escape.rb -module Puppet::Parser::Functions - newfunction(:postgresql_escape, type: :rvalue, doc: <<-EOS - This function safely escapes a string using a consistent random tag - @return Safely escapes a string using $$ using a random tag which should be consistent - EOS - ) do |args| - - if args.size != 1 - raise(Puppet::ParseError, 'postgresql_escape(): Wrong number of arguments ' \ - "given (#{args.size} for 1)") - end - - password = args[0] - - if password !~ %r{\$\$} && password[-1] != '$' - retval = "$$#{password}$$" - else - escape = Digest::MD5.hexdigest(password)[0..5].gsub(%r{\d}, '') - until password !~ %r{#{escape}} - escape = Digest::MD5.hexdigest(escape)[0..5].gsub(%r{\d}, '') - end - retval = "$#{escape}$#{password}$#{escape}$" - end - retval - end -end diff --git a/manifests/server/passwd.pp b/manifests/server/passwd.pp index a9477fd0f3..a2f52ba18b 100644 --- a/manifests/server/passwd.pp +++ b/manifests/server/passwd.pp @@ -15,12 +15,12 @@ default => '' } - if ($postgres_password != undef) { + if $postgres_password { # NOTE: this password-setting logic relies on the pg_hba.conf being # configured to allow the postgres system user to connect via psql # without specifying a password ('ident' or 'trust' security). This is # the default for pg_hba.conf. - $escaped = postgresql_escape($postgres_password) + $escaped = postgresql::postgresql_escape($postgres_password) exec { 'set_postgres_postgrespw': # This command works w/no password because we run it as postgres system # user diff --git a/spec/functions/postgresql_escape_spec.rb b/spec/functions/postgresql_escape_spec.rb new file mode 100644 index 0000000000..a00f05eecd --- /dev/null +++ b/spec/functions/postgresql_escape_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe 'postgresql_escape' do + it_behaves_like 'postgresql_escape function' +end diff --git a/spec/functions/postgresql_postgresql_escape_spec.rb b/spec/functions/postgresql_postgresql_escape_spec.rb index 947ee72423..329ae8521a 100644 --- a/spec/functions/postgresql_postgresql_escape_spec.rb +++ b/spec/functions/postgresql_postgresql_escape_spec.rb @@ -1,40 +1,5 @@ require 'spec_helper' describe 'postgresql::postgresql_escape' do - # without knowing details about the implementation, this is the only test - # case that we can autogenerate. You should add more examples below! - it { is_expected.not_to eq(nil) } - - ################################# - # Below are some example test cases. You may uncomment and modify them to match - # your needs. Notice that they all expect the base error class of `StandardError`. - # This is because the autogenerated function uses an untyped array for parameters - # and relies on your implementation to do the validation. As you convert your - # function to proper dispatches and typed signatures, you should change the - # expected error of the argument validation examples to `ArgumentError`. - # - # Other error types you might encounter include - # - # * StandardError - # * ArgumentError - # * Puppet::ParseError - # - # Read more about writing function unit tests at https://rspec-puppet.com/documentation/functions/ - # - # it 'raises an error if called with no argument' do - # is_expected.to run.with_params.and_raise_error(StandardError) - # end - # - # it 'raises an error if there is more than 1 arguments' do - # is_expected.to run.with_params({ 'foo' => 1 }, 'bar' => 2).and_raise_error(StandardError) - # end - # - # it 'raises an error if argument is not the proper type' do - # is_expected.to run.with_params('foo').and_raise_error(StandardError) - # end - # - # it 'returns the proper output' do - # is_expected.to run.with_params(123).and_return('the expected output') - # end - ################################# + it_behaves_like 'postgresql_escape function' end diff --git a/spec/spec_helper_local.rb b/spec/spec_helper_local.rb index ba834774b1..a5ed86af90 100644 --- a/spec/spec_helper_local.rb +++ b/spec/spec_helper_local.rb @@ -55,3 +55,23 @@ def param(type, title, param) is_expected.to run.with_params('foo').and_raise_error(StandardError) end end + +shared_examples 'postgresql_escape function' do + it { is_expected.not_to eq(nil) } + it { + is_expected.to run.with_params('foo') + .and_return('$$foo$$') + } + it { + is_expected.to run.with_params('fo$$o') + .and_return('$ed$fo$$o$ed$') + } + it { + is_expected.to run.with_params('foo$') + .and_return('$a$foo$$a$') + } + it 'raises an error if there is more than 1 argument' do + is_expected.to run.with_params(['foo'], ['foo']) + .and_raise_error(StandardError) + end +end diff --git a/spec/unit/functions/postgresql_escape_spec.rb b/spec/unit/functions/postgresql_escape_spec.rb deleted file mode 100644 index b512c0cda9..0000000000 --- a/spec/unit/functions/postgresql_escape_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' -describe 'postgresql_escape' do - describe 'postgresql_escape', type: :puppet_function do - it { - is_expected.to run.with_params('foo') - .and_return('$$foo$$') - } - end - describe 'postgresql_escape', type: :puppet_function do - it { - is_expected.to run.with_params('fo$$o') - .and_return('$ed$fo$$o$ed$') - } - end - describe 'postgresql_escape', type: :puppet_function do - it { - is_expected.to run.with_params('foo$') - .and_return('$a$foo$$a$') - } - end - describe 'postgresql_escape', type: :puppet_function do - it { - is_expected.to run.with_params(['foo'], ['foo']) - .and_raise_error(%r{Wrong number of arguments}) - } - end -end