Skip to content

Commit 1682167

Browse files
committed
Finish conversion of postgresql_escape function
In puppetlabs#1129 the 3 functions from this module were ported to the modern function API and namespaced. None of the boilerplate was fixed up, tests weren't updated, documentation wasn't updated etc. This commit finishes the work for the `postgresql_escape` function. * Remove old API puppet/parser/functions version. * Create a replacement non-namespaced, (but deprecated), new API shim that calls the namespaced version. This function is *probably* not being used outside of this module, but it doesn't hurt to get the old version around for now. * Replace argument validation in the function code with data-type based validation for the individual function parameters. * Refactor function for increased readability. * Test both shim and namespaced version of the function. * Update `postgresql::server` to use namespaced version. * Update REFERENCE.md
1 parent b8c5e92 commit 1682167

File tree

9 files changed

+76
-155
lines changed

9 files changed

+76
-155
lines changed

REFERENCE.md

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ _Private Classes_
6464
_Public Functions_
6565

6666
* [`postgresql::default`](#postgresqldefault): This function pull default values from the `params` class or `globals` class if the value is not present in `params`.
67-
* [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape): This function safely escapes a string using a consistent random tag
67+
* [`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.
6868
* [`postgresql::postgresql_password`](#postgresqlpostgresql_password): This function returns the postgresql password hash from the clear text username / password
69-
* [`postgresql_escape`](#postgresql_escape): This function safely escapes a string using a consistent random tag
69+
* [`postgresql_escape`](#postgresql_escape): DEPRECATED. Use the namespaced function [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape) instead.
7070
* [`postgresql_password`](#postgresql_password): DEPRECATED. Use the namespaced function [`postgresql::postgresql_password`](#postgresqlpostgresql_password) instead.
7171

7272
_Private Functions_
@@ -2787,26 +2787,19 @@ Data type: `String`
27872787

27882788
Type: Ruby 4.x API
27892789

2790-
postgresql_escape.rb
2791-
---- original file header ----
2790+
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.
27922791

2793-
@return Safely escapes a string using $$ using a random tag which should be consistent
2792+
#### `postgresql::postgresql_escape(String[1] $input_string)`
27942793

2795-
#### `postgresql::postgresql_escape(Any *$args)`
2794+
The postgresql::postgresql_escape function.
27962795

2797-
postgresql_escape.rb
2798-
---- original file header ----
2796+
Returns: `String` A `Dollar Quoted` string
27992797

2800-
@return Safely escapes a string using $$ using a random tag which should be consistent
2798+
##### `input_string`
28012799

2802-
Returns: `Data type` Describe what the function returns here
2803-
2804-
##### `*args`
2805-
2806-
Data type: `Any`
2800+
Data type: `String[1]`
28072801

2808-
The original array of arguments. Port this to individually managed params
2809-
to get the full benefit of the modern function API.
2802+
The unescaped string you want to escape using `dollar quoting`
28102803

28112804
### postgresql::postgresql_password
28122805

@@ -2834,15 +2827,21 @@ The clear text `password`
28342827

28352828
### postgresql_escape
28362829

2837-
Type: Ruby 3.x API
2830+
Type: Ruby 4.x API
2831+
2832+
DEPRECATED. Use the namespaced function [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape) instead.
28382833

2839-
This function safely escapes a string using a consistent random tag
2834+
#### `postgresql_escape(Any *$args)`
28402835

2841-
#### `postgresql_escape()`
2836+
The postgresql_escape function.
2837+
2838+
Returns: `Any`
2839+
2840+
##### `*args`
2841+
2842+
Data type: `Any`
28422843

2843-
This function safely escapes a string using a consistent random tag
28442844

2845-
Returns: `Any` Safely escapes a string using $$ using a random tag which should be consistent
28462845

28472846
### postgresql_password
28482847

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,30 @@
1-
# This is an autogenerated function, ported from the original legacy version.
2-
# It /should work/ as is, but will not have all the benefits of the modern
3-
# function API. You should see the function docs to learn how to add function
4-
# signatures for type safety and to document this function using puppet-strings.
5-
#
6-
# https://puppet.com/docs/puppet/latest/custom_functions_ruby.html
7-
#
8-
# ---- original file header ----
91
require 'digest/md5'
102

11-
# postgresql_escape.rb
12-
# ---- original file header ----
13-
#
14-
# @summary
15-
# This function safely escapes a string using a consistent random tag
16-
# @return Safely escapes a string using $$ using a random tag which should be consistent
17-
#
18-
#
3+
# @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.
194
Puppet::Functions.create_function(:'postgresql::postgresql_escape') do
20-
# @param args
21-
# The original array of arguments. Port this to individually managed params
22-
# to get the full benefit of the modern function API.
23-
#
24-
# @return [Data type]
25-
# Describe what the function returns here
5+
# @param input_string
6+
# The unescaped string you want to escape using `dollar quoting`
267
#
8+
# @return [String]
9+
# A `Dollar Quoted` string
2710
dispatch :default_impl do
28-
# Call the method named 'default_impl' when this is matched
29-
# Port this to match individual params for better type safety
30-
repeated_param 'Any', :args
11+
param 'String[1]', :input_string
3112
end
3213

33-
def default_impl(*args)
34-
if args.size != 1
35-
raise(Puppet::ParseError, 'postgresql_escape(): Wrong number of arguments ' \
36-
"given (#{args.size} for 1)")
14+
def default_impl(input_string)
15+
# Where allowed, just return the original string wrapped in `$$`
16+
return "$$#{input_string}$$" unless tag_needed?(input_string)
17+
18+
# Keep generating possible values for tag until we find one that doesn't appear in the input string
19+
tag = Digest::MD5.hexdigest(input_string)[0..5].gsub(%r{\d}, '')
20+
until input_string !~ %r{#{tag}}
21+
tag = Digest::MD5.hexdigest(tag)[0..5].gsub(%r{\d}, '')
3722
end
3823

39-
password = args[0]
24+
"$#{tag}$#{input_string}$#{tag}$"
25+
end
4026

41-
if password !~ %r{\$\$} && password[-1] != '$'
42-
retval = "$$#{password}$$"
43-
else
44-
escape = Digest::MD5.hexdigest(password)[0..5].gsub(%r{\d}, '')
45-
until password !~ %r{#{escape}}
46-
escape = Digest::MD5.hexdigest(escape)[0..5].gsub(%r{\d}, '')
47-
end
48-
retval = "$#{escape}$#{password}$#{escape}$"
49-
end
50-
retval
27+
def tag_needed?(input_string)
28+
input_string =~ %r{\$\$} || input_string.end_with?('$')
5129
end
5230
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# @summary DEPRECATED. Use the namespaced function [`postgresql::postgresql_escape`](#postgresqlpostgresql_escape) instead.
2+
Puppet::Functions.create_function(:postgresql_escape) do
3+
dispatch :deprecation_gen do
4+
repeated_param 'Any', :args
5+
end
6+
def deprecation_gen(*args)
7+
call_function('deprecation', 'postgresql_escape', 'This method is deprecated, please use postgresql::postgresql_escape instead.')
8+
call_function('postgresql::postgresql_escape', *args)
9+
end
10+
end

lib/puppet/parser/functions/postgresql_escape.rb

Lines changed: 0 additions & 29 deletions
This file was deleted.

manifests/server/passwd.pp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
default => ''
1616
}
1717

18-
if ($postgres_password != undef) {
18+
if $postgres_password {
1919
# NOTE: this password-setting logic relies on the pg_hba.conf being
2020
# configured to allow the postgres system user to connect via psql
2121
# without specifying a password ('ident' or 'trust' security). This is
2222
# the default for pg_hba.conf.
23-
$escaped = postgresql_escape($postgres_password)
23+
$escaped = postgresql::postgresql_escape($postgres_password)
2424
exec { 'set_postgres_postgrespw':
2525
# This command works w/no password because we run it as postgres system
2626
# user
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require 'spec_helper'
2+
3+
describe 'postgresql_escape' do
4+
it_behaves_like 'postgresql_escape function'
5+
end
Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,5 @@
11
require 'spec_helper'
22

33
describe 'postgresql::postgresql_escape' do
4-
# without knowing details about the implementation, this is the only test
5-
# case that we can autogenerate. You should add more examples below!
6-
it { is_expected.not_to eq(nil) }
7-
8-
#################################
9-
# Below are some example test cases. You may uncomment and modify them to match
10-
# your needs. Notice that they all expect the base error class of `StandardError`.
11-
# This is because the autogenerated function uses an untyped array for parameters
12-
# and relies on your implementation to do the validation. As you convert your
13-
# function to proper dispatches and typed signatures, you should change the
14-
# expected error of the argument validation examples to `ArgumentError`.
15-
#
16-
# Other error types you might encounter include
17-
#
18-
# * StandardError
19-
# * ArgumentError
20-
# * Puppet::ParseError
21-
#
22-
# Read more about writing function unit tests at https://rspec-puppet.com/documentation/functions/
23-
#
24-
# it 'raises an error if called with no argument' do
25-
# is_expected.to run.with_params.and_raise_error(StandardError)
26-
# end
27-
#
28-
# it 'raises an error if there is more than 1 arguments' do
29-
# is_expected.to run.with_params({ 'foo' => 1 }, 'bar' => 2).and_raise_error(StandardError)
30-
# end
31-
#
32-
# it 'raises an error if argument is not the proper type' do
33-
# is_expected.to run.with_params('foo').and_raise_error(StandardError)
34-
# end
35-
#
36-
# it 'returns the proper output' do
37-
# is_expected.to run.with_params(123).and_return('the expected output')
38-
# end
39-
#################################
4+
it_behaves_like 'postgresql_escape function'
405
end

spec/spec_helper_local.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,23 @@ def param(type, title, param)
5555
is_expected.to run.with_params('foo').and_raise_error(StandardError)
5656
end
5757
end
58+
59+
shared_examples 'postgresql_escape function' do
60+
it { is_expected.not_to eq(nil) }
61+
it {
62+
is_expected.to run.with_params('foo')
63+
.and_return('$$foo$$')
64+
}
65+
it {
66+
is_expected.to run.with_params('fo$$o')
67+
.and_return('$ed$fo$$o$ed$')
68+
}
69+
it {
70+
is_expected.to run.with_params('foo$')
71+
.and_return('$a$foo$$a$')
72+
}
73+
it 'raises an error if there is more than 1 argument' do
74+
is_expected.to run.with_params(['foo'], ['foo'])
75+
.and_raise_error(StandardError)
76+
end
77+
end

spec/unit/functions/postgresql_escape_spec.rb

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)