Skip to content

Commit ced3a74

Browse files
Merge pull request #1162 from alexjfisher/finish_postgresql_escape_conversion
Finish conversion of `postgresql_escape` function
2 parents 02d7002 + 788aad6 commit ced3a74

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)