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