diff --git a/REFERENCE.md b/REFERENCE.md index 92111e563..18bb17269 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -173,6 +173,7 @@ the provided regular expression. * [`sort`](#sort): Sorts strings and arrays lexically. * [`sprintf_hash`](#sprintf_hash): Uses sprintf with named references. * [`squeeze`](#squeeze): Returns a new string where runs of the same character that occur in this set are replaced by a single character. +* [`stdlib::crc32`](#stdlibcrc32): Run a CRC32 calculation against a given value. * [`stdlib::deferrable_epp`](#stdlibdeferrable_epp): This function returns either a rendered template or a deferred function to render at runtime. If any of the values in the variables hash are * [`stdlib::end_with`](#stdlibend_with): Returns true if str ends with one of the prefixes given. Each of the prefixes should be a String. * [`stdlib::ensure`](#stdlibensure): function to cast ensure parameter to resource specific value @@ -4190,7 +4191,9 @@ hash types are: |bcrypt-x |2x |bug compatible | |bcrypt-y |2y |historic alias for 2b| -The third argument to this function is the salt to use. +The third argument to this function is the salt to use. For bcrypt-type hashes, +the first two characters of the salt represent a strength parameter, with a value +between 4 and 31 inclusive. > *Note:*: this uses the Puppet Server's implementation of crypt(3). If your environment contains several different operating systems, ensure that they @@ -4215,7 +4218,9 @@ hash types are: |bcrypt-x |2x |bug compatible | |bcrypt-y |2y |historic alias for 2b| -The third argument to this function is the salt to use. +The third argument to this function is the salt to use. For bcrypt-type hashes, +the first two characters of the salt represent a strength parameter, with a value +between 4 and 31 inclusive. > *Note:*: this uses the Puppet Server's implementation of crypt(3). If your environment contains several different operating systems, ensure that they @@ -4662,6 +4667,66 @@ The squeeze function. Returns: `Any` a new string where runs of the same character that occur in this set are replaced by a single character. +### `stdlib::crc32` + +Type: Ruby 4.x API + +Run a CRC32 calculation against a given value. + +#### Examples + +##### Check a simple string value + +```puppet +stdlib::crc32('my string') == '18fbd270' +``` + +##### Check a Sensitive datatype + +```puppet +stdlib::crc32(sensitive('my string')) == '18fbd270' +``` + +##### Check a number + +```puppet +stdlib::crc32(100.0) == 'a3fd429a' +stdlib::crc32(100.00000) == 'a3fd429a' +``` + +#### `stdlib::crc32(Variant[ScalarData, Sensitive[ScalarData], Binary, Sensitive[Binary]] $my_data)` + +Run a CRC32 calculation against a given value. + +Returns: `String` String + +##### Examples + +###### Check a simple string value + +```puppet +stdlib::crc32('my string') == '18fbd270' +``` + +###### Check a Sensitive datatype + +```puppet +stdlib::crc32(sensitive('my string')) == '18fbd270' +``` + +###### Check a number + +```puppet +stdlib::crc32(100.0) == 'a3fd429a' +stdlib::crc32(100.00000) == 'a3fd429a' +``` + +##### `my_data` + +Data type: `Variant[ScalarData, Sensitive[ScalarData], Binary, Sensitive[Binary]]` + +The ScalarData to evaluate + ### `stdlib::deferrable_epp` Type: Puppet Language @@ -4746,7 +4811,7 @@ Type: Puppet Language function to cast ensure parameter to resource specific value -#### `stdlib::ensure(Variant[Boolean, Enum['present', 'absent']] $ensure, Enum['directory', 'link', 'mounted', 'service', 'file', 'package'] $resource)` +#### `stdlib::ensure(Variant[Boolean, Enum['present', 'absent']] $ensure, Optional[Enum['directory', 'link', 'mounted', 'service', 'file', 'package']] $resource = undef)` The stdlib::ensure function. @@ -4760,7 +4825,7 @@ Data type: `Variant[Boolean, Enum['present', 'absent']]` ##### `resource` -Data type: `Enum['directory', 'link', 'mounted', 'service', 'file', 'package']` +Data type: `Optional[Enum['directory', 'link', 'mounted', 'service', 'file', 'package']]` diff --git a/lib/puppet/functions/stdlib/crc32.rb b/lib/puppet/functions/stdlib/crc32.rb new file mode 100644 index 000000000..36b2a6ca7 --- /dev/null +++ b/lib/puppet/functions/stdlib/crc32.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'zlib' +# @note +# The CRC32 algorithm can easily generate collisions, +# but may be useful for generating sharding, describing +# secrets, or seeding nonce values. +# +# @summary +# Run a CRC32 calculation against a given value. +Puppet::Functions.create_function(:'stdlib::crc32') do + # @param my_data The ScalarData to evaluate + # @example Check a simple string value + # stdlib::crc32('my string') == '18fbd270' + # @example Check a Sensitive datatype + # stdlib::crc32(sensitive('my string')) == '18fbd270' + # @example Check a number + # stdlib::crc32(100.0) == 'a3fd429a' + # stdlib::crc32(100.00000) == 'a3fd429a' + # @return String + dispatch :crc32 do + param 'Variant[ScalarData, Sensitive[ScalarData], Binary, Sensitive[Binary]]', :my_data + return_type 'String' + end + + def crc32(my_data) + Zlib.crc32(my_data.unwrap.to_s).to_s(16).downcase + rescue + Zlib.crc32(my_data.to_s).to_s(16).downcase + end +end diff --git a/spec/functions/crc32_spec.rb b/spec/functions/crc32_spec.rb new file mode 100644 index 000000000..ed82ae2fc --- /dev/null +++ b/spec/functions/crc32_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'stdlib::crc32' do + context 'when default' do + it { is_expected.not_to eq(nil) } + it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{stdlib::crc32}) } + end + + context 'when testing a simple string' do + it { is_expected.to run.with_params('abc').and_return('352441c2') } + it { is_expected.to run.with_params('acb').and_return('5b384015') } + it { is_expected.to run.with_params('my string').and_return('18fbd270') } + it { is_expected.to run.with_params('0').and_return('f4dbdf21') } + end + + context 'when testing a sensitive string' do + it { is_expected.to run.with_params(sensitive('my string')).and_return('18fbd270') } + end + + context 'when testing an integer' do + it { is_expected.to run.with_params(0).and_return('f4dbdf21') } + it { is_expected.to run.with_params(100).and_return('237750ea') } + it { is_expected.to run.with_params(sensitive(100)).and_return('237750ea') } + end + + context 'when testing a float' do + it { is_expected.to run.with_params(200.3).and_return('7d5469f0') } + + # .0 isn't always converted into an integer, but should have rational truncation + it { is_expected.to run.with_params(100.0).and_return('a3fd429a') } + it { is_expected.to run.with_params(sensitive(100.0000)).and_return('a3fd429a') } + end + + context 'when testing a bool' do + it { is_expected.to run.with_params(true).and_return('fdfc4c8d') } + it { is_expected.to run.with_params(false).and_return('2bcd6830') } + end + + context 'when testing a binary' do + it { is_expected.to run.with_params("\xFE\xED\xBE\xEF").and_return('ac3481a4') } + end +end