Project import generated by Copybara.

GitOrigin-RevId: c6e90de466877b3b0d6dd39c7573c1cfedf0a58d
Change-Id: I48a0a6f1b70ee8a61e4bb1eceb71fd331536e86a
diff --git a/v3.6.0/.changes/3.4.3.md b/v3.6.0/.changes/3.4.3.md
new file mode 100644
index 0000000..e42b69f
--- /dev/null
+++ b/v3.6.0/.changes/3.4.3.md
@@ -0,0 +1,214 @@
+## 3.4.3 (September 08, 2022)
+
+NOTES:
+
+* resource/random_password: The values for `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special`, `min_upper` and `length` could be null if the resource was imported using version 3.3.1 or before. The value for `length` will be automatically calculated and assigned and default values will be assigned for the other attributes listed after this upgrade ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_string: The values for `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special`, `min_upper` and `length` could be null if the resource was imported using version 3.3.1 or before. The value for `length` will be automatically calculated and assigned and default values will be assigned for the other attributes listed after this upgrade ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_password: If the resource was created between versions 3.4.0 and 3.4.2, the `bcrypt_hash` value would not correctly verify against the `result` value. Affected resources will automatically regenerate a valid `bcrypt_hash` after this upgrade. ([#308](https://github.com/hashicorp/terraform-provider-random/pull/308))
+* resource/random_password: The `override_special` attribute may show a plan difference from empty string (`""`) to `null` if previously applied with version 3.4.2. The plan should show this as an in-place update and it should occur only once after upgrading. ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+* resource/random_string: The `override_special` attribute may show a plan difference from empty string (`""`) to `null` if previously applied with version 3.4.2. The plan should show this as an in-place update and it should occur only once after upgrading. ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+
+BUG FIXES:
+
+* resource/random_password: Assign default values to `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special` and `min_upper` if null. Assign length of `result` to `length` if null ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_string: Assign default values to `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special` and `min_upper` if null. Assign length of `result` to `length` if null ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_password: Fixed incorrect `bcrypt_hash` generation since version 3.4.0 ([#308](https://github.com/hashicorp/terraform-provider-random/pull/308))
+* resource/random_password: Prevented difference with `override_special` when upgrading from version 3.3.2 and earlier ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+* resource/random_string: Prevented difference with `override_special` when upgrading from version 3.3.2 and earlier ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+
+## 3.4.2 (September 02, 2022)
+
+BUG FIXES:
+
+* all: Prevent `keeper` with `null` values from forcing replacement ([305](https://github.com/hashicorp/terraform-provider-random/pull/305)).
+* resource/random_password: During upgrade state, ensure `min_upper` is populated ([304](https://github.com/hashicorp/terraform-provider-random/pull/304)).
+* resource/random_string: During upgrade state, ensure `min_upper` is populated ([304](https://github.com/hashicorp/terraform-provider-random/pull/304)).
+
+## 3.4.1 (August 31, 2022)
+
+BUG FIXES:
+
+* resource/random_password: During attribute plan modifier, only return error if `number` and `numeric` are both present and do not match ([301](https://github.com/hashicorp/terraform-provider-random/pull/301)).
+* resource/random_string: During attribute plan modifier, only return error if `number` and `numeric` are both present and do not match ([301](https://github.com/hashicorp/terraform-provider-random/pull/301)).
+
+## 3.4.0 (August 30, 2022)
+
+NOTES:
+
+* Provider has been re-written using the new [`terraform-plugin-framework`](https://www.terraform.io/plugin/framework) ([#177](https://github.com/hashicorp/terraform-provider-random/pull/177)).
+* resource/random_password: `number` was deprecated in [v3.3.0](https://github.com/hashicorp/terraform-provider-random/releases/tag/v3.3.0) and will be removed in the next major release.
+* resource/random_string: `number` was deprecated in [v3.3.0](https://github.com/hashicorp/terraform-provider-random/releases/tag/v3.3.0) and will be removed in the next major release.
+
+## 3.3.2 (June 23, 2022)
+
+BUG FIXES:
+
+* resource/random_password: When importing set defaults for all attributes that have a default defined ([256](https://github.com/hashicorp/terraform-provider-random/pull/256)).
+* resource/random_string: When importing set defaults for all attributes that have a default defined ([256](https://github.com/hashicorp/terraform-provider-random/pull/256)).
+
+## 3.3.1 (June 07, 2022)
+
+BUG FIXES:
+
+* resource/random_password: During schema upgrade, copy value of attribute `number` to attribute `numeric`, only if said value is a boolean (i.e. not `null`) ([262](https://github.com/hashicorp/terraform-provider-random/pull/262))
+* resource/random_string: During schema upgrade, copy value of attribute `number` to attribute `numeric`, only if said value is a boolean (i.e. not `null`) ([262](https://github.com/hashicorp/terraform-provider-random/pull/262))
+
+## 3.3.0 (June 06, 2022)
+
+ENHANCEMENTS:
+
+* resource/random_password: `number` is now deprecated and `numeric` has been added to align attribute naming. `number` will be removed in the next major release ([#258](https://github.com/hashicorp/terraform-provider-random/pull/258)).
+* resource/random_string: `number` is now deprecated and `numeric` has been added to align attribute naming. `number` will be removed in the next major release ([#258](https://github.com/hashicorp/terraform-provider-random/pull/258)).
+
+## 3.2.0 (May 18, 2022)
+
+NEW FEATURES:
+
+* resource/random_password: New attribute `bcrypt_hash`, which is the hashed password ([73](https://github.com/hashicorp/terraform-provider-random/pull/73), [102](https://github.com/hashicorp/terraform-provider-random/issues/102), [254](https://github.com/hashicorp/terraform-provider-random/pull/254))
+
+NOTES:
+
+* Adds or updates DESIGN.md, README.md, CONTRIBUTING.md and SUPPORT.md docs ([176](https://github.com/hashicorp/terraform-provider-random/issues/176), [235](https://github.com/hashicorp/terraform-provider-random/issues/235), [242](https://github.com/hashicorp/terraform-provider-random/pull/242)).
+* Removes usage of deprecated fields, types and functions ([243](https://github.com/hashicorp/terraform-provider-random/issues/243), [244](https://github.com/hashicorp/terraform-provider-random/pull/244)).
+* Tests all minor Terraform versions ([238](https://github.com/hashicorp/terraform-provider-random/issues/238), [241](https://github.com/hashicorp/terraform-provider-random/pull/241))
+* Switches to linting with golangci-lint ([237](https://github.com/hashicorp/terraform-provider-random/issues/237), [240](https://github.com/hashicorp/terraform-provider-random/pull/240)).
+
+## 3.1.3 (April 22, 2022)
+
+BUG FIXES:
+
+* resource/random_password: Prevent crash when length is less than 0 ([#129](https://github.com/hashicorp/terraform-provider-random/issues/129), [#181](https://github.com/hashicorp/terraform-provider-random/issues/181), [#200](https://github.com/hashicorp/terraform-provider-random/pull/200), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+* resource/random_string: Prevent crash when length is less than 0 ([#129](https://github.com/hashicorp/terraform-provider-random/issues/129), [#181](https://github.com/hashicorp/terraform-provider-random/issues/181), [#200](https://github.com/hashicorp/terraform-provider-random/pull/200), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+* resource/random_password: Prevent confusing inconsistent result error when length is 0 ([#222](https://github.com/hashicorp/terraform-provider-random/issues/222), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+* resource/random_string: Prevent confusing inconsistent result error when length is 0 ([#222](https://github.com/hashicorp/terraform-provider-random/issues/222), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+
+## 3.1.2 (March 17, 2022)
+
+BUG FIXES:
+
+* resource/random_pet: Prevented deterministic results since 3.1.1 ([#217](https://github.com/hashicorp/terraform-provider-random/issues/217). 
+
+## 3.1.1 (March 16, 2022)
+
+NOTES:
+
+* Updated [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs) to `v0.7.0`:
+  this improves generated documentation, with attributes now correctly formatted as `code`
+  and provided with anchors.
+* Functionally identical to the previous 3.1.0 release.
+
+## 3.1.0 (February 19, 2021)
+
+Binary releases of this provider now include the darwin-arm64 platform. This version contains no further changes.
+
+## 3.0.1 (January 12, 2021)
+
+BUG FIXES:
+
+* `resource_integer`: Integers in state that do not cleanly fit into float64s no longer lose their precision ([#132](https://github.com/terraform-providers/terraform-provider-random/issues/132))
+
+## 3.0.0 (October 09, 2020)
+
+Binary releases of this provider will now include the linux-arm64 platform.
+
+BREAKING CHANGES:
+
+* Upgrade to version 2 of the Terraform Plugin SDK, which drops support for Terraform 0.11. This provider will continue to work as expected for users of Terraform 0.11, which will not download the new version. ([#118](https://github.com/terraform-providers/terraform-provider-random/issues/118))
+* Remove deprecated `b64` attribute ([#118](https://github.com/terraform-providers/terraform-provider-random/issues/118))
+
+## 2.3.1 (October 26, 2020)
+
+NOTES: This version is identical to v2.3.0, but has been compiled using Go v1.14.5 to fix https://github.com/hashicorp/terraform-provider-random/issues/120.
+
+## 2.3.0 (July 07, 2020)
+
+NOTES:
+
+* The provider now uses the binary driver for acceptance tests ([#99](https://github.com/terraform-providers/terraform-provider-random/issues/99))
+
+NEW FEATURES:
+
+* Added import handling for `random_string` and `random_password` ([#104](https://github.com/terraform-providers/terraform-provider-random/issues/104))
+
+## 2.2.1 (September 25, 2019)
+
+NOTES:
+
+* The provider has switched to the standalone TF SDK, there should be no noticeable impact on compatibility. ([#76](https://github.com/terraform-providers/terraform-provider-random/issues/76))
+
+## 2.2.0 (August 08, 2019)
+
+NEW FEATURES:
+
+* `random_password` is similar to `random_string` but is marked sensitive for logs and output [[#52](https://github.com/terraform-providers/terraform-provider-random/issues/52)] 
+
+## 2.1.2 (April 30, 2019)
+
+* This release includes another Terraform SDK upgrade intended to align with that being used for other providers as we prepare for the Core v0.12.0 release. It should have no significant changes in behavior for this provider.
+
+## 2.1.1 (April 12, 2019)
+
+* This release includes only a Terraform SDK upgrade intended to align with that being used for other providers as we prepare for the Core v0.12.0 release. It should have no significant changes in behavior for this provider.
+
+## 2.1.0 (March 20, 2019)
+
+IMPROVEMENTS:
+
+* The provider is now compatible with Terraform v0.12, while retaining compatibility with prior versions.
+
+## 2.0.0 (August 15, 2018)
+
+BACKWARDS INCOMPATIBILITIES / NOTES:
+* `random_string`: set the ID for random_string resources to "none". Any terraform configuration referring to `random_string.foo.id` will need to be updated to reference `random_string.foo.result` ([#17](https://github.com/terraform-providers/terraform-provider-random/issues/17))
+
+NEW FEATURES:
+
+* `random_uuid` generates random uuid string that is intended to be used as unique identifiers for other resources ([#38](https://github.com/terraform-providers/terraform-provider-random/issues/38))
+
+BUG FIXES: 
+* Use UnixNano() instead of Unix() for the current time seed in NewRand() ([#27](https://github.com/terraform-providers/terraform-provider-random/issues/27))
+* `random_shuffle`: if `random_shuffle` is given an empty list, it will return an empty list
+
+IMPROVEMENTS:
+
+* Replace ReadPet function in `resource_pet` with schema.Noop ([#34](https://github.com/terraform-providers/terraform-provider-random/issues/34))
+
+## 1.3.1 (May 22, 2018)
+
+BUG FIXES:
+
+* Add migration and new schema version for `resource_string` ([#29](https://github.com/terraform-providers/terraform-provider-random/issues/29))
+
+## 1.3.0 (May 21, 2018)
+
+BUG FIXES:
+
+* `random_integer` now supports update ([#25](https://github.com/terraform-providers/terraform-provider-random/issues/25))
+
+IMPROVEMENTS:
+
+* Add optional minimum character constraints to `random_string` ([#22](https://github.com/terraform-providers/terraform-provider-random/issues/22))
+
+## 1.2.0 (April 03, 2018)
+
+NEW FEATURES:
+
+* `random_integer` and `random_id` are now importable. ([#20](https://github.com/terraform-providers/terraform-provider-random/issues/20))
+
+## 1.1.0 (December 01, 2017)
+
+NEW FEATURES:
+
+* `random_integer` resource generates a single integer within a given range. ([#12](https://github.com/terraform-providers/terraform-provider-random/issues/12))
+
+## 1.0.0 (September 15, 2017)
+
+NEW FEATURES:
+
+* `random_string` resource generates random strings of a given length consisting of letters, digits and symbols. ([#5](https://github.com/terraform-providers/terraform-provider-random/issues/5))
+
+## 0.1.0 (June 21, 2017)
+
+NOTES:
+
+* Same functionality as that of Terraform 0.9.8. Repacked as part of [Provider Splitout](https://www.hashicorp.com/blog/upcoming-provider-changes-in-terraform-0-10/)
diff --git a/v3.6.0/.changes/3.5.0.md b/v3.6.0/.changes/3.5.0.md
new file mode 100644
index 0000000..c547a04
--- /dev/null
+++ b/v3.6.0/.changes/3.5.0.md
@@ -0,0 +1,6 @@
+## 3.5.0 (April 11, 2023)
+
+NOTES:
+
+* This Go module has been updated to Go 1.19 per the [Go support policy](https://golang.org/doc/devel/release.html#policy). Any consumers building on earlier Go versions may experience errors. ([#378](https://github.com/hashicorp/terraform-provider-random/issues/378))
+
diff --git a/v3.6.0/.changes/3.5.1.md b/v3.6.0/.changes/3.5.1.md
new file mode 100644
index 0000000..d538b2b
--- /dev/null
+++ b/v3.6.0/.changes/3.5.1.md
@@ -0,0 +1,6 @@
+## 3.5.1 (April 12, 2023)
+
+BUG FIXES:
+
+* resource/random_password: Prevent error with `bcrypt` by truncating the bytes that are hashed to a maximum length of 72 ([#397](https://github.com/hashicorp/terraform-provider-random/issues/397))
+
diff --git a/v3.6.0/.changes/3.6.0.md b/v3.6.0/.changes/3.6.0.md
new file mode 100644
index 0000000..a6f6482
--- /dev/null
+++ b/v3.6.0/.changes/3.6.0.md
@@ -0,0 +1,6 @@
+## 3.6.0 (December 04, 2023)
+
+FEATURES:
+
+* resource/random_bytes: New resource that generates an array of random bytes intended to be used as key or secret ([#272](https://github.com/hashicorp/terraform-provider-random/issues/272))
+
diff --git a/v3.6.0/.changes/unreleased/.gitkeep b/v3.6.0/.changes/unreleased/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v3.6.0/.changes/unreleased/.gitkeep
diff --git a/v3.6.0/.changie.yaml b/v3.6.0/.changie.yaml
new file mode 100644
index 0000000..2f65c89
--- /dev/null
+++ b/v3.6.0/.changie.yaml
@@ -0,0 +1,22 @@
+changesDir: .changes
+unreleasedDir: unreleased
+changelogPath: CHANGELOG.md
+versionExt: md
+versionFormat: '## {{.Version}} ({{.Time.Format "January 02, 2006"}})'
+kindFormat: '{{.Kind}}:'
+changeFormat: '* {{.Body}} ([#{{.Custom.Issue}}](https://github.com/hashicorp/terraform-provider-random/issues/{{.Custom.Issue}}))'
+custom:
+  - key: Issue
+    label: Issue/PR Number
+    type: int
+    minInt: 1
+kinds:
+  - label: BREAKING CHANGES
+  - label: NOTES
+  - label: FEATURES
+  - label: ENHANCEMENTS
+  - label: BUG FIXES
+newlines:
+  afterKind: 1
+  beforeKind: 1
+  endOfVersion: 2
diff --git a/v3.6.0/.copywrite.hcl b/v3.6.0/.copywrite.hcl
new file mode 100644
index 0000000..2cc5810
--- /dev/null
+++ b/v3.6.0/.copywrite.hcl
@@ -0,0 +1,31 @@
+schema_version = 1
+
+project {
+  license        = "MPL-2.0"
+  copyright_year = 2017
+
+
+  header_ignore = [
+    # changie tooling configuration and CHANGELOG entries (prose)
+    ".changes/unreleased/*.yaml",
+    ".changie.yaml",
+
+    # examples used within documentation (prose)
+    "examples/**",
+
+    # GitHub issue template configuration
+    ".github/ISSUE_TEMPLATE/*.yml",
+
+    # GitHub Actions workflow-specific configurations
+    ".github/labeler-*.yml",
+
+    # golangci-lint tooling configuration
+    ".golangci.yml",
+
+    # GoReleaser tooling configuration
+    ".goreleaser.yml",
+
+    # Release Engineering tooling configuration
+    ".release/*.hcl",
+  ]
+}
diff --git a/v3.6.0/.github/CODEOWNERS b/v3.6.0/.github/CODEOWNERS
new file mode 100644
index 0000000..922ee27
--- /dev/null
+++ b/v3.6.0/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @hashicorp/terraform-devex
diff --git a/v3.6.0/.github/CODE_OF_CONDUCT.md b/v3.6.0/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..0c8b092
--- /dev/null
+++ b/v3.6.0/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,5 @@
+# Code of Conduct
+
+HashiCorp Community Guidelines apply to you when interacting with the community here on GitHub and contributing code.
+
+Please read the full text at https://www.hashicorp.com/community-guidelines
diff --git a/v3.6.0/.github/CONTRIBUTING.md b/v3.6.0/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..3557248
--- /dev/null
+++ b/v3.6.0/.github/CONTRIBUTING.md
@@ -0,0 +1,148 @@
+# Contributing
+
+Thank you for investing your time and energy by contributing to our project: please ensure you are familiar
+with the [HashiCorp Code of Conduct](https://github.com/hashicorp/.github/blob/master/CODE_OF_CONDUCT.md).
+
+This provider is a HashiCorp **utility provider**, which means any bug fix and feature
+has to be considered in the context of the thousands/millions of configurations in which this provider is used.
+This is great as your contribution can have a big positive impact, but we have to assess potential negative impact too
+(e.g. breaking existing configurations). _Stability over features_.
+
+To provide some safety to the wider provider ecosystem, we strictly follow
+[semantic versioning](https://semver.org/) and HashiCorp's own
+[versioning specification](https://www.terraform.io/plugin/sdkv2/best-practices/versioning#versioning-specification).
+Any changes that could be considered as breaking will only be included as part of a major release.
+In case multiple breaking changes need to happen, we will group them in the next upcoming major release.
+
+## Asking Questions
+
+For questions, curiosity, or if still unsure what you are dealing with,
+please see the HashiCorp [Terraform Providers Discuss](https://discuss.hashicorp.com/c/terraform-providers/31)
+forum.
+
+## Reporting Vulnerabilities
+
+Please disclose security vulnerabilities responsibly by following the
+[HashiCorp Vulnerability Reporting guidelines](https://www.hashicorp.com/security#vulnerability-reporting).
+
+## Understanding the design
+
+Before proceeding with raising issues or submitting pull requests, it will probably help to familiarise yourself with
+the [design principles](../DESIGN.md) of this provider. This will aid your proposals, and help understand
+why we took certain decisions during development.
+
+## Raising Issues
+
+We welcome issues of all kinds including feature requests, bug reports or documentation suggestions.
+Below are guidelines for well-formed issues of each type.
+
+### Bug Reports
+
+* [ ] **Test against latest release**: Make sure you test against the latest available version of Terraform and the provider.
+  It is possible we may have already fixed the bug you're experiencing.
+* [ ] **Search for duplicates**: It's helpful to keep bug reports consolidated to one thread, so do a quick search
+  on existing bug reports to check if anybody else has reported the same thing.
+  You can scope searches by the label `bug` to help narrow things down.
+* [ ] **Include steps to reproduce**: Provide steps to reproduce the issue, along with code examples and/or real code,
+  so we can try to reproduce it. Without this, it makes it much harder (sometimes impossible) to fix the issue.
+
+### Feature Requests
+
+* [ ] **Search for possible duplicate requests**: It's helpful to keep requests consolidated to one thread,
+  so do a quick search on existing requests to check if anybody else has reported the same thing.
+  You can scope searches by the label `enhancement` to help narrow things down.
+* [ ] **Include a use case description**: In addition to describing the behavior of the feature you'd like to see added,
+  it's helpful to also make a case for why the feature would be important and how it would benefit
+  the provider and, potentially, the wider Terraform ecosystem.
+
+## New Pull Request
+
+Thank you for contributing!
+
+We are happy to review pull requests without associated issues,
+but we **highly recommend** starting by describing and discussing
+your problem or feature and attaching use cases to an issue first
+before raising a pull request.
+
+* [ ] **Early validation of idea and implementation plan**: provider development is complicated enough that there
+  are often several ways to implement something, each of which has different implications and tradeoffs.
+  Working through a plan of attack with the team before you dive into implementation will help ensure that you're
+  working in the right direction.
+* [ ] **Tests**: It may go without saying, but every new patch should be covered by tests wherever possible.
+  For bug-fixes, tests to prove the fix is valid. For features, tests to exercise the new code paths.
+* [ ] **Go Modules**: We use [Go Modules](https://github.com/golang/go/wiki/Modules) to manage and version our dependencies.
+  Please make sure that you reflect dependency changes in your pull requests appropriately
+  (e.g. `go get`, `go mod tidy` or other commands).
+  Refer to the [dependency updates](#dependency-updates) section for more information about how
+  this project maintains existing dependencies.
+* [ ] **Changelog**: Refer to the [changelog](#changelog) section for more information about how to create changelog entries.
+* [ ] **License Headers**: All source code requires a license header at the top of the file, refer to [License Headers](#license-headers) for information on how to autogenerate these headers.
+
+### Dependency Updates
+
+Dependency management is performed by [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates).
+Where possible, dependency updates should occur through that system to ensure all Go module files are appropriately
+updated and to prevent duplicated effort of concurrent update submissions.
+Once available, updates are expected to be verified and merged to prevent latent technical debt.
+
+### Changelog
+
+HashiCorp’s open-source projects have always maintained user-friendly, readable `CHANGELOG`s that allow
+practitioners and developers to tell at a glance whether a release should have any effect on them,
+and to gauge the risk of an upgrade.
+
+We follow Terraform Plugin
+[changelog specifications](https://www.terraform.io/plugin/sdkv2/best-practices/versioning#changelog-specification).
+
+#### Changie Automation Tool
+This provider uses the [Changie](https://changie.dev/) automation tool for changelog automation.
+To add a new entry to the `CHANGELOG` install Changie using the following [instructions](https://changie.dev/guide/installation/)
+and run
+```bash
+changie new
+```
+then choose a `kind` of change corresponding to the Terraform Plugin [changelog categories](https://developer.hashicorp.com/terraform/plugin/sdkv2/best-practices/versioning#categorization)
+and then fill out the body following the entry format. Changie will then prompt for a Github issue or pull request number.
+Repeat this process for any additional changes. The `.yaml` files created in the `.changes/unreleased` folder
+should be pushed the repository along with any code changes.
+
+#### Entry format
+
+Entries that are specific to _resources_ or _data sources_, they should look like:
+
+```markdown
+* resource/RESOURCE_NAME: ENTRY DESCRIPTION 
+
+* data-source/DATA-SOURCE_NAME: ENTRY DESCRIPTION
+```
+
+#### Pull Request Types to `CHANGELOG`
+
+The `CHANGELOG` is intended to show developer-impacting changes to the codebase for a particular version.
+If every change or commit to the code resulted in an entry, the `CHANGELOG` would become less useful for developers.
+The lists below are general guidelines to decide whether a change should have an entry.
+
+##### Changes that should not have a `CHANGELOG` entry
+
+* Documentation updates
+* Testing updates
+* Code refactoring
+
+##### Changes that may have a `CHANGELOG` entry
+
+* Dependency updates: If the update contains relevant bug fixes or enhancements that affect developers,
+  those should be called out.
+
+##### Changes that should have a `CHANGELOG` entry
+
+* Major features
+* Bug fixes
+* Enhancements
+* Deprecations
+* Breaking changes and removals
+
+### License Headers
+
+All source code files (excluding autogenerated files like `go.mod`, prose, and files excluded in [.copywrite.hcl](../.copywrite.hcl)) must have a license header at the top.
+
+This can be autogenerated by running `make generate` or running `go generate ./...` in the [/tools](../tools) directory.
diff --git a/v3.6.0/.github/ISSUE_TEMPLATE/Bug_Report.yml b/v3.6.0/.github/ISSUE_TEMPLATE/Bug_Report.yml
new file mode 100644
index 0000000..6227a8e
--- /dev/null
+++ b/v3.6.0/.github/ISSUE_TEMPLATE/Bug_Report.yml
@@ -0,0 +1,85 @@
+name: Bug Report
+description: Something is incorrect or not working as expected.
+labels: ["bug"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for taking the time to fill out this bug report! Please note that this issue tracker is only used for bug reports and feature requests. Other issues will be closed.
+
+        If you have a configuration, workflow, or other question, please go back to the issue chooser and select one of the question links.
+  - type: textarea
+    id: versions
+    attributes:
+      label: Terraform CLI and Provider Versions
+      description: What versions of Terraform CLI and the provider?
+      placeholder: Output of `terraform version` from configuration directory
+    validations:
+      required: true
+  - type: textarea
+    id: terraform-configuration
+    attributes:
+      label: Terraform Configuration
+      description: Please copy and paste any relevant Terraform configuration. This will be automatically formatted into code, so no need for backticks.
+      render: terraform
+    validations:
+      required: true
+  - type: textarea
+    id: expected-behavior
+    attributes:
+      label: Expected Behavior
+      description: What did you expect to happen?
+      placeholder: Description of what should have happened.
+    validations:
+      required: true
+  - type: textarea
+    id: actual-behavior
+    attributes:
+      label: Actual Behavior
+      description: What actually happened?
+      placeholder: Description of what actually happened.
+    validations:
+      required: true
+  - type: textarea
+    id: reproduction-steps
+    attributes:
+      label: Steps to Reproduce
+      description: List of steps to reproduce the issue.
+      value: |
+        1. `terraform apply`
+    validations:
+      required: true
+  - type: dropdown
+    id: impact
+    attributes:
+      label: How much impact is this issue causing?
+      description: High represents completely not able to use the provider or unexpected destruction of data/infrastructure. Medium represents unable to upgrade provider version or an issue with potential workaround. Low represents minor provider code, configuration, or documentation issues.
+      options:
+        - High
+        - Medium
+        - Low
+    validations:
+      required: true
+  - type: input
+    id: logs
+    attributes:
+      label: Logs
+      description: Please provide a link to a [GitHub Gist](https://gist.github.com) containing TRACE log output. [Terraform Debugging Documentation](https://www.terraform.io/internals/debugging)
+      placeholder: https://gist.github.com/example/12345678
+    validations:
+      required: false
+  - type: textarea
+    id: additional-information
+    attributes:
+      label: Additional Information
+      description: Are there any additional details about your environment, workflow, or recent changes that might be relevant? Have you discovered a workaround? Are there links to other related issues?
+    validations:
+      required: false
+  - type: checkboxes
+    id: terms
+    attributes:
+      label: Code of Conduct
+      description: By submitting this issue, you agree to follow our [Community Guidelines](https://www.hashicorp.com/community-guidelines).
+      options:
+        - label: I agree to follow this project's Code of Conduct
+          required: true
diff --git a/v3.6.0/.github/ISSUE_TEMPLATE/Feature_Request.yml b/v3.6.0/.github/ISSUE_TEMPLATE/Feature_Request.yml
new file mode 100644
index 0000000..275c48e
--- /dev/null
+++ b/v3.6.0/.github/ISSUE_TEMPLATE/Feature_Request.yml
@@ -0,0 +1,60 @@
+name: Feature Request
+description: Something is missing or could be improved.
+labels: ["enhancement"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for taking the time to fill out this feature request! Please note that this issue tracker is only used for bug reports and feature requests. Other issues will be closed.
+
+        If you have a configuration, workflow, or other question, please go back to the issue chooser and select one of the question links.
+  - type: textarea
+    id: versions
+    attributes:
+      label: Terraform CLI and Provider Versions
+      description: What versions of Terraform CLI and the provider?
+      placeholder: Output of `terraform version` from configuration directory
+    validations:
+      required: true
+  - type: textarea
+    id: use-case
+    attributes:
+      label: Use Cases or Problem Statement
+      description: What use cases or problems are you trying to solve?
+      placeholder: Description of use cases or problems.
+    validations:
+      required: true
+  - type: textarea
+    id: proposal
+    attributes:
+      label: Proposal
+      description: What solutions would you prefer?
+      placeholder: Description of proposed solutions.
+    validations:
+      required: true
+  - type: dropdown
+    id: impact
+    attributes:
+      label: How much impact is this issue causing?
+      description: High represents completely not able to use the provider without this. Medium represents unable to solve a specific problem or understand something. Low represents minor provider code, configuration, or documentation issues.
+      options:
+        - High
+        - Medium
+        - Low
+    validations:
+      required: true
+  - type: textarea
+    id: additional-information
+    attributes:
+      label: Additional Information
+      description: Are there any additional details about your environment, workflow, or recent changes that might be relevant? Have you discovered a workaround? Are there links to other related issues?
+    validations:
+      required: false
+  - type: checkboxes
+    id: terms
+    attributes:
+      label: Code of Conduct
+      description: By submitting this issue, you agree to follow our [Community Guidelines](https://www.hashicorp.com/community-guidelines).
+      options:
+        - label: I agree to follow this project's Code of Conduct
+          required: true
diff --git a/v3.6.0/.github/ISSUE_TEMPLATE/config.yml b/v3.6.0/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..cd2c84d
--- /dev/null
+++ b/v3.6.0/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+  - name: Terraform Provider Questions
+    url: https://discuss.hashicorp.com/c/terraform-providers/31
+    about: GitHub issues in this repository are only intended for bug reports and feature requests. Other issues will be closed. Please ask and answer questions through the Terraform Provider section of HashiCorp Discuss.
+  - name: Terraform Language or Workflow Questions
+    url: https://discuss.hashicorp.com/c/terraform-core
+    about: Please ask and answer language or workflow related questions through the Terraform Core section of HashiCorp Discuss.
diff --git a/v3.6.0/.github/SUPPORT.md b/v3.6.0/.github/SUPPORT.md
new file mode 100644
index 0000000..7b1f015
--- /dev/null
+++ b/v3.6.0/.github/SUPPORT.md
@@ -0,0 +1,6 @@
+# Support
+
+* Project [README](../README.md)
+* Official [Documentation](https://registry.terraform.io/providers/hashicorp/random/latest/docs)
+* Providers [Discuss forums](https://discuss.hashicorp.com/c/terraform-providers/31)
+* Terraform [Community](https://www.terraform.io/community.html) page
diff --git a/v3.6.0/.github/dependabot.yml b/v3.6.0/.github/dependabot.yml
new file mode 100644
index 0000000..a785244
--- /dev/null
+++ b/v3.6.0/.github/dependabot.yml
@@ -0,0 +1,14 @@
+# See GitHub's docs for more information on this file:
+# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates
+version: 2
+updates:
+  # Maintain dependencies for Go modules
+  - package-ecosystem: "gomod"
+    directory: "/"
+    schedule:
+      # Check for updates to Go modules every weekday
+      interval: "daily"
+  - package-ecosystem: "gomod"
+    directory: "/tools"
+    schedule:
+      interval: "daily"
diff --git a/v3.6.0/.github/labeler-issue-triage.yml b/v3.6.0/.github/labeler-issue-triage.yml
new file mode 100644
index 0000000..d1a51fd
--- /dev/null
+++ b/v3.6.0/.github/labeler-issue-triage.yml
@@ -0,0 +1,4 @@
+bug:
+  - 'panic:'
+crash:
+  - 'panic:'
diff --git a/v3.6.0/.github/labeler-pull-request-triage.yml b/v3.6.0/.github/labeler-pull-request-triage.yml
new file mode 100644
index 0000000..9c5d581
--- /dev/null
+++ b/v3.6.0/.github/labeler-pull-request-triage.yml
@@ -0,0 +1,6 @@
+dependencies:
+  - .github/dependabot.yml
+  - go.mod
+  - go.sum
+documentation:
+  - docs/**/*
diff --git a/v3.6.0/.github/workflows/add-content-to-project.yml b/v3.6.0/.github/workflows/add-content-to-project.yml
new file mode 100644
index 0000000..35166f2
--- /dev/null
+++ b/v3.6.0/.github/workflows/add-content-to-project.yml
@@ -0,0 +1,40 @@
+# Based on https://github.com/leonsteinhaeuser/project-beta-automations
+
+name: "Add Issues/PRs to TF Provider DevEx team board"
+
+on:
+  issues:
+    types: [opened, reopened]
+  pull_request_target:
+    # NOTE: The way content is added to project board is equivalent to an "upsert".
+    # Calling it multiple times will be idempotent.
+    #
+    # See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
+    # to see the reasoning behind using `pull_request_target` instead of `pull_request`
+    types: [opened, reopened, ready_for_review]
+
+jobs:
+  add-content-to-project:
+    name: "Add Content to project"
+    runs-on: ubuntu-latest
+    steps:
+      - name: "Set Issue to 'Priority = Triage Next'"
+        uses: leonsteinhaeuser/project-beta-automations@939000fb1900c9fc4f7b5058a09d9f833ebc6859 # v2.2.1
+        if: github.event_name == 'issues'
+        with:
+          gh_token: ${{ secrets.TF_DEVEX_PROJECT_GITHUB_TOKEN }}
+          organization: "hashicorp"
+          project_id: 99      #< https://github.com/orgs/hashicorp/projects/99
+          resource_node_id: ${{ github.event.issue.node_id }}
+          operation_mode: custom_field
+          custom_field_values: '[{\"name\":\"Priority\",\"type\":\"single_select\",\"value\":\"Triage Next\"}]'
+      - name: "Set Pull Request to 'Priority = Triage Next'"
+        uses: leonsteinhaeuser/project-beta-automations@939000fb1900c9fc4f7b5058a09d9f833ebc6859 # v2.2.1
+        if: github.event_name == 'pull_request_target'
+        with:
+          gh_token: ${{ secrets.TF_DEVEX_PROJECT_GITHUB_TOKEN }}
+          organization: "hashicorp"
+          project_id: 99      #< https://github.com/orgs/hashicorp/projects/99
+          resource_node_id: ${{ github.event.pull_request.node_id }}
+          operation_mode: custom_field
+          custom_field_values: '[{\"name\":\"Priority\",\"type\":\"single_select\",\"value\":\"Triage Next\"}]'
diff --git a/v3.6.0/.github/workflows/ci-changie.yml b/v3.6.0/.github/workflows/ci-changie.yml
new file mode 100644
index 0000000..8ec8b11
--- /dev/null
+++ b/v3.6.0/.github/workflows/ci-changie.yml
@@ -0,0 +1,23 @@
+# Continuous integration handling for changie
+name: ci-changie
+
+on:
+  pull_request:
+    paths:
+      - .changes/unreleased/*.yaml
+      - .changie.yaml
+      - .github/workflows/ci-changie.yml
+
+permissions:
+  contents: read
+
+jobs:
+  check:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+      - uses: miniscruff/changie-action@6dcc2533cac0495148ed4046c438487e4dceaa23 # v2.0.0
+        with:
+          version: latest
+          args: batch patch --dry-run
+
diff --git a/v3.6.0/.github/workflows/compliance.yml b/v3.6.0/.github/workflows/compliance.yml
new file mode 100644
index 0000000..4be40b1
--- /dev/null
+++ b/v3.6.0/.github/workflows/compliance.yml
@@ -0,0 +1,17 @@
+name: compliance
+
+on:
+  pull_request:
+
+permissions:
+  contents: read
+
+jobs:
+  # Reference: ENGSRV-059
+  copywrite:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+      - uses: hashicorp/setup-copywrite@867a1a2a064a0626db322392806428f7dc59cb3e # v1.1.2
+      - run: copywrite headers --plan
+      - run: copywrite license --plan
diff --git a/v3.6.0/.github/workflows/issue-comment-created.yml b/v3.6.0/.github/workflows/issue-comment-created.yml
new file mode 100644
index 0000000..0c4f898
--- /dev/null
+++ b/v3.6.0/.github/workflows/issue-comment-created.yml
@@ -0,0 +1,15 @@
+name: Issue Comment Created Triage
+
+on:
+  issue_comment:
+    types: [created]
+
+jobs:
+  issue_comment_triage:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1.3.0
+        with:
+          labels: |
+            stale
+            waiting-response
diff --git a/v3.6.0/.github/workflows/issue-opened.yml b/v3.6.0/.github/workflows/issue-opened.yml
new file mode 100644
index 0000000..3dac637
--- /dev/null
+++ b/v3.6.0/.github/workflows/issue-opened.yml
@@ -0,0 +1,16 @@
+name: Issue Opened Triage
+
+on:
+  issues:
+    types: [opened]
+
+jobs:
+  issue_triage:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+    - uses: github/issue-labeler@6bea9ed491bb74fce38775b3d863e64a59dbd9eb # v3.3
+      with:
+        repo-token: "${{ secrets.GITHUB_TOKEN }}"
+        configuration-path: .github/labeler-issue-triage.yml
+        enable-versioned-regex: 0
diff --git a/v3.6.0/.github/workflows/jira-sync.yml b/v3.6.0/.github/workflows/jira-sync.yml
new file mode 100644
index 0000000..737d56a
--- /dev/null
+++ b/v3.6.0/.github/workflows/jira-sync.yml
@@ -0,0 +1,39 @@
+on:
+  issues:
+    types: [closed, deleted, reopened]
+  pull_request_target:
+    types: [closed, reopened]
+
+name: Jira Sync
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    name: Jira sync
+    steps:
+
+    - name: Login
+      uses: atlassian/gajira-login@45fd029b9f1d6d8926c6f04175aa80c0e42c9026 # v3.0.1
+      if: contains(github.event.pull_request.labels.*.name, 'tf-devex-triage') || contains(github.event.issue.labels.*.name, 'tf-devex-triage')
+      env:
+        JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
+        JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
+        JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
+    - name: Search for existing issue
+      id: search
+      if: contains(github.event.pull_request.labels.*.name, 'tf-devex-triage') || contains(github.event.issue.labels.*.name, 'tf-devex-triage')
+      uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2
+      with:
+        jql: 'project="TFECO" and "Team (R&D)[Labels]"="TF-DevEx" and description ~ "${{ github.event.issue.html_url || github.event.pull_request.html_url }}" and labels in (Github)'
+    - name: Close task
+      if: ( github.event.action == 'closed' || github.event.action == 'deleted' ) && steps.search.outputs.issue
+      uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3.0.1
+      with:
+        issue: ${{ steps.search.outputs.issue }}
+        transition: "Closed"
+    - name: Reopen task
+      if: github.event.action == 'reopened' && steps.search.outputs.issue
+      uses: atlassian/gajira-transition@38fc9cd61b03d6a53dd35fcccda172fe04b36de3 # v3.0.1
+      with:
+        issue: ${{ steps.search.outputs.issue }}
+        transition: "To Do"
diff --git a/v3.6.0/.github/workflows/pull-request.yml b/v3.6.0/.github/workflows/pull-request.yml
new file mode 100644
index 0000000..ef73062
--- /dev/null
+++ b/v3.6.0/.github/workflows/pull-request.yml
@@ -0,0 +1,31 @@
+name: "Pull Request Triage"
+
+on: [pull_request_target]
+
+permissions:
+  # CodelyTV/pr-size-labeler uses issues URL for labeling
+  issues: write
+  pull-requests: write
+
+jobs:
+  triage:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
+      with:
+        configuration-path: .github/labeler-pull-request-triage.yml
+        repo-token: "${{ secrets.GITHUB_TOKEN }}"
+    - uses: CodelyTV/pr-size-labeler@54ef36785e9f4cb5ecf1949cfc9b00dbb621d761 # v1.8.1
+      with:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        xs_label: 'size/XS'
+        xs_max_size: '30'
+        s_label: 'size/S'
+        s_max_size: '60'
+        m_label: 'size/M'
+        m_max_size: '150'
+        l_label: 'size/L'
+        l_max_size: '300'
+        xl_label: 'size/XL'
+        message_if_xl: ''
+        files_to_ignore: 'go.sum'
diff --git a/v3.6.0/.github/workflows/release.yml b/v3.6.0/.github/workflows/release.yml
new file mode 100644
index 0000000..611d2e5
--- /dev/null
+++ b/v3.6.0/.github/workflows/release.yml
@@ -0,0 +1,118 @@
+name: Release
+
+on:
+  workflow_dispatch:
+    inputs:
+      versionNumber:
+        description: 'Release version number (v#.#.#)'
+        type: string
+        required: true
+
+permissions:
+  contents: read # Changelog commit operations use service account PAT
+
+jobs:
+  changelog-version:
+    runs-on: ubuntu-latest
+    outputs:
+      version: ${{ steps.changelog-version.outputs.version }}
+    steps:
+      - id: changelog-version
+        run: echo "version=$(echo "${{ inputs.versionNumber }}" | cut -c 2-)" >> "$GITHUB_OUTPUT"
+
+  changelog:
+    needs: changelog-version
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          fetch-depth: 0
+          # Avoid persisting GITHUB_TOKEN credentials as they take priority over our service account PAT for `git push` operations
+          # More details: https://github.com/actions/checkout/blob/b4626ce19ce1106186ddf9bb20e706842f11a7c3/adrs/0153-checkout-v2.md#persist-credentials
+          persist-credentials: false
+
+      - name: Batch changes
+        uses: miniscruff/changie-action@6dcc2533cac0495148ed4046c438487e4dceaa23 # v2.0.0
+        with:
+          version: latest
+          args: batch ${{ needs.changelog-version.outputs.version }}
+
+      - name: Merge changes
+        uses: miniscruff/changie-action@6dcc2533cac0495148ed4046c438487e4dceaa23 # v2.0.0
+        with:
+          version: latest
+          args: merge
+
+      - name: Git push changelog
+        run: |
+          git config --global user.name "${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}"
+          git config --global user.email "${{ vars.TF_DEVEX_CI_COMMIT_EMAIL }}"
+          git add .
+          git commit -a -m "Update changelog"
+          git push "https://${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}:${{ secrets.TF_DEVEX_COMMIT_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
+
+  release-tag:
+    needs: changelog
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          fetch-depth: 0
+          # Default input is the SHA that initially triggered the workflow. As we created a new commit in the previous job,
+          # to ensure we get the latest commit we use the ref for checkout: 'refs/heads/<branch_name>'
+          ref: ${{ github.ref }}
+          # Avoid persisting GITHUB_TOKEN credentials as they take priority over our service account PAT for `git push` operations
+          # More details: https://github.com/actions/checkout/blob/b4626ce19ce1106186ddf9bb20e706842f11a7c3/adrs/0153-checkout-v2.md#persist-credentials
+          persist-credentials: false
+
+      - name: Git push release tag
+        run: |
+          git config --global user.name "${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}"
+          git config --global user.email "${{ vars.TF_DEVEX_CI_COMMIT_EMAIL }}"
+          
+          git tag "${{ inputs.versionNumber }}"
+          git push "https://${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}:${{ secrets.TF_DEVEX_COMMIT_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" "${{ inputs.versionNumber }}"
+
+  release-notes:
+    needs: [ changelog-version, changelog, release-tag ]
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          ref: ${{ inputs.versionNumber }}
+          fetch-depth: 0
+
+      - name: Generate Release Notes
+        run: |
+          cd .changes
+          sed -e "1{/# /d;}" -e "2{/^$/d;}" ${{ needs.changelog-version.outputs.version }}.md > release-notes.txt
+
+      - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
+        with:
+          name: release-notes
+          path: ./.changes/release-notes.txt
+          retention-days: 1
+
+  terraform-provider-release:
+    name: 'Terraform Provider Release'
+    needs: [ release-notes ]
+    permissions:
+      contents: write # Needed for goreleaser to create GitHub release
+    uses: hashicorp/ghaction-terraform-provider-release/.github/workflows/hashicorp.yml@01981baad5d35ce2342924e60ae91cf69fe31fd0 # v2.3.0
+    secrets:
+      hc-releases-key-prod: '${{ secrets.HC_RELEASES_KEY_PROD }}'
+      hc-releases-key-staging: '${{ secrets.HC_RELEASES_KEY_STAGING }}'
+      hc-releases-github-token: '${{ secrets.HASHI_RELEASES_GITHUB_TOKEN }}'
+      hc-releases-terraform-registry-sync-token: '${{ secrets.TF_PROVIDER_RELEASE_TERRAFORM_REGISTRY_SYNC_TOKEN }}'
+      setup-signore-github-token: '${{ secrets.HASHI_SIGNORE_GITHUB_TOKEN }}'
+      signore-client-id: '${{ secrets.SIGNORE_CLIENT_ID }}'
+      signore-client-secret: '${{ secrets.SIGNORE_CLIENT_SECRET }}'
+      hc-releases-host-staging: '${{ secrets.HC_RELEASES_HOST_STAGING }}'
+      hc-releases-host-prod: '${{ secrets.HC_RELEASES_HOST_PROD }}'
+    with:
+      release-notes: true
+      setup-go-version-file: 'go.mod'
+      # Product Version (e.g. v1.2.3)
+      product-version: '${{ inputs.versionNumber }}'
diff --git a/v3.6.0/.github/workflows/send-to-jira.yml b/v3.6.0/.github/workflows/send-to-jira.yml
new file mode 100644
index 0000000..cee84f6
--- /dev/null
+++ b/v3.6.0/.github/workflows/send-to-jira.yml
@@ -0,0 +1,37 @@
+on:
+  issues:
+    types: [labeled]
+
+name: Jira Sync
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    name: Jira sync
+    steps:
+
+    - name: Login
+      uses: atlassian/gajira-login@45fd029b9f1d6d8926c6f04175aa80c0e42c9026 # v3.0.1
+      if: github.event.label.name == 'tf-devex-triage'
+      env:
+        JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
+        JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
+        JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
+    - name: Search for existing issue
+      id: search
+      if: github.event.label.name == 'tf-devex-triage'
+      uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2
+      with:
+        jql: 'project="TFECO" and "Team (R&D)[Labels]"="TF-DevEx" and description ~ "${{ github.event.issue.html_url || github.event.pull_request.html_url }}" and labels in (Github)'
+
+    - name: Create task in DevEx board
+      if: github.event.label.name == 'tf-devex-triage' && !steps.search.outputs.issue
+      uses: atlassian/gajira-create@59e177c4f6451399df5b4911c2211104f171e669 # v3.0.1
+      with:
+        project: TFECO
+        issuetype: "Task"
+        summary: "[GH] ${{ github.event.issue.title || github.event.pull_request.title }}"
+        description: "${{ github.event.issue.html_url || github.event.pull_request.html_url }} \n Synced by Github Actions, tagged by ${{ github.actor }}"
+        # customfield_10091 is Team (R&D)
+        fields: '{"customfield_10091": ["TF-DevEx"], "labels": ["Github"]}'
+
diff --git a/v3.6.0/.github/workflows/test.yml b/v3.6.0/.github/workflows/test.yml
new file mode 100644
index 0000000..b5abfb2
--- /dev/null
+++ b/v3.6.0/.github/workflows/test.yml
@@ -0,0 +1,80 @@
+name: Test
+
+on:
+  pull_request:
+    branches: [ main ]
+    paths-ignore:
+      - 'README.md'
+      - 'CHANGELOG.md'
+      - 'website/*'
+  push:
+    branches: [ main ]
+    paths-ignore:
+      - 'README.md'
+      - 'CHANGELOG.md'
+      - 'website/*'
+
+jobs:
+  build:
+    name: Build
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+
+    - name: Check out code into the Go module directory
+      uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+
+    - name: Set up Go
+      uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
+      with:
+        go-version-file: 'go.mod'
+      id: go
+
+    - name: Run linters
+      uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
+      with:
+        version: latest
+
+    - name: Generate
+      run: make generate
+
+    - name: Confirm no diff
+      run: |
+        git diff --compact-summary --exit-code || \
+          (echo "*** Unexpected differences after code generation. Run 'make generate' and commit."; exit 1)
+
+    - name: Build
+      run: make build
+
+  test:
+    name: 'Acc. Tests (OS: ${{ matrix.os }} / TF: ${{ matrix.terraform }})'
+    needs: build
+    runs-on: ${{ matrix.os }}
+    timeout-minutes: 20
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - macos-latest
+          - windows-latest
+          - ubuntu-latest
+        terraform: ${{ fromJSON(vars.TF_VERSIONS_PROTOCOL_V5) }}
+    steps:
+
+    - name: Check out code
+      uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+
+    - name: Setup Go
+      uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
+      with:
+        go-version-file: 'go.mod'
+        check-latest: true
+
+    - name: Setup Terraform ${{ matrix.terraform }}
+      uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3
+      with:
+        terraform_version: ${{ matrix.terraform }}.*
+        terraform_wrapper: false
+
+    - name: Run acceptance test
+      run: make testacc
diff --git a/v3.6.0/.gitignore b/v3.6.0/.gitignore
new file mode 100644
index 0000000..5982d2c
--- /dev/null
+++ b/v3.6.0/.gitignore
@@ -0,0 +1,31 @@
+*.dll
+*.exe
+.DS_Store
+example.tf
+terraform.tfplan
+terraform.tfstate
+bin/
+modules-dev/
+/pkg/
+website/.vagrant
+website/.bundle
+website/build
+website/node_modules
+.vagrant/
+*.backup
+./*.tfstate
+.terraform/
+*.log
+*.bak
+*~
+.*.swp
+.idea
+*.iml
+*.test
+*.iml
+
+website/vendor
+
+# Test exclusions
+!command/test-fixtures/**/*.tfstate
+!command/test-fixtures/**/.terraform/
diff --git a/v3.6.0/.golangci.yml b/v3.6.0/.golangci.yml
new file mode 100644
index 0000000..e7976eb
--- /dev/null
+++ b/v3.6.0/.golangci.yml
@@ -0,0 +1,25 @@
+issues:
+  max-per-linter: 0
+  max-same-issues: 0
+
+linters:
+  disable-all: true
+  enable:
+    - durationcheck
+    - errcheck
+    - exportloopref
+    - forcetypeassert
+    - godot
+    - gofmt
+    - gosimple
+    - ineffassign
+    - makezero
+    - misspell
+    - nilerr
+    - predeclared
+    - staticcheck
+    - tenv
+    - unconvert
+    - unparam
+    - unused
+    - vet
\ No newline at end of file
diff --git a/v3.6.0/.goreleaser.yml b/v3.6.0/.goreleaser.yml
new file mode 100644
index 0000000..90b209d
--- /dev/null
+++ b/v3.6.0/.goreleaser.yml
@@ -0,0 +1,77 @@
+archives:
+  - files:
+      # Ensure only built binary is archived
+      - 'none*'
+    format: zip
+    name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
+before:
+  hooks:
+    - 'go mod download'
+builds:
+  - # Binary naming only required for Terraform CLI 0.12
+    binary: '{{ .ProjectName }}_v{{ .Version }}_x5'
+    env:
+      - CGO_ENABLED=0
+    flags:
+      - -trimpath
+    goos:
+      - darwin
+      - freebsd
+      - linux
+      - windows
+    goarch:
+      - '386'
+      - amd64
+      - arm
+      - arm64
+    ignore:
+      - goarch: arm
+        goos: windows
+      - goarch: arm64
+        goos: freebsd
+      - goarch: arm64
+        goos: windows
+    ldflags:
+      - -s -w -X main.Version={{.Version}}
+    mod_timestamp: '{{ .CommitTimestamp }}'
+checksum:
+  algorithm: sha256
+  extra_files:
+    - glob: 'terraform-registry-manifest.json'
+      name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
+  name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
+milestones:
+  - close: true
+publishers:
+  - checksum: true
+    # Terraform CLI 0.10 - 0.11 perform discovery via HTTP headers on releases.hashicorp.com
+    # For providers which have existed since those CLI versions, exclude
+    # discovery by setting the protocol version headers to 5.
+    cmd: |
+      hc-releases upload -product {{ .ProjectName }} -version {{ .Version }} -file={{ .ArtifactPath }}={{ .ArtifactName }} -header=x-terraform-protocol-version=5 -header=x-terraform-protocol-versions=5.0
+    env:
+      - HC_RELEASES_HOST={{ .Env.HC_RELEASES_HOST }}
+      - HC_RELEASES_KEY={{ .Env.HC_RELEASES_KEY }}
+    extra_files:
+      - glob: 'terraform-registry-manifest.json'
+        name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
+    name: upload
+    signature: true
+release:
+  extra_files:
+    - glob: 'terraform-registry-manifest.json'
+      name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
+  ids:
+    - none
+signs:
+  - args: ["sign", "--dearmor", "--file", "${artifact}", "--out", "${signature}"]
+    artifacts: checksum
+    cmd: signore
+    signature: ${artifact}.sig
+  - args: ["sign", "--dearmor", "--file", "${artifact}", "--out", "${signature}"]
+    artifacts: checksum
+    cmd: signore
+    id: key-id
+    signature: ${artifact}.72D7468F.sig
+snapshot:
+  name_template: "{{ .Tag }}-next"
diff --git a/v3.6.0/.release/release-metadata.hcl b/v3.6.0/.release/release-metadata.hcl
new file mode 100644
index 0000000..5941632
--- /dev/null
+++ b/v3.6.0/.release/release-metadata.hcl
@@ -0,0 +1,2 @@
+url_source_repository      = "https://github.com/hashicorp/terraform-provider-random"
+url_license                = "https://github.com/hashicorp/terraform-provider-random/blob/main/LICENSE"
diff --git a/v3.6.0/CHANGELOG.md b/v3.6.0/CHANGELOG.md
new file mode 100644
index 0000000..b724366
--- /dev/null
+++ b/v3.6.0/CHANGELOG.md
@@ -0,0 +1,232 @@
+## 3.6.0 (December 04, 2023)
+
+FEATURES:
+
+* resource/random_bytes: New resource that generates an array of random bytes intended to be used as key or secret ([#272](https://github.com/hashicorp/terraform-provider-random/issues/272))
+
+## 3.5.1 (April 12, 2023)
+
+BUG FIXES:
+
+* resource/random_password: Prevent error with `bcrypt` by truncating the bytes that are hashed to a maximum length of 72 ([#397](https://github.com/hashicorp/terraform-provider-random/issues/397))
+
+## 3.5.0 (April 11, 2023)
+
+NOTES:
+
+* This Go module has been updated to Go 1.19 per the [Go support policy](https://golang.org/doc/devel/release.html#policy). Any consumers building on earlier Go versions may experience errors. ([#378](https://github.com/hashicorp/terraform-provider-random/issues/378))
+
+## 3.4.3 (September 08, 2022)
+
+NOTES:
+
+* resource/random_password: The values for `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special`, `min_upper` and `length` could be null if the resource was imported using version 3.3.1 or before. The value for `length` will be automatically calculated and assigned and default values will be assigned for the other attributes listed after this upgrade ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_string: The values for `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special`, `min_upper` and `length` could be null if the resource was imported using version 3.3.1 or before. The value for `length` will be automatically calculated and assigned and default values will be assigned for the other attributes listed after this upgrade ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_password: If the resource was created between versions 3.4.0 and 3.4.2, the `bcrypt_hash` value would not correctly verify against the `result` value. Affected resources will automatically regenerate a valid `bcrypt_hash` after this upgrade. ([#308](https://github.com/hashicorp/terraform-provider-random/pull/308))
+* resource/random_password: The `override_special` attribute may show a plan difference from empty string (`""`) to `null` if previously applied with version 3.4.2. The plan should show this as an in-place update and it should occur only once after upgrading. ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+* resource/random_string: The `override_special` attribute may show a plan difference from empty string (`""`) to `null` if previously applied with version 3.4.2. The plan should show this as an in-place update and it should occur only once after upgrading. ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+
+BUG FIXES:
+
+* resource/random_password: Assign default values to `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special` and `min_upper` if null. Assign length of `result` to `length` if null ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_string: Assign default values to `lower`, `number`, `special`, `upper`, `min_lower`, `min_numeric`, `min_special` and `min_upper` if null. Assign length of `result` to `length` if null ([#313](https://github.com/hashicorp/terraform-provider-random/pull/313))
+* resource/random_password: Fixed incorrect `bcrypt_hash` generation since version 3.4.0 ([#308](https://github.com/hashicorp/terraform-provider-random/pull/308))
+* resource/random_password: Prevented difference with `override_special` when upgrading from version 3.3.2 and earlier ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+* resource/random_string: Prevented difference with `override_special` when upgrading from version 3.3.2 and earlier ([#312](https://github.com/hashicorp/terraform-provider-random/pull/312))
+
+## 3.4.2 (September 02, 2022)
+
+BUG FIXES:
+
+* all: Prevent `keeper` with `null` values from forcing replacement ([305](https://github.com/hashicorp/terraform-provider-random/pull/305)).
+* resource/random_password: During upgrade state, ensure `min_upper` is populated ([304](https://github.com/hashicorp/terraform-provider-random/pull/304)).
+* resource/random_string: During upgrade state, ensure `min_upper` is populated ([304](https://github.com/hashicorp/terraform-provider-random/pull/304)).
+
+## 3.4.1 (August 31, 2022)
+
+BUG FIXES:
+
+* resource/random_password: During attribute plan modifier, only return error if `number` and `numeric` are both present and do not match ([301](https://github.com/hashicorp/terraform-provider-random/pull/301)).
+* resource/random_string: During attribute plan modifier, only return error if `number` and `numeric` are both present and do not match ([301](https://github.com/hashicorp/terraform-provider-random/pull/301)).
+
+## 3.4.0 (August 30, 2022)
+
+NOTES:
+
+* Provider has been re-written using the new [`terraform-plugin-framework`](https://www.terraform.io/plugin/framework) ([#177](https://github.com/hashicorp/terraform-provider-random/pull/177)).
+* resource/random_password: `number` was deprecated in [v3.3.0](https://github.com/hashicorp/terraform-provider-random/releases/tag/v3.3.0) and will be removed in the next major release.
+* resource/random_string: `number` was deprecated in [v3.3.0](https://github.com/hashicorp/terraform-provider-random/releases/tag/v3.3.0) and will be removed in the next major release.
+
+## 3.3.2 (June 23, 2022)
+
+BUG FIXES:
+
+* resource/random_password: When importing set defaults for all attributes that have a default defined ([256](https://github.com/hashicorp/terraform-provider-random/pull/256)).
+* resource/random_string: When importing set defaults for all attributes that have a default defined ([256](https://github.com/hashicorp/terraform-provider-random/pull/256)).
+
+## 3.3.1 (June 07, 2022)
+
+BUG FIXES:
+
+* resource/random_password: During schema upgrade, copy value of attribute `number` to attribute `numeric`, only if said value is a boolean (i.e. not `null`) ([262](https://github.com/hashicorp/terraform-provider-random/pull/262))
+* resource/random_string: During schema upgrade, copy value of attribute `number` to attribute `numeric`, only if said value is a boolean (i.e. not `null`) ([262](https://github.com/hashicorp/terraform-provider-random/pull/262))
+
+## 3.3.0 (June 06, 2022)
+
+ENHANCEMENTS:
+
+* resource/random_password: `number` is now deprecated and `numeric` has been added to align attribute naming. `number` will be removed in the next major release ([#258](https://github.com/hashicorp/terraform-provider-random/pull/258)).
+* resource/random_string: `number` is now deprecated and `numeric` has been added to align attribute naming. `number` will be removed in the next major release ([#258](https://github.com/hashicorp/terraform-provider-random/pull/258)).
+
+## 3.2.0 (May 18, 2022)
+
+NEW FEATURES:
+
+* resource/random_password: New attribute `bcrypt_hash`, which is the hashed password ([73](https://github.com/hashicorp/terraform-provider-random/pull/73), [102](https://github.com/hashicorp/terraform-provider-random/issues/102), [254](https://github.com/hashicorp/terraform-provider-random/pull/254))
+
+NOTES:
+
+* Adds or updates DESIGN.md, README.md, CONTRIBUTING.md and SUPPORT.md docs ([176](https://github.com/hashicorp/terraform-provider-random/issues/176), [235](https://github.com/hashicorp/terraform-provider-random/issues/235), [242](https://github.com/hashicorp/terraform-provider-random/pull/242)).
+* Removes usage of deprecated fields, types and functions ([243](https://github.com/hashicorp/terraform-provider-random/issues/243), [244](https://github.com/hashicorp/terraform-provider-random/pull/244)).
+* Tests all minor Terraform versions ([238](https://github.com/hashicorp/terraform-provider-random/issues/238), [241](https://github.com/hashicorp/terraform-provider-random/pull/241))
+* Switches to linting with golangci-lint ([237](https://github.com/hashicorp/terraform-provider-random/issues/237), [240](https://github.com/hashicorp/terraform-provider-random/pull/240)).
+
+## 3.1.3 (April 22, 2022)
+
+BUG FIXES:
+
+* resource/random_password: Prevent crash when length is less than 0 ([#129](https://github.com/hashicorp/terraform-provider-random/issues/129), [#181](https://github.com/hashicorp/terraform-provider-random/issues/181), [#200](https://github.com/hashicorp/terraform-provider-random/pull/200), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+* resource/random_string: Prevent crash when length is less than 0 ([#129](https://github.com/hashicorp/terraform-provider-random/issues/129), [#181](https://github.com/hashicorp/terraform-provider-random/issues/181), [#200](https://github.com/hashicorp/terraform-provider-random/pull/200), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+* resource/random_password: Prevent confusing inconsistent result error when length is 0 ([#222](https://github.com/hashicorp/terraform-provider-random/issues/222), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+* resource/random_string: Prevent confusing inconsistent result error when length is 0 ([#222](https://github.com/hashicorp/terraform-provider-random/issues/222), [#233](https://github.com/hashicorp/terraform-provider-random/issues/233)).
+
+## 3.1.2 (March 17, 2022)
+
+BUG FIXES:
+
+* resource/random_pet: Prevented deterministic results since 3.1.1 ([#217](https://github.com/hashicorp/terraform-provider-random/issues/217). 
+
+## 3.1.1 (March 16, 2022)
+
+NOTES:
+
+* Updated [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs) to `v0.7.0`:
+  this improves generated documentation, with attributes now correctly formatted as `code`
+  and provided with anchors.
+* Functionally identical to the previous 3.1.0 release.
+
+## 3.1.0 (February 19, 2021)
+
+Binary releases of this provider now include the darwin-arm64 platform. This version contains no further changes.
+
+## 3.0.1 (January 12, 2021)
+
+BUG FIXES:
+
+* `resource_integer`: Integers in state that do not cleanly fit into float64s no longer lose their precision ([#132](https://github.com/terraform-providers/terraform-provider-random/issues/132))
+
+## 3.0.0 (October 09, 2020)
+
+Binary releases of this provider will now include the linux-arm64 platform.
+
+BREAKING CHANGES:
+
+* Upgrade to version 2 of the Terraform Plugin SDK, which drops support for Terraform 0.11. This provider will continue to work as expected for users of Terraform 0.11, which will not download the new version. ([#118](https://github.com/terraform-providers/terraform-provider-random/issues/118))
+* Remove deprecated `b64` attribute ([#118](https://github.com/terraform-providers/terraform-provider-random/issues/118))
+
+## 2.3.1 (October 26, 2020)
+
+NOTES: This version is identical to v2.3.0, but has been compiled using Go v1.14.5 to fix https://github.com/hashicorp/terraform-provider-random/issues/120.
+
+## 2.3.0 (July 07, 2020)
+
+NOTES:
+
+* The provider now uses the binary driver for acceptance tests ([#99](https://github.com/terraform-providers/terraform-provider-random/issues/99))
+
+NEW FEATURES:
+
+* Added import handling for `random_string` and `random_password` ([#104](https://github.com/terraform-providers/terraform-provider-random/issues/104))
+
+## 2.2.1 (September 25, 2019)
+
+NOTES:
+
+* The provider has switched to the standalone TF SDK, there should be no noticeable impact on compatibility. ([#76](https://github.com/terraform-providers/terraform-provider-random/issues/76))
+
+## 2.2.0 (August 08, 2019)
+
+NEW FEATURES:
+
+* `random_password` is similar to `random_string` but is marked sensitive for logs and output [[#52](https://github.com/terraform-providers/terraform-provider-random/issues/52)] 
+
+## 2.1.2 (April 30, 2019)
+
+* This release includes another Terraform SDK upgrade intended to align with that being used for other providers as we prepare for the Core v0.12.0 release. It should have no significant changes in behavior for this provider.
+
+## 2.1.1 (April 12, 2019)
+
+* This release includes only a Terraform SDK upgrade intended to align with that being used for other providers as we prepare for the Core v0.12.0 release. It should have no significant changes in behavior for this provider.
+
+## 2.1.0 (March 20, 2019)
+
+IMPROVEMENTS:
+
+* The provider is now compatible with Terraform v0.12, while retaining compatibility with prior versions.
+
+## 2.0.0 (August 15, 2018)
+
+BACKWARDS INCOMPATIBILITIES / NOTES:
+* `random_string`: set the ID for random_string resources to "none". Any terraform configuration referring to `random_string.foo.id` will need to be updated to reference `random_string.foo.result` ([#17](https://github.com/terraform-providers/terraform-provider-random/issues/17))
+
+NEW FEATURES:
+
+* `random_uuid` generates random uuid string that is intended to be used as unique identifiers for other resources ([#38](https://github.com/terraform-providers/terraform-provider-random/issues/38))
+
+BUG FIXES: 
+* Use UnixNano() instead of Unix() for the current time seed in NewRand() ([#27](https://github.com/terraform-providers/terraform-provider-random/issues/27))
+* `random_shuffle`: if `random_shuffle` is given an empty list, it will return an empty list
+
+IMPROVEMENTS:
+
+* Replace ReadPet function in `resource_pet` with schema.Noop ([#34](https://github.com/terraform-providers/terraform-provider-random/issues/34))
+
+## 1.3.1 (May 22, 2018)
+
+BUG FIXES:
+
+* Add migration and new schema version for `resource_string` ([#29](https://github.com/terraform-providers/terraform-provider-random/issues/29))
+
+## 1.3.0 (May 21, 2018)
+
+BUG FIXES:
+
+* `random_integer` now supports update ([#25](https://github.com/terraform-providers/terraform-provider-random/issues/25))
+
+IMPROVEMENTS:
+
+* Add optional minimum character constraints to `random_string` ([#22](https://github.com/terraform-providers/terraform-provider-random/issues/22))
+
+## 1.2.0 (April 03, 2018)
+
+NEW FEATURES:
+
+* `random_integer` and `random_id` are now importable. ([#20](https://github.com/terraform-providers/terraform-provider-random/issues/20))
+
+## 1.1.0 (December 01, 2017)
+
+NEW FEATURES:
+
+* `random_integer` resource generates a single integer within a given range. ([#12](https://github.com/terraform-providers/terraform-provider-random/issues/12))
+
+## 1.0.0 (September 15, 2017)
+
+NEW FEATURES:
+
+* `random_string` resource generates random strings of a given length consisting of letters, digits and symbols. ([#5](https://github.com/terraform-providers/terraform-provider-random/issues/5))
+
+## 0.1.0 (June 21, 2017)
+
+NOTES:
+
+* Same functionality as that of Terraform 0.9.8. Repacked as part of [Provider Splitout](https://www.hashicorp.com/blog/upcoming-provider-changes-in-terraform-0-10/)
diff --git a/v3.6.0/DESIGN.md b/v3.6.0/DESIGN.md
new file mode 100644
index 0000000..12d3523
--- /dev/null
+++ b/v3.6.0/DESIGN.md
@@ -0,0 +1,44 @@
+# Random Provider Design
+
+The Random Provider offers focussed functionality specifically geared towards the generation of random values for use
+within Terraform configurations. Specifically, the provider resources generate random values at the time they are 
+created and then maintain these values unless the resource inputs are altered.
+
+Below we have a collection of _Goals_ and _Patterns_: they represent the guiding principles applied during the
+development of this provider. Some are in place, others are ongoing processes, others are still just inspirational.
+
+## Goals
+
+* [_Stability over features_](.github/CONTRIBUTING.md)
+* Provide managed resources to generate random values for use within Terraform configurations.
+* Support the underlying use of a cryptographic random number generator for
+  [id](docs/resources/id.md), [password](docs/resources/id.md) and
+  [string](docs/resources/string.md).
+* Support the use of "[keepers](docs/index.md)" for all resources.
+* Support the use of encoding [id](docs/resources/id.md) as: 
+  * [base64](https://www.rfc-editor.org/rfc/rfc4648.html#section-4)
+  * [base64 URL](https://www.rfc-editor.org/rfc/rfc4648.html#section-5)
+  * [decimal](https://pkg.go.dev/math/big#Int.String)
+  * [hex](https://pkg.go.dev/math/big#Int.String)
+
+## Patterns
+
+Specific to this provider:
+
+* The generation of [password](docs/resources/password.md) and
+  [string](docs/resources/string.md) use exactly the same underlying code, the only 
+  difference is that the output from *password* is treated as 
+  [sensitive](https://www.terraform.io/language/state/sensitive-data).
+
+General to development:
+
+* **Avoid repetition**: the entities managed can sometimes require similar pieces of logic and/or schema to be realised.
+  When this happens it's important to keep the code shared in communal sections, so to avoid having to modify code in
+  multiple places when they start changing.
+* **Test expectations as well as bugs**: While it's typical to write tests to exercise a new functionality, it's key to
+  also provide tests for issues that get identified and fixed, so to prove resolution as well as avoid regression.
+* **Automate boring tasks**: Processes that are manual, repetitive and can be automated, should be. In addition to be a
+  time-saving practice, this ensures consistency and reduces human error (ex. static code analysis).
+* **Semantic versioning**: Adhering to HashiCorp's own
+  [Versioning Specification](https://www.terraform.io/plugin/sdkv2/best-practices/versioning#versioning-specification)
+  ensures we provide a consistent practitioner experience, and a clear process to deprecation and decommission.
diff --git a/v3.6.0/GNUmakefile b/v3.6.0/GNUmakefile
new file mode 100644
index 0000000..e0de862
--- /dev/null
+++ b/v3.6.0/GNUmakefile
@@ -0,0 +1,26 @@
+default: build
+
+build:
+	go build -v ./...
+
+install: build
+	go install -v ./...
+
+# See https://golangci-lint.run/
+lint:
+	golangci-lint run
+
+# Generate docs and copywrite headers
+generate:
+	cd tools; go generate ./...
+
+fmt:
+	gofmt -s -w -e .
+
+test:
+	go test -v -cover -timeout=120s -parallel=4 ./...
+
+testacc:
+	TF_ACC=1 go test -v -cover -timeout 120m ./...
+
+.PHONY: build install lint generate fmt test testacc
diff --git a/v3.6.0/LICENSE b/v3.6.0/LICENSE
new file mode 100644
index 0000000..b9ac071
--- /dev/null
+++ b/v3.6.0/LICENSE
@@ -0,0 +1,375 @@
+Copyright (c) 2017 HashiCorp, Inc.
+
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
diff --git a/v3.6.0/README.md b/v3.6.0/README.md
new file mode 100644
index 0000000..fa3e88c
--- /dev/null
+++ b/v3.6.0/README.md
@@ -0,0 +1,119 @@
+# Terraform Provider: Random
+
+The Random provider supports the use of randomness within Terraform configurations. The
+provider resources can be used to generate a random [id](docs/resources/id.md),
+[integer](docs/resources/integer.md), [password](docs/resources/password.md),
+[pet](docs/resources/pet.md), [shuffle](docs/resources/shuffle.md) (random permutation
+of a list of strings), [string](docs/resources/string.md) or 
+[uuid](docs/resources/uuid.md).
+
+## Documentation, questions and discussions
+
+Official documentation on how to use this provider can be found on the
+[Terraform Registry](https://registry.terraform.io/providers/hashicorp/random/latest/docs).
+In case of specific questions or discussions, please use the
+HashiCorp [Terraform Providers Discuss forums](https://discuss.hashicorp.com/c/terraform-providers/31),
+in accordance with HashiCorp [Community Guidelines](https://www.hashicorp.com/community-guidelines).
+
+We also provide:
+
+* [Support](.github/SUPPORT.md) page for help when using the provider
+* [Contributing](.github/CONTRIBUTING.md) guidelines in case you want to help this project
+* [Design](DESIGN.md) documentation to understand the scope and maintenance decisions
+
+The remainder of this document will focus on the development aspects of the provider.
+
+## Requirements
+
+* [Terraform](https://www.terraform.io/downloads) (>= 0.12)
+* [Go](https://go.dev/doc/install) (1.20)
+* [GNU Make](https://www.gnu.org/software/make/)
+* [golangci-lint](https://golangci-lint.run/usage/install/#local-installation) (optional)
+
+## Development
+
+### Building
+
+1. `git clone` this repository and `cd` into its directory
+2. `make build` will trigger the Golang build
+
+The provided `GNUmakefile` defines additional commands generally useful during development,
+like for running tests, generating documentation, code formatting and linting.
+Taking a look at it's content is recommended.
+
+### Testing
+
+In order to test the provider, you can run
+
+* `make test` to run provider tests
+* `make testacc` to run provider acceptance tests
+
+It's important to note that acceptance tests (`testacc`) will actually spawn
+`terraform` and the provider. Read more about they work on the
+[official page](https://www.terraform.io/plugin/sdkv2/testing/acceptance-tests).
+
+### Generating documentation
+
+This provider uses [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/)
+to generate documentation and store it in the `docs/` directory.
+Once a release is cut, the Terraform Registry will download the documentation from `docs/`
+and associate it with the release version. Read more about how this works on the
+[official page](https://www.terraform.io/registry/providers/docs).
+
+Use `make generate` to ensure the documentation is regenerated with any changes.
+
+### Using a development build
+
+If [running tests and acceptance tests](#testing) isn't enough, it's possible to set up a local terraform configuration
+to use a development builds of the provider. This can be achieved by leveraging the Terraform CLI
+[configuration file development overrides](https://www.terraform.io/cli/config/config-file#development-overrides-for-provider-developers).
+
+First, use `make install` to place a fresh development build of the provider in your [`${GOBIN}`](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies) (defaults to `${GOPATH}/bin` or `${HOME}/go/bin` if `${GOPATH}` is not set). Repeat
+this every time you make changes to the provider locally.
+
+Then, in your `${HOME}/.terraformrc` (Unix) / `%APPDATA%\terraform.rc` (Windows), a `provider_installation` that contains
+the following `dev_overrides`:
+
+```hcl
+provider_installation {
+  dev_overrides {
+    "hashicorp/random" = "${GOBIN}" //< replace `${GOBIN}` with the actual path on your system
+  }
+
+  direct {}
+}
+```
+
+Note that it's also possible to use a dedicated Terraform configuration file and invoke `terraform` while setting
+the environment variable `TF_CLI_CONFIG_FILE=my_terraform_config_file`.
+
+Once the `dev_overrides` are in place, any local execution of `terraform plan` and `terraform apply` will
+use the version of the provider found in the given `${GOBIN}` directory,
+instead of the one indicated in your terraform configuration.
+
+### Testing GitHub Actions
+
+This project uses [GitHub Actions](https://docs.github.com/en/actions/automating-builds-and-tests) to realize its CI.
+
+Sometimes it might be helpful to locally reproduce the behaviour of those actions,
+and for this we use [act](https://github.com/nektos/act). Once installed, you can _simulate_ the actions executed
+when opening a PR with:
+
+```shell
+# List of workflows for the 'pull_request' action
+$ act -l pull_request
+
+# Execute the workflows associated with the `pull_request' action 
+$ act pull_request
+```
+
+## Releasing
+
+The release process is automated via GitHub Actions, and it's defined in the Workflow
+[release.yml](./.github/workflows/release.yml).
+
+Each release is cut by pushing a [semantically versioned](https://semver.org/) tag to the default branch.
+
+## License
+
+[Mozilla Public License v2.0](./LICENSE)
diff --git a/v3.6.0/docs/cdktf/python/index.md b/v3.6.0/docs/cdktf/python/index.md
new file mode 100644
index 0000000..9090445
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/index.md
@@ -0,0 +1,82 @@
+---
+page_title: "Provider: Random"
+description: |-
+  The Random provider is used to generate randomness.
+---
+
+
+<!-- Please do not edit this file, it is generated. -->
+# Random Provider
+
+The "random" provider allows the use of randomness within Terraform
+configurations. This is a *logical provider*, which means that it works
+entirely within Terraform's logic, and doesn't interact with any other
+services.
+
+Unconstrained randomness within a Terraform configuration would not be very
+useful, since Terraform's goal is to converge on a fixed configuration by
+applying a diff. Because of this, the "random" provider provides an idea of
+*managed randomness*: it provides resources that generate random values during
+their creation and then hold those values steady until the inputs are changed.
+
+Even with these resources, it is advisable to keep the use of randomness within
+Terraform configuration to a minimum, and retain it for special cases only;
+Terraform works best when the configuration is well-defined, since its behavior
+can then be more readily predicted.
+
+Unless otherwise stated within the documentation of a specific resource, this
+provider's results are **not** sufficiently random for cryptographic use.
+
+For more information on the specific resources available, see the links in the
+navigation bar. Read on for information on the general patterns that apply
+to this provider's resources.
+
+## Resource "Keepers"
+
+As noted above, the random resources generate randomness only when they are
+created; the results produced are stored in the Terraform state and re-used
+until the inputs change, prompting the resource to be recreated.
+
+The resources all provide a map argument called `keepers` that can be populated
+with arbitrary key/value pairs that should be selected such that they remain
+the same until new random values are desired.
+
+For example:
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import Fn, Token, TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.aws.instance import Instance
+from imports.random.id import Id
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        server = Id(self, "server",
+            byte_length=8,
+            keepers={
+                "ami_id": ami_id.string_value
+            }
+        )
+        aws_instance_server = Instance(self, "server_1",
+            ami=Token.as_string(Fn.lookup_nested(server, ["keepers", "ami_id"])),
+            tags={
+                "Name": "web-server ${" + server.hex + "}"
+            }
+        )
+        # This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.
+        aws_instance_server.override_logical_id("server")
+```
+
+Resource "keepers" are optional. The other arguments to each resource must
+*also* remain constant in order to retain a random result.
+
+`keepers` are *not* treated as sensitive attributes; a value used for `keepers` will be displayed in Terraform UI output as plaintext.
+
+To force a random result to be replaced, the `taint` command can be used to
+produce a new result on the next run.
+<!-- cache-key: cdktf-0.19.0 input-481e7e1d76d2dd9651b63f9879c24c591e04b1977a58673585b6ad657bd0e1fc 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/bytes.md b/v3.6.0/docs/cdktf/python/resources/bytes.md
new file mode 100644
index 0000000..fcca2e0
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/bytes.md
@@ -0,0 +1,69 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_bytes Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_bytes generates random bytes that are intended to be used as a secret, or key. Use this in preference to random_id when the output is considered sensitive, and should not be displayed in the CLI.
+---
+
+# random_bytes (Resource)
+
+The resource `random_bytes` generates random bytes that are intended to be used as a secret, or key. Use this in preference to `random_id` when the output is considered sensitive, and should not be displayed in the CLI.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.azurerm.key_vault_secret import KeyVaultSecret
+from imports.random. import Bytes
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        # The following providers are missing schema information and might need manual adjustments to synthesize correctly: azurerm.
+        #     For a more precise conversion please use the --provider flag in convert.
+        jwt_secret = Bytes(self, "jwt_secret",
+            length=64
+        )
+        azurerm_key_vault_secret_jwt_secret = KeyVaultSecret(self, "jwt_secret_1",
+            key_vault_id="some-azure-key-vault-id",
+            name="JwtSecret",
+            value=jwt_secret.base64
+        )
+        # This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.
+        azurerm_key_vault_secret_jwt_secret.override_logical_id("jwt_secret")
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The number of bytes requested. The minimum value for length is 1.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+
+### Read-Only
+
+- `base64` (String, Sensitive) The generated bytes presented in base64 string format.
+- `hex` (String, Sensitive) The generated bytes presented in hex string format.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random bytes can be imported by specifying the value as base64 string.
+terraform import random_bytes.basic "8/fu3q+2DcgSJ19i0jZ5Cw=="
+```
+
+<!-- cache-key: cdktf-0.19.0 input-3a420905eebef2639383ff9b2cb6272c60987fb763332d4f0c4ebc8e93d7dbbb 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/id.md b/v3.6.0/docs/cdktf/python/resources/id.md
new file mode 100644
index 0000000..2eb5d85
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/id.md
@@ -0,0 +1,106 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_id Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_id generates random numbers that are intended to be
+  used as unique identifiers for other resources. If the output is considered
+  sensitive, and should not be displayed in the CLI, use random_bytes
+  instead.
+  This resource does use a cryptographic random number generator in order
+  to minimize the chance of collisions, making the results of this resource
+  when a 16-byte identifier is requested of equivalent uniqueness to a
+  type-4 UUID.
+  This resource can be used in conjunction with resources that have
+  the create_before_destroy lifecycle flag set to avoid conflicts with
+  unique names during the brief period where both the old and new resources
+  exist concurrently.
+---
+
+# random_id (Resource)
+
+The resource `random_id` generates random numbers that are intended to be
+used as unique identifiers for other resources. If the output is considered 
+sensitive, and should not be displayed in the CLI, use `random_bytes`
+instead.
+
+This resource *does* use a cryptographic random number generator in order
+to minimize the chance of collisions, making the results of this resource
+when a 16-byte identifier is requested of equivalent uniqueness to a
+type-4 UUID.
+
+This resource can be used in conjunction with resources that have
+the `create_before_destroy` lifecycle flag set to avoid conflicts with
+unique names during the brief period where both the old and new resources
+exist concurrently.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import Fn, Token, TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.aws.instance import Instance
+from imports.random.id import Id
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        server = Id(self, "server",
+            byte_length=8,
+            keepers={
+                "ami_id": ami_id.string_value
+            }
+        )
+        aws_instance_server = Instance(self, "server_1",
+            ami=Token.as_string(Fn.lookup_nested(server, ["keepers", "ami_id"])),
+            tags={
+                "Name": "web-server ${" + server.hex + "}"
+            }
+        )
+        # This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.
+        aws_instance_server.override_logical_id("server")
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `byte_length` (Number) The number of random bytes to produce. The minimum value is 1, which produces eight bits of randomness.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `prefix` (String) Arbitrary string to prefix the output value with. This string is supplied as-is, meaning it is not guaranteed to be URL-safe or base64 encoded.
+
+### Read-Only
+
+- `b64_std` (String) The generated id presented in base64 without additional transformations.
+- `b64_url` (String) The generated id presented in base64, using the URL-friendly character set: case-sensitive letters, digits and the characters `_` and `-`.
+- `dec` (String) The generated id presented in non-padded decimal digits.
+- `hex` (String) The generated id presented in padded hexadecimal digits. This result will always be twice as long as the requested byte length.
+- `id` (String) The generated id presented in base64 without additional transformations or prefix.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random IDs can be imported using the b64_url with an optional prefix. This
+# can be used to replace a config value with a value interpolated from the
+# random provider without experiencing diffs.
+
+# Example with no prefix:
+terraform import random_id.server p-9hUg
+
+# Example with prefix (prefix is separated by a ,):
+$ terraform import random_id.server my-prefix-,p-9hUg
+```
+
+<!-- cache-key: cdktf-0.19.0 input-5f91020093f3912bfcdaccf929f7d6b4f81c78dec85ef60164d34297667dd198 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/integer.md b/v3.6.0/docs/cdktf/python/resources/integer.md
new file mode 100644
index 0000000..14dc27e
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/integer.md
@@ -0,0 +1,84 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_integer Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_integer generates random values from a given range, described by the min and max attributes of a given resource.
+  This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+---
+
+# random_integer (Resource)
+
+The resource `random_integer` generates random values from a given range, described by the `min` and `max` attributes of a given resource.
+
+This resource can be used in conjunction with resources that have the `create_before_destroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import Fn, Token, TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.aws.alb_listener_rule import AlbListenerRule
+from imports.random.integer import Integer
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name, *, condition):
+        super().__init__(scope, name)
+        priority = Integer(self, "priority",
+            keepers={
+                "listener_arn": listener_arn.string_value
+            },
+            max=50000,
+            min=1
+        )
+        AlbListenerRule(self, "main",
+            action=[AlbListenerRuleAction(
+                target_group_arn=target_group_arn.string_value,
+                type="forward"
+            )
+            ],
+            listener_arn=Token.as_string(
+                Fn.lookup_nested(priority, ["keepers", "listener_arn"])),
+            priority=priority.result,
+            condition=condition
+        )
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `max` (Number) The maximum inclusive value of the range.
+- `min` (Number) The minimum inclusive value of the range.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `seed` (String) A custom seed to always produce the same value.
+
+### Read-Only
+
+- `id` (String) The string representation of the integer result.
+- `result` (Number) The random integer result.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random integers can be imported using the result, min, and max, with an
+# optional seed. This can be used to replace a config value with a value
+# interpolated from the random provider without experiencing diffs.
+
+# Example (values are separated by a ,):
+terraform import random_integer.priority 15390,1,50000
+```
+
+<!-- cache-key: cdktf-0.19.0 input-14468c71f20ebc7d2a161542108e1cc214b9ae4d6f2c5008aa55d67bf9354ebf 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/password.md b/v3.6.0/docs/cdktf/python/resources/password.md
new file mode 100644
index 0000000..3d0e9a1
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/password.md
@@ -0,0 +1,183 @@
+---
+page_title: "random_password Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  Identical to random_string string.html with the exception that the result is treated as sensitive and, thus, not displayed in console output. Read more about sensitive data handling in the Terraform documentation https://www.terraform.io/docs/language/state/sensitive-data.html.
+  This resource does use a cryptographic random number generator.
+---
+
+
+<!-- Please do not edit this file, it is generated. -->
+# random_password (Resource)
+
+Identical to [random_string](string.html) with the exception that the result is treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive data handling in the [Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).
+
+This resource *does* use a cryptographic random number generator.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.aws.db_instance import DbInstance
+from imports.random.password import Password
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        password = Password(self, "password",
+            length=16,
+            override_special="!#$%&*()-_=+[]{}<>:?",
+            special=True
+        )
+        DbInstance(self, "example",
+            allocated_storage=64,
+            engine="mysql",
+            instance_class="db.t3.micro",
+            password=password.result,
+            username="someone"
+        )
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The length of the string desired. The minimum value for length is 1 and, length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `lower` (Boolean) Include lowercase alphabet characters in the result. Default value is `true`.
+- `min_lower` (Number) Minimum number of lowercase alphabet characters in the result. Default value is `0`.
+- `min_numeric` (Number) Minimum number of numeric characters in the result. Default value is `0`.
+- `min_special` (Number) Minimum number of special characters in the result. Default value is `0`.
+- `min_upper` (Number) Minimum number of uppercase alphabet characters in the result. Default value is `0`.
+- `number` (Boolean, Deprecated) Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.
+- `numeric` (Boolean) Include numeric characters in the result. Default value is `true`.
+- `override_special` (String) Supply your own list of special characters to use for string generation.  This overrides the default character list in the special argument.  The `special` argument must still be set to true for any overwritten characters to be used in generation.
+- `special` (Boolean) Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.
+- `upper` (Boolean) Include uppercase alphabet characters in the result. Default value is `true`.
+
+### Read-Only
+
+- `bcrypt_hash` (String, Sensitive) A bcrypt hash of the generated random string. **NOTE**: If the generated random string is greater than 72 bytes in length, `bcrypt_hash` will contain a hash of the first 72 bytes.
+- `id` (String) A static value used internally by Terraform, this should not be referenced in configurations.
+- `result` (String, Sensitive) The generated random string.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_password.password securepassword
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.password import Password
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        Password(self, "password",
+            length=16,
+            lower=False
+        )
+```
+
+Then importing the resource using `terraform import random_password.password securepassword`,
+would result in the triggering of a replacement (i.e., destroy-create) during the next
+`terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_password.password securepassword`,
+replacement could be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+
+    ```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.password import Password
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        Password(self, "password",
+            length=14,
+            lower=True
+        )
+```
+
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+
+    ```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.password import Password
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        Password(self, "password",
+            length=14
+        )
+```
+
+
+3. `ignore_changes` specifying the attributes to ignore:
+
+    ```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from cdktf import TerraformResourceLifecycle
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.password import Password
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        Password(self, "password",
+            length=16,
+            lifecycle=TerraformResourceLifecycle(
+                ignore_changes=[length, lower]
+            ),
+            lower=False
+        )
+```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
+
+<!-- cache-key: cdktf-0.19.0 input-679f2842bdae2deada09d08030e614f09c42f4d6c2a4a7861ed1b7a84f1ceeea 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/pet.md b/v3.6.0/docs/cdktf/python/resources/pet.md
new file mode 100644
index 0000000..1495727
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/pet.md
@@ -0,0 +1,62 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_pet Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_pet generates random pet names that are intended to be used as unique identifiers for other resources.
+  This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+---
+
+# random_pet (Resource)
+
+The resource `random_pet` generates random pet names that are intended to be used as unique identifiers for other resources.
+
+This resource can be used in conjunction with resources that have the `create_before_destroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import Fn, Token, TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.aws.instance import Instance
+from imports.random.pet import Pet
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        server = Pet(self, "server",
+            keepers={
+                "ami_id": ami_id.string_value
+            }
+        )
+        aws_instance_server = Instance(self, "server_1",
+            ami=Token.as_string(Fn.lookup_nested(server, ["keepers", "ami_id"])),
+            tags={
+                "Name": "web-server-${" + server.id + "}"
+            }
+        )
+        # This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.
+        aws_instance_server.override_logical_id("server")
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `length` (Number) The length (in words) of the pet name. Defaults to 2
+- `prefix` (String) A string to prefix the name with.
+- `separator` (String) The character to separate words in the pet name. Defaults to "-"
+
+### Read-Only
+
+- `id` (String) The random pet name.
+
+<!-- cache-key: cdktf-0.19.0 input-6817a99fd74086b883ff0596b3649d0f6a3dcaab94e9dea42308adc5fa0fada5 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/shuffle.md b/v3.6.0/docs/cdktf/python/resources/shuffle.md
new file mode 100644
index 0000000..106ba98
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/shuffle.md
@@ -0,0 +1,60 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_shuffle Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_shuffle generates a random permutation of a list of strings given as an argument.
+---
+
+# random_shuffle (Resource)
+
+The resource `random_shuffle` generates a random permutation of a list of strings given as an argument.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import Token, TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.aws.elb import Elb
+from imports.random.shuffle import Shuffle
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name, *, listener):
+        super().__init__(scope, name)
+        az = Shuffle(self, "az",
+            input=["us-west-1a", "us-west-1c", "us-west-1d", "us-west-1e"],
+            result_count=2
+        )
+        Elb(self, "example",
+            availability_zones=Token.as_list(az.result),
+            listener=listener
+        )
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `input` (List of String) The list of strings to shuffle.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `result_count` (Number) The number of results to return. Defaults to the number of items in the `input` list. If fewer items are requested, some elements will be excluded from the result. If more items are requested, items will be repeated in the result but not more frequently than the number of items in the input list.
+- `seed` (String) Arbitrary string with which to seed the random number generator, in order to produce less-volatile permutations of the list.
+
+**Important:** Even with an identical seed, it is not guaranteed that the same permutation will be produced across different versions of Terraform. This argument causes the result to be *less volatile*, but not fixed for all time.
+
+### Read-Only
+
+- `id` (String) A static value used internally by Terraform, this should not be referenced in configurations.
+- `result` (List of String) Random permutation of the list of strings given in `input`.
+
+<!-- cache-key: cdktf-0.19.0 input-86b1815d80e8e409f9aa5cc558980861275f4603260f1c637f82069bba22d88b 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/string.md b/v3.6.0/docs/cdktf/python/resources/string.md
new file mode 100644
index 0000000..b994f5a
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/string.md
@@ -0,0 +1,171 @@
+---
+page_title: "random_string Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_string generates a random permutation of alphanumeric characters and optionally special characters.
+  This resource does use a cryptographic random number generator.
+  Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use random_id id.html, for sensitive random values please use random_password password.html.
+---
+
+
+<!-- Please do not edit this file, it is generated. -->
+# random_string (Resource)
+
+The resource `random_string` generates a random permutation of alphanumeric characters and optionally special characters.
+
+This resource *does* use a cryptographic random number generator.
+
+Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use [random_id](id.html), for sensitive random values please use [random_password](password.html).
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.string_resource import StringResource
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        StringResource(self, "random",
+            length=16,
+            override_special="/@£$",
+            special=True
+        )
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The length of the string desired. The minimum value for length is 1 and, length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `lower` (Boolean) Include lowercase alphabet characters in the result. Default value is `true`.
+- `min_lower` (Number) Minimum number of lowercase alphabet characters in the result. Default value is `0`.
+- `min_numeric` (Number) Minimum number of numeric characters in the result. Default value is `0`.
+- `min_special` (Number) Minimum number of special characters in the result. Default value is `0`.
+- `min_upper` (Number) Minimum number of uppercase alphabet characters in the result. Default value is `0`.
+- `number` (Boolean, Deprecated) Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.
+- `numeric` (Boolean) Include numeric characters in the result. Default value is `true`.
+- `override_special` (String) Supply your own list of special characters to use for string generation.  This overrides the default character list in the special argument.  The `special` argument must still be set to true for any overwritten characters to be used in generation.
+- `special` (Boolean) Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.
+- `upper` (Boolean) Include uppercase alphabet characters in the result. Default value is `true`.
+
+### Read-Only
+
+- `id` (String) The generated random string.
+- `result` (String) The generated random string.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_string.test test
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.string_resource import StringResource
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        StringResource(self, "test",
+            length=16,
+            lower=False
+        )
+```
+
+Then importing the resource using `terraform import random_string.test test`,
+would result in the triggering of a replacement (i.e., destroy-create) during
+the next `terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_string.test test`,
+replacement can be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+    ```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.string_resource import StringResource
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        StringResource(self, "test",
+            length=4,
+            lower=True
+        )
+```
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+    ```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.string_resource import StringResource
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        StringResource(self, "test",
+            length=4
+        )
+```
+
+3. `ignore_changes` specifying the attributes to ignore:
+    ```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from cdktf import TerraformResourceLifecycle
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.random.string_resource import StringResource
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        StringResource(self, "test",
+            length=16,
+            lifecycle=TerraformResourceLifecycle(
+                ignore_changes=[length, lower]
+            ),
+            lower=False
+        )
+```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
+<!-- cache-key: cdktf-0.19.0 input-54afc295b1f13e4a8837c027e2fd4b275761a58e02a58fa325f8460acce4ca8f 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/python/resources/uuid.md b/v3.6.0/docs/cdktf/python/resources/uuid.md
new file mode 100644
index 0000000..fa7db2a
--- /dev/null
+++ b/v3.6.0/docs/cdktf/python/resources/uuid.md
@@ -0,0 +1,68 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_uuid Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_uuid generates a random uuid string that is intended to be used as a unique identifier for other resources.
+  This resource uses hashicorp/go-uuid https://github.com/hashicorp/go-uuid to generate a UUID-formatted string for use with services needing a unique string identifier.
+---
+
+# random_uuid (Resource)
+
+The resource `random_uuid` generates a random uuid string that is intended to be used as a unique identifier for other resources.
+
+This resource uses [hashicorp/go-uuid](https://github.com/hashicorp/go-uuid) to generate a UUID-formatted string for use with services needing a unique string identifier.
+
+## Example Usage
+
+```python
+# DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+from constructs import Construct
+from cdktf import TerraformStack
+#
+# Provider bindings are generated by running `cdktf get`.
+# See https://cdk.tf/provider-generation for more details.
+#
+from imports.azurerm.resource_group import ResourceGroup
+from imports.random.uuid import Uuid
+class MyConvertedCode(TerraformStack):
+    def __init__(self, scope, name):
+        super().__init__(scope, name)
+        # The following providers are missing schema information and might need manual adjustments to synthesize correctly: azurerm.
+        #     For a more precise conversion please use the --provider flag in convert.
+        test = Uuid(self, "test")
+        azurerm_resource_group_test = ResourceGroup(self, "test_1",
+            location="Central US",
+            name="${" + test.result + "}-rg"
+        )
+        # This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.
+        azurerm_resource_group_test.override_logical_id("test")
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+
+### Read-Only
+
+- `id` (String) The generated uuid presented in string format.
+- `result` (String) The generated uuid presented in string format.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random UUID's can be imported. This can be used to replace a config
+# value with a value interpolated from the random provider without
+# experiencing diffs.
+
+terraform import random_uuid.main aabbccdd-eeff-0011-2233-445566778899
+```
+
+<!-- cache-key: cdktf-0.19.0 input-28b6319e244b3425052c370a8691eaadb0c8a850033c058c030cffbcec995a1d 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/index.md b/v3.6.0/docs/cdktf/typescript/index.md
new file mode 100644
index 0000000..6b3e141
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/index.md
@@ -0,0 +1,85 @@
+---
+page_title: "Provider: Random"
+description: |-
+  The Random provider is used to generate randomness.
+---
+
+
+<!-- Please do not edit this file, it is generated. -->
+# Random Provider
+
+The "random" provider allows the use of randomness within Terraform
+configurations. This is a *logical provider*, which means that it works
+entirely within Terraform's logic, and doesn't interact with any other
+services.
+
+Unconstrained randomness within a Terraform configuration would not be very
+useful, since Terraform's goal is to converge on a fixed configuration by
+applying a diff. Because of this, the "random" provider provides an idea of
+*managed randomness*: it provides resources that generate random values during
+their creation and then hold those values steady until the inputs are changed.
+
+Even with these resources, it is advisable to keep the use of randomness within
+Terraform configuration to a minimum, and retain it for special cases only;
+Terraform works best when the configuration is well-defined, since its behavior
+can then be more readily predicted.
+
+Unless otherwise stated within the documentation of a specific resource, this
+provider's results are **not** sufficiently random for cryptographic use.
+
+For more information on the specific resources available, see the links in the
+navigation bar. Read on for information on the general patterns that apply
+to this provider's resources.
+
+## Resource "Keepers"
+
+As noted above, the random resources generate randomness only when they are
+created; the results produced are stored in the Terraform state and re-used
+until the inputs change, prompting the resource to be recreated.
+
+The resources all provide a map argument called `keepers` that can be populated
+with arbitrary key/value pairs that should be selected such that they remain
+the same until new random values are desired.
+
+For example:
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { Fn, Token, TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Instance } from "./.gen/providers/aws/instance";
+import { Id } from "./.gen/providers/random/id";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    const server = new Id(this, "server", {
+      byteLength: 8,
+      keepers: {
+        ami_id: amiId.stringValue,
+      },
+    });
+    const awsInstanceServer = new Instance(this, "server_1", {
+      ami: Token.asString(Fn.lookupNested(server, ["keepers", "ami_id"])),
+      tags: {
+        Name: "web-server ${" + server.hex + "}",
+      },
+    });
+    /*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
+    awsInstanceServer.overrideLogicalId("server");
+  }
+}
+
+```
+
+Resource "keepers" are optional. The other arguments to each resource must
+*also* remain constant in order to retain a random result.
+
+`keepers` are *not* treated as sensitive attributes; a value used for `keepers` will be displayed in Terraform UI output as plaintext.
+
+To force a random result to be replaced, the `taint` command can be used to
+produce a new result on the next run.
+<!-- cache-key: cdktf-0.19.0 input-481e7e1d76d2dd9651b63f9879c24c591e04b1977a58673585b6ad657bd0e1fc 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/bytes.md b/v3.6.0/docs/cdktf/typescript/resources/bytes.md
new file mode 100644
index 0000000..8d125f5
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/bytes.md
@@ -0,0 +1,76 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_bytes Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_bytes generates random bytes that are intended to be used as a secret, or key. Use this in preference to random_id when the output is considered sensitive, and should not be displayed in the CLI.
+---
+
+# random_bytes (Resource)
+
+The resource `randomBytes` generates random bytes that are intended to be used as a secret, or key. Use this in preference to `randomId` when the output is considered sensitive, and should not be displayed in the CLI.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { KeyVaultSecret } from "./.gen/providers/azurerm/key-vault-secret";
+import { Bytes } from "./.gen/providers/random/";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    /*The following providers are missing schema information and might need manual adjustments to synthesize correctly: azurerm.
+    For a more precise conversion please use the --provider flag in convert.*/
+    const jwtSecret = new Bytes(this, "jwt_secret", {
+      length: 64,
+    });
+    const azurermKeyVaultSecretJwtSecret = new KeyVaultSecret(
+      this,
+      "jwt_secret_1",
+      {
+        key_vault_id: "some-azure-key-vault-id",
+        name: "JwtSecret",
+        value: jwtSecret.base64,
+      }
+    );
+    /*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
+    azurermKeyVaultSecretJwtSecret.overrideLogicalId("jwt_secret");
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The number of bytes requested. The minimum value for length is 1.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+
+### Read-Only
+
+- `base64` (String, Sensitive) The generated bytes presented in base64 string format.
+- `hex` (String, Sensitive) The generated bytes presented in hex string format.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random bytes can be imported by specifying the value as base64 string.
+terraform import random_bytes.basic "8/fu3q+2DcgSJ19i0jZ5Cw=="
+```
+
+<!-- cache-key: cdktf-0.19.0 input-3a420905eebef2639383ff9b2cb6272c60987fb763332d4f0c4ebc8e93d7dbbb 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/id.md b/v3.6.0/docs/cdktf/typescript/resources/id.md
new file mode 100644
index 0000000..0936c82
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/id.md
@@ -0,0 +1,109 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_id Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_id generates random numbers that are intended to be
+  used as unique identifiers for other resources. If the output is considered
+  sensitive, and should not be displayed in the CLI, use random_bytes
+  instead.
+  This resource does use a cryptographic random number generator in order
+  to minimize the chance of collisions, making the results of this resource
+  when a 16-byte identifier is requested of equivalent uniqueness to a
+  type-4 UUID.
+  This resource can be used in conjunction with resources that have
+  the create_before_destroy lifecycle flag set to avoid conflicts with
+  unique names during the brief period where both the old and new resources
+  exist concurrently.
+---
+
+# random_id (Resource)
+
+The resource `randomId` generates random numbers that are intended to be
+used as unique identifiers for other resources. If the output is considered 
+sensitive, and should not be displayed in the CLI, use `randomBytes`
+instead.
+
+This resource *does* use a cryptographic random number generator in order
+to minimize the chance of collisions, making the results of this resource
+when a 16-byte identifier is requested of equivalent uniqueness to a
+type-4 UUID.
+
+This resource can be used in conjunction with resources that have
+the `createBeforeDestroy` lifecycle flag set to avoid conflicts with
+unique names during the brief period where both the old and new resources
+exist concurrently.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { Fn, Token, TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Instance } from "./.gen/providers/aws/instance";
+import { Id } from "./.gen/providers/random/id";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    const server = new Id(this, "server", {
+      byteLength: 8,
+      keepers: {
+        ami_id: amiId.stringValue,
+      },
+    });
+    const awsInstanceServer = new Instance(this, "server_1", {
+      ami: Token.asString(Fn.lookupNested(server, ["keepers", "ami_id"])),
+      tags: {
+        Name: "web-server ${" + server.hex + "}",
+      },
+    });
+    /*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
+    awsInstanceServer.overrideLogicalId("server");
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `byteLength` (Number) The number of random bytes to produce. The minimum value is 1, which produces eight bits of randomness.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `prefix` (String) Arbitrary string to prefix the output value with. This string is supplied as-is, meaning it is not guaranteed to be URL-safe or base64 encoded.
+
+### Read-Only
+
+- `b64Std` (String) The generated id presented in base64 without additional transformations.
+- `b64Url` (String) The generated id presented in base64, using the URL-friendly character set: case-sensitive letters, digits and the characters `_` and `-`.
+- `dec` (String) The generated id presented in non-padded decimal digits.
+- `hex` (String) The generated id presented in padded hexadecimal digits. This result will always be twice as long as the requested byte length.
+- `id` (String) The generated id presented in base64 without additional transformations or prefix.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random IDs can be imported using the b64_url with an optional prefix. This
+# can be used to replace a config value with a value interpolated from the
+# random provider without experiencing diffs.
+
+# Example with no prefix:
+terraform import random_id.server p-9hUg
+
+# Example with prefix (prefix is separated by a ,):
+$ terraform import random_id.server my-prefix-,p-9hUg
+```
+
+<!-- cache-key: cdktf-0.19.0 input-5f91020093f3912bfcdaccf929f7d6b4f81c78dec85ef60164d34297667dd198 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/integer.md b/v3.6.0/docs/cdktf/typescript/resources/integer.md
new file mode 100644
index 0000000..2d65fbd
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/integer.md
@@ -0,0 +1,92 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_integer Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_integer generates random values from a given range, described by the min and max attributes of a given resource.
+  This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+---
+
+# random_integer (Resource)
+
+The resource `randomInteger` generates random values from a given range, described by the `min` and `max` attributes of a given resource.
+
+This resource can be used in conjunction with resources that have the `createBeforeDestroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { Fn, Token, TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { AlbListenerRule } from "./.gen/providers/aws/alb-listener-rule";
+import { Integer } from "./.gen/providers/random/integer";
+interface MyConfig {
+  condition: any;
+}
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string, config: MyConfig) {
+    super(scope, name);
+    const priority = new Integer(this, "priority", {
+      keepers: {
+        listener_arn: listenerArn.stringValue,
+      },
+      max: 50000,
+      min: 1,
+    });
+    new AlbListenerRule(this, "main", {
+      action: [
+        {
+          targetGroupArn: targetGroupArn.stringValue,
+          type: "forward",
+        },
+      ],
+      listenerArn: Token.asString(
+        Fn.lookupNested(priority, ["keepers", "listener_arn"])
+      ),
+      priority: priority.result,
+      condition: config.condition,
+    });
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `max` (Number) The maximum inclusive value of the range.
+- `min` (Number) The minimum inclusive value of the range.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `seed` (String) A custom seed to always produce the same value.
+
+### Read-Only
+
+- `id` (String) The string representation of the integer result.
+- `result` (Number) The random integer result.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random integers can be imported using the result, min, and max, with an
+# optional seed. This can be used to replace a config value with a value
+# interpolated from the random provider without experiencing diffs.
+
+# Example (values are separated by a ,):
+terraform import random_integer.priority 15390,1,50000
+```
+
+<!-- cache-key: cdktf-0.19.0 input-14468c71f20ebc7d2a161542108e1cc214b9ae4d6f2c5008aa55d67bf9354ebf 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/password.md b/v3.6.0/docs/cdktf/typescript/resources/password.md
new file mode 100644
index 0000000..7b40158
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/password.md
@@ -0,0 +1,197 @@
+---
+page_title: "random_password Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  Identical to random_string string.html with the exception that the result is treated as sensitive and, thus, not displayed in console output. Read more about sensitive data handling in the Terraform documentation https://www.terraform.io/docs/language/state/sensitive-data.html.
+  This resource does use a cryptographic random number generator.
+---
+
+
+<!-- Please do not edit this file, it is generated. -->
+# random_password (Resource)
+
+Identical to [random_string](string.html) with the exception that the result is treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive data handling in the [Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).
+
+This resource *does* use a cryptographic random number generator.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { DbInstance } from "./.gen/providers/aws/db-instance";
+import { Password } from "./.gen/providers/random/password";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    const password = new Password(this, "password", {
+      length: 16,
+      overrideSpecial: "!#$%&*()-_=+[]{}<>:?",
+      special: true,
+    });
+    new DbInstance(this, "example", {
+      allocatedStorage: 64,
+      engine: "mysql",
+      instanceClass: "db.t3.micro",
+      password: password.result,
+      username: "someone",
+    });
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The length of the string desired. The minimum value for length is 1 and, length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `lower` (Boolean) Include lowercase alphabet characters in the result. Default value is `true`.
+- `minLower` (Number) Minimum number of lowercase alphabet characters in the result. Default value is `0`.
+- `minNumeric` (Number) Minimum number of numeric characters in the result. Default value is `0`.
+- `minSpecial` (Number) Minimum number of special characters in the result. Default value is `0`.
+- `minUpper` (Number) Minimum number of uppercase alphabet characters in the result. Default value is `0`.
+- `number` (Boolean, Deprecated) Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.
+- `numeric` (Boolean) Include numeric characters in the result. Default value is `true`.
+- `overrideSpecial` (String) Supply your own list of special characters to use for string generation.  This overrides the default character list in the special argument.  The `special` argument must still be set to true for any overwritten characters to be used in generation.
+- `special` (Boolean) Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.
+- `upper` (Boolean) Include uppercase alphabet characters in the result. Default value is `true`.
+
+### Read-Only
+
+- `bcryptHash` (String, Sensitive) A bcrypt hash of the generated random string. **NOTE**: If the generated random string is greater than 72 bytes in length, `bcrypt_hash` will contain a hash of the first 72 bytes.
+- `id` (String) A static value used internally by Terraform, this should not be referenced in configurations.
+- `result` (String, Sensitive) The generated random string.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_password.password securepassword
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Password } from "./.gen/providers/random/password";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new Password(this, "password", {
+      length: 16,
+      lower: false,
+    });
+  }
+}
+
+```
+
+Then importing the resource using `terraform import random_password.password securepassword`,
+would result in the triggering of a replacement (i.e., destroy-create) during the next
+`terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_password.password securepassword`,
+replacement could be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+
+    ```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Password } from "./.gen/providers/random/password";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new Password(this, "password", {
+      length: 14,
+      lower: true,
+    });
+  }
+}
+
+```
+
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+
+    ```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Password } from "./.gen/providers/random/password";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new Password(this, "password", {
+      length: 14,
+    });
+  }
+}
+
+```
+
+
+3. `ignoreChanges` specifying the attributes to ignore:
+
+    ```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Password } from "./.gen/providers/random/password";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new Password(this, "password", {
+      length: 16,
+      lifecycle: {
+        ignoreChanges: [length, lower],
+      },
+      lower: false,
+    });
+  }
+}
+
+```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
+
+<!-- cache-key: cdktf-0.19.0 input-679f2842bdae2deada09d08030e614f09c42f4d6c2a4a7861ed1b7a84f1ceeea 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/pet.md b/v3.6.0/docs/cdktf/typescript/resources/pet.md
new file mode 100644
index 0000000..1e21513
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/pet.md
@@ -0,0 +1,65 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_pet Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_pet generates random pet names that are intended to be used as unique identifiers for other resources.
+  This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+---
+
+# random_pet (Resource)
+
+The resource `randomPet` generates random pet names that are intended to be used as unique identifiers for other resources.
+
+This resource can be used in conjunction with resources that have the `createBeforeDestroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { Fn, Token, TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Instance } from "./.gen/providers/aws/instance";
+import { Pet } from "./.gen/providers/random/pet";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    const server = new Pet(this, "server", {
+      keepers: {
+        ami_id: amiId.stringValue,
+      },
+    });
+    const awsInstanceServer = new Instance(this, "server_1", {
+      ami: Token.asString(Fn.lookupNested(server, ["keepers", "ami_id"])),
+      tags: {
+        Name: "web-server-${" + server.id + "}",
+      },
+    });
+    /*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
+    awsInstanceServer.overrideLogicalId("server");
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `length` (Number) The length (in words) of the pet name. Defaults to 2
+- `prefix` (String) A string to prefix the name with.
+- `separator` (String) The character to separate words in the pet name. Defaults to "-"
+
+### Read-Only
+
+- `id` (String) The random pet name.
+
+<!-- cache-key: cdktf-0.19.0 input-6817a99fd74086b883ff0596b3649d0f6a3dcaab94e9dea42308adc5fa0fada5 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/shuffle.md b/v3.6.0/docs/cdktf/typescript/resources/shuffle.md
new file mode 100644
index 0000000..5f81ebe
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/shuffle.md
@@ -0,0 +1,66 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_shuffle Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_shuffle generates a random permutation of a list of strings given as an argument.
+---
+
+# random_shuffle (Resource)
+
+The resource `randomShuffle` generates a random permutation of a list of strings given as an argument.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { Token, TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { Elb } from "./.gen/providers/aws/elb";
+import { Shuffle } from "./.gen/providers/random/shuffle";
+interface MyConfig {
+  listener: any;
+}
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string, config: MyConfig) {
+    super(scope, name);
+    const az = new Shuffle(this, "az", {
+      input: ["us-west-1a", "us-west-1c", "us-west-1d", "us-west-1e"],
+      resultCount: 2,
+    });
+    new Elb(this, "example", {
+      availabilityZones: Token.asList(az.result),
+      listener: config.listener,
+    });
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `input` (List of String) The list of strings to shuffle.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `resultCount` (Number) The number of results to return. Defaults to the number of items in the `input` list. If fewer items are requested, some elements will be excluded from the result. If more items are requested, items will be repeated in the result but not more frequently than the number of items in the input list.
+- `seed` (String) Arbitrary string with which to seed the random number generator, in order to produce less-volatile permutations of the list.
+
+**Important:** Even with an identical seed, it is not guaranteed that the same permutation will be produced across different versions of Terraform. This argument causes the result to be *less volatile*, but not fixed for all time.
+
+### Read-Only
+
+- `id` (String) A static value used internally by Terraform, this should not be referenced in configurations.
+- `result` (List of String) Random permutation of the list of strings given in `input`.
+
+<!-- cache-key: cdktf-0.19.0 input-86b1815d80e8e409f9aa5cc558980861275f4603260f1c637f82069bba22d88b 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/string.md b/v3.6.0/docs/cdktf/typescript/resources/string.md
new file mode 100644
index 0000000..3679d8b
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/string.md
@@ -0,0 +1,185 @@
+---
+page_title: "random_string Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_string generates a random permutation of alphanumeric characters and optionally special characters.
+  This resource does use a cryptographic random number generator.
+  Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use random_id id.html, for sensitive random values please use random_password password.html.
+---
+
+
+<!-- Please do not edit this file, it is generated. -->
+# random_string (Resource)
+
+The resource `randomString` generates a random permutation of alphanumeric characters and optionally special characters.
+
+This resource *does* use a cryptographic random number generator.
+
+Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use [random_id](id.html), for sensitive random values please use [random_password](password.html).
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { StringResource } from "./.gen/providers/random/string-resource";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new StringResource(this, "random", {
+      length: 16,
+      overrideSpecial: "/@\xA3$",
+      special: true,
+    });
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The length of the string desired. The minimum value for length is 1 and, length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `lower` (Boolean) Include lowercase alphabet characters in the result. Default value is `true`.
+- `minLower` (Number) Minimum number of lowercase alphabet characters in the result. Default value is `0`.
+- `minNumeric` (Number) Minimum number of numeric characters in the result. Default value is `0`.
+- `minSpecial` (Number) Minimum number of special characters in the result. Default value is `0`.
+- `minUpper` (Number) Minimum number of uppercase alphabet characters in the result. Default value is `0`.
+- `number` (Boolean, Deprecated) Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.
+- `numeric` (Boolean) Include numeric characters in the result. Default value is `true`.
+- `overrideSpecial` (String) Supply your own list of special characters to use for string generation.  This overrides the default character list in the special argument.  The `special` argument must still be set to true for any overwritten characters to be used in generation.
+- `special` (Boolean) Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.
+- `upper` (Boolean) Include uppercase alphabet characters in the result. Default value is `true`.
+
+### Read-Only
+
+- `id` (String) The generated random string.
+- `result` (String) The generated random string.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_string.test test
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { StringResource } from "./.gen/providers/random/string-resource";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new StringResource(this, "test", {
+      length: 16,
+      lower: false,
+    });
+  }
+}
+
+```
+
+Then importing the resource using `terraform import random_string.test test`,
+would result in the triggering of a replacement (i.e., destroy-create) during
+the next `terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_string.test test`,
+replacement can be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+    ```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { StringResource } from "./.gen/providers/random/string-resource";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new StringResource(this, "test", {
+      length: 4,
+      lower: true,
+    });
+  }
+}
+
+```
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+    ```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { StringResource } from "./.gen/providers/random/string-resource";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new StringResource(this, "test", {
+      length: 4,
+    });
+  }
+}
+
+```
+
+3. `ignoreChanges` specifying the attributes to ignore:
+    ```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { StringResource } from "./.gen/providers/random/string-resource";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    new StringResource(this, "test", {
+      length: 16,
+      lifecycle: {
+        ignoreChanges: [length, lower],
+      },
+      lower: false,
+    });
+  }
+}
+
+```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
+<!-- cache-key: cdktf-0.19.0 input-54afc295b1f13e4a8837c027e2fd4b275761a58e02a58fa325f8460acce4ca8f 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/cdktf/typescript/resources/uuid.md b/v3.6.0/docs/cdktf/typescript/resources/uuid.md
new file mode 100644
index 0000000..dcd6515
--- /dev/null
+++ b/v3.6.0/docs/cdktf/typescript/resources/uuid.md
@@ -0,0 +1,71 @@
+---
+
+<!-- Please do not edit this file, it is generated. -->
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_uuid Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_uuid generates a random uuid string that is intended to be used as a unique identifier for other resources.
+  This resource uses hashicorp/go-uuid https://github.com/hashicorp/go-uuid to generate a UUID-formatted string for use with services needing a unique string identifier.
+---
+
+# random_uuid (Resource)
+
+The resource `randomUuid` generates a random uuid string that is intended to be used as a unique identifier for other resources.
+
+This resource uses [hashicorp/go-uuid](https://github.com/hashicorp/go-uuid) to generate a UUID-formatted string for use with services needing a unique string identifier.
+
+## Example Usage
+
+```typescript
+// DO NOT EDIT. Code generated by 'cdktf convert' - Please report bugs at https://cdk.tf/bug
+import { Construct } from "constructs";
+import { TerraformStack } from "cdktf";
+/*
+ * Provider bindings are generated by running `cdktf get`.
+ * See https://cdk.tf/provider-generation for more details.
+ */
+import { ResourceGroup } from "./.gen/providers/azurerm/resource-group";
+import { Uuid } from "./.gen/providers/random/uuid";
+class MyConvertedCode extends TerraformStack {
+  constructor(scope: Construct, name: string) {
+    super(scope, name);
+    /*The following providers are missing schema information and might need manual adjustments to synthesize correctly: azurerm.
+    For a more precise conversion please use the --provider flag in convert.*/
+    const test = new Uuid(this, "test", {});
+    const azurermResourceGroupTest = new ResourceGroup(this, "test_1", {
+      location: "Central US",
+      name: "${" + test.result + "}-rg",
+    });
+    /*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
+    azurermResourceGroupTest.overrideLogicalId("test");
+  }
+}
+
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+
+### Read-Only
+
+- `id` (String) The generated uuid presented in string format.
+- `result` (String) The generated uuid presented in string format.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random UUID's can be imported. This can be used to replace a config
+# value with a value interpolated from the random provider without
+# experiencing diffs.
+
+terraform import random_uuid.main aabbccdd-eeff-0011-2233-445566778899
+```
+
+<!-- cache-key: cdktf-0.19.0 input-28b6319e244b3425052c370a8691eaadb0c8a850033c058c030cffbcec995a1d 556251879b8ed0dc4c87a76b568667e0ab5e2c46efdd14a05c556daf05678783-->
\ No newline at end of file
diff --git a/v3.6.0/docs/index.md b/v3.6.0/docs/index.md
new file mode 100644
index 0000000..b0e80ed
--- /dev/null
+++ b/v3.6.0/docs/index.md
@@ -0,0 +1,73 @@
+---
+page_title: "Provider: Random"
+description: |-
+  The Random provider is used to generate randomness.
+---
+
+# Random Provider
+
+The "random" provider allows the use of randomness within Terraform
+configurations. This is a *logical provider*, which means that it works
+entirely within Terraform's logic, and doesn't interact with any other
+services.
+
+Unconstrained randomness within a Terraform configuration would not be very
+useful, since Terraform's goal is to converge on a fixed configuration by
+applying a diff. Because of this, the "random" provider provides an idea of
+*managed randomness*: it provides resources that generate random values during
+their creation and then hold those values steady until the inputs are changed.
+
+Even with these resources, it is advisable to keep the use of randomness within
+Terraform configuration to a minimum, and retain it for special cases only;
+Terraform works best when the configuration is well-defined, since its behavior
+can then be more readily predicted.
+
+Unless otherwise stated within the documentation of a specific resource, this
+provider's results are **not** sufficiently random for cryptographic use.
+
+For more information on the specific resources available, see the links in the
+navigation bar. Read on for information on the general patterns that apply
+to this provider's resources.
+
+## Resource "Keepers"
+
+As noted above, the random resources generate randomness only when they are
+created; the results produced are stored in the Terraform state and re-used
+until the inputs change, prompting the resource to be recreated.
+
+The resources all provide a map argument called `keepers` that can be populated
+with arbitrary key/value pairs that should be selected such that they remain
+the same until new random values are desired.
+
+For example:
+
+```terraform
+resource "random_id" "server" {
+  keepers = {
+    # Generate a new id each time we switch to a new AMI id
+    ami_id = var.ami_id
+  }
+
+  byte_length = 8
+}
+
+resource "aws_instance" "server" {
+  tags = {
+    Name = "web-server ${random_id.server.hex}"
+  }
+
+  # Read the AMI id "through" the random_id resource to ensure that
+  # both will change together.
+  ami = random_id.server.keepers.ami_id
+
+  # ... (other aws_instance arguments) ...
+}
+```
+
+Resource "keepers" are optional. The other arguments to each resource must
+*also* remain constant in order to retain a random result.
+
+`keepers` are *not* treated as sensitive attributes; a value used for `keepers` will be displayed in Terraform UI output as plaintext.
+
+To force a random result to be replaced, the `taint` command can be used to
+produce a new result on the next run.
\ No newline at end of file
diff --git a/v3.6.0/docs/resources/bytes.md b/v3.6.0/docs/resources/bytes.md
new file mode 100644
index 0000000..11bd06b
--- /dev/null
+++ b/v3.6.0/docs/resources/bytes.md
@@ -0,0 +1,50 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_bytes Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_bytes generates random bytes that are intended to be used as a secret, or key. Use this in preference to random_id when the output is considered sensitive, and should not be displayed in the CLI.
+---
+
+# random_bytes (Resource)
+
+The resource `random_bytes` generates random bytes that are intended to be used as a secret, or key. Use this in preference to `random_id` when the output is considered sensitive, and should not be displayed in the CLI.
+
+## Example Usage
+
+```terraform
+resource "random_bytes" "jwt_secret" {
+  length = 64
+}
+
+resource "azurerm_key_vault_secret" "jwt_secret" {
+  key_vault_id = "some-azure-key-vault-id"
+  name         = "JwtSecret"
+  value        = random_bytes.jwt_secret.base64
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The number of bytes requested. The minimum value for length is 1.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+
+### Read-Only
+
+- `base64` (String, Sensitive) The generated bytes presented in base64 string format.
+- `hex` (String, Sensitive) The generated bytes presented in hex string format.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random bytes can be imported by specifying the value as base64 string.
+terraform import random_bytes.basic "8/fu3q+2DcgSJ19i0jZ5Cw=="
+```
diff --git a/v3.6.0/docs/resources/id.md b/v3.6.0/docs/resources/id.md
new file mode 100644
index 0000000..a44ed74
--- /dev/null
+++ b/v3.6.0/docs/resources/id.md
@@ -0,0 +1,99 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_id Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_id generates random numbers that are intended to be
+  used as unique identifiers for other resources. If the output is considered
+  sensitive, and should not be displayed in the CLI, use random_bytes
+  instead.
+  This resource does use a cryptographic random number generator in order
+  to minimize the chance of collisions, making the results of this resource
+  when a 16-byte identifier is requested of equivalent uniqueness to a
+  type-4 UUID.
+  This resource can be used in conjunction with resources that have
+  the create_before_destroy lifecycle flag set to avoid conflicts with
+  unique names during the brief period where both the old and new resources
+  exist concurrently.
+---
+
+# random_id (Resource)
+
+The resource `random_id` generates random numbers that are intended to be
+used as unique identifiers for other resources. If the output is considered 
+sensitive, and should not be displayed in the CLI, use `random_bytes`
+instead.
+
+This resource *does* use a cryptographic random number generator in order
+to minimize the chance of collisions, making the results of this resource
+when a 16-byte identifier is requested of equivalent uniqueness to a
+type-4 UUID.
+
+This resource can be used in conjunction with resources that have
+the `create_before_destroy` lifecycle flag set to avoid conflicts with
+unique names during the brief period where both the old and new resources
+exist concurrently.
+
+## Example Usage
+
+```terraform
+# The following example shows how to generate a unique name for an AWS EC2
+# instance that changes each time a new AMI id is selected.
+
+resource "random_id" "server" {
+  keepers = {
+    # Generate a new id each time we switch to a new AMI id
+    ami_id = var.ami_id
+  }
+
+  byte_length = 8
+}
+
+resource "aws_instance" "server" {
+  tags = {
+    Name = "web-server ${random_id.server.hex}"
+  }
+
+  # Read the AMI id "through" the random_id resource to ensure that
+  # both will change together.
+  ami = random_id.server.keepers.ami_id
+
+  # ... (other aws_instance arguments) ...
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `byte_length` (Number) The number of random bytes to produce. The minimum value is 1, which produces eight bits of randomness.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `prefix` (String) Arbitrary string to prefix the output value with. This string is supplied as-is, meaning it is not guaranteed to be URL-safe or base64 encoded.
+
+### Read-Only
+
+- `b64_std` (String) The generated id presented in base64 without additional transformations.
+- `b64_url` (String) The generated id presented in base64, using the URL-friendly character set: case-sensitive letters, digits and the characters `_` and `-`.
+- `dec` (String) The generated id presented in non-padded decimal digits.
+- `hex` (String) The generated id presented in padded hexadecimal digits. This result will always be twice as long as the requested byte length.
+- `id` (String) The generated id presented in base64 without additional transformations or prefix.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random IDs can be imported using the b64_url with an optional prefix. This
+# can be used to replace a config value with a value interpolated from the
+# random provider without experiencing diffs.
+
+# Example with no prefix:
+terraform import random_id.server p-9hUg
+
+# Example with prefix (prefix is separated by a ,):
+$ terraform import random_id.server my-prefix-,p-9hUg
+```
diff --git a/v3.6.0/docs/resources/integer.md b/v3.6.0/docs/resources/integer.md
new file mode 100644
index 0000000..80ff15d
--- /dev/null
+++ b/v3.6.0/docs/resources/integer.md
@@ -0,0 +1,72 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_integer Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_integer generates random values from a given range, described by the min and max attributes of a given resource.
+  This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+---
+
+# random_integer (Resource)
+
+The resource `random_integer` generates random values from a given range, described by the `min` and `max` attributes of a given resource.
+
+This resource can be used in conjunction with resources that have the `create_before_destroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+
+## Example Usage
+
+```terraform
+# The following example shows how to generate a random priority
+# between 1 and 50000 for a aws_alb_listener_rule resource:
+
+resource "random_integer" "priority" {
+  min = 1
+  max = 50000
+  keepers = {
+    # Generate a new integer each time we switch to a new listener ARN
+    listener_arn = var.listener_arn
+  }
+}
+
+resource "aws_alb_listener_rule" "main" {
+  listener_arn = random_integer.priority.keepers.listener_arn
+  priority     = random_integer.priority.result
+
+  action {
+    type             = "forward"
+    target_group_arn = var.target_group_arn
+  }
+  # ... (other aws_alb_listener_rule arguments) ...
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `max` (Number) The maximum inclusive value of the range.
+- `min` (Number) The minimum inclusive value of the range.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `seed` (String) A custom seed to always produce the same value.
+
+### Read-Only
+
+- `id` (String) The string representation of the integer result.
+- `result` (Number) The random integer result.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random integers can be imported using the result, min, and max, with an
+# optional seed. This can be used to replace a config value with a value
+# interpolated from the random provider without experiencing diffs.
+
+# Example (values are separated by a ,):
+terraform import random_integer.priority 15390,1,50000
+```
diff --git a/v3.6.0/docs/resources/password.md b/v3.6.0/docs/resources/password.md
new file mode 100644
index 0000000..afc9620
--- /dev/null
+++ b/v3.6.0/docs/resources/password.md
@@ -0,0 +1,127 @@
+---
+page_title: "random_password Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  Identical to random_string string.html with the exception that the result is treated as sensitive and, thus, not displayed in console output. Read more about sensitive data handling in the Terraform documentation https://www.terraform.io/docs/language/state/sensitive-data.html.
+  This resource does use a cryptographic random number generator.
+---
+
+# random_password (Resource)
+
+Identical to [random_string](string.html) with the exception that the result is treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive data handling in the [Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).
+
+This resource *does* use a cryptographic random number generator.
+
+## Example Usage
+
+```terraform
+resource "random_password" "password" {
+  length           = 16
+  special          = true
+  override_special = "!#$%&*()-_=+[]{}<>:?"
+}
+
+resource "aws_db_instance" "example" {
+  instance_class    = "db.t3.micro"
+  allocated_storage = 64
+  engine            = "mysql"
+  username          = "someone"
+  password          = random_password.password.result
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The length of the string desired. The minimum value for length is 1 and, length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `lower` (Boolean) Include lowercase alphabet characters in the result. Default value is `true`.
+- `min_lower` (Number) Minimum number of lowercase alphabet characters in the result. Default value is `0`.
+- `min_numeric` (Number) Minimum number of numeric characters in the result. Default value is `0`.
+- `min_special` (Number) Minimum number of special characters in the result. Default value is `0`.
+- `min_upper` (Number) Minimum number of uppercase alphabet characters in the result. Default value is `0`.
+- `number` (Boolean, Deprecated) Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.
+- `numeric` (Boolean) Include numeric characters in the result. Default value is `true`.
+- `override_special` (String) Supply your own list of special characters to use for string generation.  This overrides the default character list in the special argument.  The `special` argument must still be set to true for any overwritten characters to be used in generation.
+- `special` (Boolean) Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.
+- `upper` (Boolean) Include uppercase alphabet characters in the result. Default value is `true`.
+
+### Read-Only
+
+- `bcrypt_hash` (String, Sensitive) A bcrypt hash of the generated random string. **NOTE**: If the generated random string is greater than 72 bytes in length, `bcrypt_hash` will contain a hash of the first 72 bytes.
+- `id` (String) A static value used internally by Terraform, this should not be referenced in configurations.
+- `result` (String, Sensitive) The generated random string.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_password.password securepassword
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```terraform
+resource "random_password" "password" {
+  length = 16
+  lower  = false
+}
+```
+
+Then importing the resource using `terraform import random_password.password securepassword`,
+would result in the triggering of a replacement (i.e., destroy-create) during the next
+`terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_password.password securepassword`,
+replacement could be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+
+    ```terraform
+    resource "random_password" "password" {
+      length = 14
+      lower  = true
+    }
+    ```
+
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+
+    ```terraform
+    resource "random_password" "password" {
+      length = 14
+    }
+    ```
+
+
+3. `ignore_changes` specifying the attributes to ignore:
+
+    ```terraform
+    resource "random_password" "password" {
+      length = 16
+      lower  = false
+
+      lifecycle {
+        ignore_changes = [
+          length,
+          lower,
+        ]
+      }
+    }
+    ```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
diff --git a/v3.6.0/docs/resources/pet.md b/v3.6.0/docs/resources/pet.md
new file mode 100644
index 0000000..e740eb5
--- /dev/null
+++ b/v3.6.0/docs/resources/pet.md
@@ -0,0 +1,55 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_pet Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_pet generates random pet names that are intended to be used as unique identifiers for other resources.
+  This resource can be used in conjunction with resources that have the create_before_destroy lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+---
+
+# random_pet (Resource)
+
+The resource `random_pet` generates random pet names that are intended to be used as unique identifiers for other resources.
+
+This resource can be used in conjunction with resources that have the `create_before_destroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.
+
+## Example Usage
+
+```terraform
+# The following example shows how to generate a unique pet name
+# for an AWS EC2 instance that changes each time a new AMI id is
+# selected.
+
+resource "random_pet" "server" {
+  keepers = {
+    # Generate a new pet name each time we switch to a new AMI id
+    ami_id = var.ami_id
+  }
+}
+
+resource "aws_instance" "server" {
+  tags = {
+    Name = "web-server-${random_pet.server.id}"
+  }
+
+  # Read the AMI id "through" the random_pet resource to ensure that
+  # both will change together.
+  ami = random_pet.server.keepers.ami_id
+
+  # ... (other aws_instance arguments) ...
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `length` (Number) The length (in words) of the pet name. Defaults to 2
+- `prefix` (String) A string to prefix the name with.
+- `separator` (String) The character to separate words in the pet name. Defaults to "-"
+
+### Read-Only
+
+- `id` (String) The random pet name.
diff --git a/v3.6.0/docs/resources/shuffle.md b/v3.6.0/docs/resources/shuffle.md
new file mode 100644
index 0000000..926be80
--- /dev/null
+++ b/v3.6.0/docs/resources/shuffle.md
@@ -0,0 +1,48 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_shuffle Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_shuffle generates a random permutation of a list of strings given as an argument.
+---
+
+# random_shuffle (Resource)
+
+The resource `random_shuffle` generates a random permutation of a list of strings given as an argument.
+
+## Example Usage
+
+```terraform
+resource "random_shuffle" "az" {
+  input        = ["us-west-1a", "us-west-1c", "us-west-1d", "us-west-1e"]
+  result_count = 2
+}
+
+resource "aws_elb" "example" {
+  # Place the ELB in any two of the given availability zones, selected
+  # at random.
+  availability_zones = random_shuffle.az.result
+
+  # ... and other aws_elb arguments ...
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `input` (List of String) The list of strings to shuffle.
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `result_count` (Number) The number of results to return. Defaults to the number of items in the `input` list. If fewer items are requested, some elements will be excluded from the result. If more items are requested, items will be repeated in the result but not more frequently than the number of items in the input list.
+- `seed` (String) Arbitrary string with which to seed the random number generator, in order to produce less-volatile permutations of the list.
+
+**Important:** Even with an identical seed, it is not guaranteed that the same permutation will be produced across different versions of Terraform. This argument causes the result to be *less volatile*, but not fixed for all time.
+
+### Read-Only
+
+- `id` (String) A static value used internally by Terraform, this should not be referenced in configurations.
+- `result` (List of String) Random permutation of the list of strings given in `input`.
diff --git a/v3.6.0/docs/resources/string.md b/v3.6.0/docs/resources/string.md
new file mode 100644
index 0000000..2ad2427
--- /dev/null
+++ b/v3.6.0/docs/resources/string.md
@@ -0,0 +1,116 @@
+---
+page_title: "random_string Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_string generates a random permutation of alphanumeric characters and optionally special characters.
+  This resource does use a cryptographic random number generator.
+  Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use random_id id.html, for sensitive random values please use random_password password.html.
+---
+
+# random_string (Resource)
+
+The resource `random_string` generates a random permutation of alphanumeric characters and optionally special characters.
+
+This resource *does* use a cryptographic random number generator.
+
+Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use [random_id](id.html), for sensitive random values please use [random_password](password.html).
+
+## Example Usage
+
+```terraform
+resource "random_string" "random" {
+  length           = 16
+  special          = true
+  override_special = "/@£$"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `length` (Number) The length of the string desired. The minimum value for length is 1 and, length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+- `lower` (Boolean) Include lowercase alphabet characters in the result. Default value is `true`.
+- `min_lower` (Number) Minimum number of lowercase alphabet characters in the result. Default value is `0`.
+- `min_numeric` (Number) Minimum number of numeric characters in the result. Default value is `0`.
+- `min_special` (Number) Minimum number of special characters in the result. Default value is `0`.
+- `min_upper` (Number) Minimum number of uppercase alphabet characters in the result. Default value is `0`.
+- `number` (Boolean, Deprecated) Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.
+- `numeric` (Boolean) Include numeric characters in the result. Default value is `true`.
+- `override_special` (String) Supply your own list of special characters to use for string generation.  This overrides the default character list in the special argument.  The `special` argument must still be set to true for any overwritten characters to be used in generation.
+- `special` (Boolean) Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.
+- `upper` (Boolean) Include uppercase alphabet characters in the result. Default value is `true`.
+
+### Read-Only
+
+- `id` (String) The generated random string.
+- `result` (String) The generated random string.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_string.test test
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```terraform
+resource "random_string" "test" {
+  length = 16
+  lower  = false
+}
+```
+
+Then importing the resource using `terraform import random_string.test test`,
+would result in the triggering of a replacement (i.e., destroy-create) during
+the next `terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_string.test test`,
+replacement can be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+    ```terraform
+    resource "random_string" "test" {
+      length = 4
+      lower  = true
+    }
+    ```
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+    ```terraform
+    resource "random_string" "test" {
+      length = 4
+    }
+    ```
+
+3. `ignore_changes` specifying the attributes to ignore:
+    ```terraform
+    resource "random_string" "test" {
+      length = 16
+      lower  = false
+
+      lifecycle {
+        ignore_changes = [
+          length,
+          lower,
+        ]
+      }
+    }
+    ```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
\ No newline at end of file
diff --git a/v3.6.0/docs/resources/uuid.md b/v3.6.0/docs/resources/uuid.md
new file mode 100644
index 0000000..37fd92e
--- /dev/null
+++ b/v3.6.0/docs/resources/uuid.md
@@ -0,0 +1,52 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "random_uuid Resource - terraform-provider-random"
+subcategory: ""
+description: |-
+  The resource random_uuid generates a random uuid string that is intended to be used as a unique identifier for other resources.
+  This resource uses hashicorp/go-uuid https://github.com/hashicorp/go-uuid to generate a UUID-formatted string for use with services needing a unique string identifier.
+---
+
+# random_uuid (Resource)
+
+The resource `random_uuid` generates a random uuid string that is intended to be used as a unique identifier for other resources.
+
+This resource uses [hashicorp/go-uuid](https://github.com/hashicorp/go-uuid) to generate a UUID-formatted string for use with services needing a unique string identifier.
+
+## Example Usage
+
+```terraform
+# The following example shows how to generate a unique name for an Azure Resource Group.
+
+resource "random_uuid" "test" {
+}
+
+resource "azurerm_resource_group" "test" {
+  name     = "${random_uuid.test.result}-rg"
+  location = "Central US"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `keepers` (Map of String) Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.
+
+### Read-Only
+
+- `id` (String) The generated uuid presented in string format.
+- `result` (String) The generated uuid presented in string format.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Random UUID's can be imported. This can be used to replace a config
+# value with a value interpolated from the random provider without
+# experiencing diffs.
+
+terraform import random_uuid.main aabbccdd-eeff-0011-2233-445566778899
+```
diff --git a/v3.6.0/examples/provider/provider.tf b/v3.6.0/examples/provider/provider.tf
new file mode 100644
index 0000000..794487d
--- /dev/null
+++ b/v3.6.0/examples/provider/provider.tf
@@ -0,0 +1,20 @@
+resource "random_id" "server" {
+  keepers = {
+    # Generate a new id each time we switch to a new AMI id
+    ami_id = var.ami_id
+  }
+
+  byte_length = 8
+}
+
+resource "aws_instance" "server" {
+  tags = {
+    Name = "web-server ${random_id.server.hex}"
+  }
+
+  # Read the AMI id "through" the random_id resource to ensure that
+  # both will change together.
+  ami = random_id.server.keepers.ami_id
+
+  # ... (other aws_instance arguments) ...
+}
diff --git a/v3.6.0/examples/resources/random_bytes/import.sh b/v3.6.0/examples/resources/random_bytes/import.sh
new file mode 100644
index 0000000..058d5d7
--- /dev/null
+++ b/v3.6.0/examples/resources/random_bytes/import.sh
@@ -0,0 +1,2 @@
+# Random bytes can be imported by specifying the value as base64 string.
+terraform import random_bytes.basic "8/fu3q+2DcgSJ19i0jZ5Cw=="
diff --git a/v3.6.0/examples/resources/random_bytes/resource.tf b/v3.6.0/examples/resources/random_bytes/resource.tf
new file mode 100644
index 0000000..6983ea6
--- /dev/null
+++ b/v3.6.0/examples/resources/random_bytes/resource.tf
@@ -0,0 +1,9 @@
+resource "random_bytes" "jwt_secret" {
+  length = 64
+}
+
+resource "azurerm_key_vault_secret" "jwt_secret" {
+  key_vault_id = "some-azure-key-vault-id"
+  name         = "JwtSecret"
+  value        = random_bytes.jwt_secret.base64
+}
diff --git a/v3.6.0/examples/resources/random_id/import.sh b/v3.6.0/examples/resources/random_id/import.sh
new file mode 100644
index 0000000..ba27755
--- /dev/null
+++ b/v3.6.0/examples/resources/random_id/import.sh
@@ -0,0 +1,9 @@
+# Random IDs can be imported using the b64_url with an optional prefix. This
+# can be used to replace a config value with a value interpolated from the
+# random provider without experiencing diffs.
+
+# Example with no prefix:
+terraform import random_id.server p-9hUg
+
+# Example with prefix (prefix is separated by a ,):
+$ terraform import random_id.server my-prefix-,p-9hUg
\ No newline at end of file
diff --git a/v3.6.0/examples/resources/random_id/resource.tf b/v3.6.0/examples/resources/random_id/resource.tf
new file mode 100644
index 0000000..cbc0a16
--- /dev/null
+++ b/v3.6.0/examples/resources/random_id/resource.tf
@@ -0,0 +1,23 @@
+# The following example shows how to generate a unique name for an AWS EC2
+# instance that changes each time a new AMI id is selected.
+
+resource "random_id" "server" {
+  keepers = {
+    # Generate a new id each time we switch to a new AMI id
+    ami_id = var.ami_id
+  }
+
+  byte_length = 8
+}
+
+resource "aws_instance" "server" {
+  tags = {
+    Name = "web-server ${random_id.server.hex}"
+  }
+
+  # Read the AMI id "through" the random_id resource to ensure that
+  # both will change together.
+  ami = random_id.server.keepers.ami_id
+
+  # ... (other aws_instance arguments) ...
+}
diff --git a/v3.6.0/examples/resources/random_integer/import.sh b/v3.6.0/examples/resources/random_integer/import.sh
new file mode 100644
index 0000000..2f63806
--- /dev/null
+++ b/v3.6.0/examples/resources/random_integer/import.sh
@@ -0,0 +1,6 @@
+# Random integers can be imported using the result, min, and max, with an
+# optional seed. This can be used to replace a config value with a value
+# interpolated from the random provider without experiencing diffs.
+
+# Example (values are separated by a ,):
+terraform import random_integer.priority 15390,1,50000
\ No newline at end of file
diff --git a/v3.6.0/examples/resources/random_integer/resource.tf b/v3.6.0/examples/resources/random_integer/resource.tf
new file mode 100644
index 0000000..8ee6c70
--- /dev/null
+++ b/v3.6.0/examples/resources/random_integer/resource.tf
@@ -0,0 +1,22 @@
+# The following example shows how to generate a random priority
+# between 1 and 50000 for a aws_alb_listener_rule resource:
+
+resource "random_integer" "priority" {
+  min = 1
+  max = 50000
+  keepers = {
+    # Generate a new integer each time we switch to a new listener ARN
+    listener_arn = var.listener_arn
+  }
+}
+
+resource "aws_alb_listener_rule" "main" {
+  listener_arn = random_integer.priority.keepers.listener_arn
+  priority     = random_integer.priority.result
+
+  action {
+    type             = "forward"
+    target_group_arn = var.target_group_arn
+  }
+  # ... (other aws_alb_listener_rule arguments) ...
+}
diff --git a/v3.6.0/examples/resources/random_password/import.sh b/v3.6.0/examples/resources/random_password/import.sh
new file mode 100644
index 0000000..1394dfc
--- /dev/null
+++ b/v3.6.0/examples/resources/random_password/import.sh
@@ -0,0 +1,2 @@
+# Random Password can be imported by specifying the value of the password. 
+terraform import random_password.password securepassword
\ No newline at end of file
diff --git a/v3.6.0/examples/resources/random_password/resource.tf b/v3.6.0/examples/resources/random_password/resource.tf
new file mode 100644
index 0000000..922795e
--- /dev/null
+++ b/v3.6.0/examples/resources/random_password/resource.tf
@@ -0,0 +1,13 @@
+resource "random_password" "password" {
+  length           = 16
+  special          = true
+  override_special = "!#$%&*()-_=+[]{}<>:?"
+}
+
+resource "aws_db_instance" "example" {
+  instance_class    = "db.t3.micro"
+  allocated_storage = 64
+  engine            = "mysql"
+  username          = "someone"
+  password          = random_password.password.result
+}
diff --git a/v3.6.0/examples/resources/random_pet/resource.tf b/v3.6.0/examples/resources/random_pet/resource.tf
new file mode 100644
index 0000000..ab3974f
--- /dev/null
+++ b/v3.6.0/examples/resources/random_pet/resource.tf
@@ -0,0 +1,22 @@
+# The following example shows how to generate a unique pet name
+# for an AWS EC2 instance that changes each time a new AMI id is
+# selected.
+
+resource "random_pet" "server" {
+  keepers = {
+    # Generate a new pet name each time we switch to a new AMI id
+    ami_id = var.ami_id
+  }
+}
+
+resource "aws_instance" "server" {
+  tags = {
+    Name = "web-server-${random_pet.server.id}"
+  }
+
+  # Read the AMI id "through" the random_pet resource to ensure that
+  # both will change together.
+  ami = random_pet.server.keepers.ami_id
+
+  # ... (other aws_instance arguments) ...
+}
diff --git a/v3.6.0/examples/resources/random_shuffle/resource.tf b/v3.6.0/examples/resources/random_shuffle/resource.tf
new file mode 100644
index 0000000..6065ef0
--- /dev/null
+++ b/v3.6.0/examples/resources/random_shuffle/resource.tf
@@ -0,0 +1,12 @@
+resource "random_shuffle" "az" {
+  input        = ["us-west-1a", "us-west-1c", "us-west-1d", "us-west-1e"]
+  result_count = 2
+}
+
+resource "aws_elb" "example" {
+  # Place the ELB in any two of the given availability zones, selected
+  # at random.
+  availability_zones = random_shuffle.az.result
+
+  # ... and other aws_elb arguments ...
+}
diff --git a/v3.6.0/examples/resources/random_string/import.sh b/v3.6.0/examples/resources/random_string/import.sh
new file mode 100644
index 0000000..da10104
--- /dev/null
+++ b/v3.6.0/examples/resources/random_string/import.sh
@@ -0,0 +1,2 @@
+# Random String can be imported by specifying the value of the string.
+terraform import random_string.test test
\ No newline at end of file
diff --git a/v3.6.0/examples/resources/random_string/resource.tf b/v3.6.0/examples/resources/random_string/resource.tf
new file mode 100644
index 0000000..d15bb4e
--- /dev/null
+++ b/v3.6.0/examples/resources/random_string/resource.tf
@@ -0,0 +1,5 @@
+resource "random_string" "random" {
+  length           = 16
+  special          = true
+  override_special = "/@£$"
+}
diff --git a/v3.6.0/examples/resources/random_uuid/import.sh b/v3.6.0/examples/resources/random_uuid/import.sh
new file mode 100644
index 0000000..255e4c4
--- /dev/null
+++ b/v3.6.0/examples/resources/random_uuid/import.sh
@@ -0,0 +1,5 @@
+# Random UUID's can be imported. This can be used to replace a config
+# value with a value interpolated from the random provider without
+# experiencing diffs.
+
+terraform import random_uuid.main aabbccdd-eeff-0011-2233-445566778899
\ No newline at end of file
diff --git a/v3.6.0/examples/resources/random_uuid/resource.tf b/v3.6.0/examples/resources/random_uuid/resource.tf
new file mode 100644
index 0000000..87ba531
--- /dev/null
+++ b/v3.6.0/examples/resources/random_uuid/resource.tf
@@ -0,0 +1,9 @@
+# The following example shows how to generate a unique name for an Azure Resource Group.
+
+resource "random_uuid" "test" {
+}
+
+resource "azurerm_resource_group" "test" {
+  name     = "${random_uuid.test.result}-rg"
+  location = "Central US"
+}
diff --git a/v3.6.0/go.mod b/v3.6.0/go.mod
new file mode 100644
index 0000000..68d7fe6
--- /dev/null
+++ b/v3.6.0/go.mod
@@ -0,0 +1,63 @@
+module github.com/terraform-providers/terraform-provider-random
+
+go 1.20
+
+require (
+	github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
+	github.com/google/go-cmp v0.6.0
+	github.com/hashicorp/go-uuid v1.0.3
+	github.com/hashicorp/terraform-plugin-framework v1.4.2
+	github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
+	github.com/hashicorp/terraform-plugin-go v0.19.1
+	github.com/hashicorp/terraform-plugin-testing v1.5.1
+	golang.org/x/crypto v0.16.0
+)
+
+require (
+	github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
+	github.com/agext/levenshtein v1.2.2 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
+	github.com/cloudflare/circl v1.3.3 // indirect
+	github.com/fatih/color v1.13.0 // indirect
+	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/hashicorp/errwrap v1.1.0 // indirect
+	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
+	github.com/hashicorp/go-hclog v1.5.0 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	github.com/hashicorp/go-plugin v1.5.2 // indirect
+	github.com/hashicorp/go-version v1.6.0 // indirect
+	github.com/hashicorp/hc-install v0.6.0 // indirect
+	github.com/hashicorp/hcl/v2 v2.18.0 // indirect
+	github.com/hashicorp/logutils v1.0.0 // indirect
+	github.com/hashicorp/terraform-exec v0.19.0 // indirect
+	github.com/hashicorp/terraform-json v0.17.1 // indirect
+	github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
+	github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 // indirect
+	github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
+	github.com/hashicorp/terraform-svchost v0.1.1 // indirect
+	github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
+	github.com/kr/pretty v0.3.0 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.16 // indirect
+	github.com/mitchellh/copystructure v1.2.0 // indirect
+	github.com/mitchellh/go-testing-interface v1.14.1 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.0 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/mitchellh/reflectwalk v1.0.2 // indirect
+	github.com/oklog/run v1.1.0 // indirect
+	github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
+	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/zclconf/go-cty v1.14.0 // indirect
+	golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect
+	golang.org/x/mod v0.12.0 // indirect
+	golang.org/x/net v0.17.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
+	google.golang.org/grpc v1.59.0 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
+)
diff --git a/v3.6.0/go.sum b/v3.6.0/go.sum
new file mode 100644
index 0000000..0bc11df
--- /dev/null
+++ b/v3.6.0/go.sum
@@ -0,0 +1,220 @@
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
+github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
+github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
+github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
+github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
+github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
+github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
+github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 h1:90Ly+6UfUypEF6vvvW5rQIv9opIL8CbmW9FT20LDQoY=
+github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0/go.mod h1:V+Qd57rJe8gd4eiGzZyg4h54VLHmYVVw54iMnlAMrF8=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
+github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
+github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A=
+github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
+github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
+github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
+github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y=
+github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
+github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hc-install v0.6.0 h1:fDHnU7JNFNSQebVKYhHZ0va1bC6SrPQ8fpebsvNr2w4=
+github.com/hashicorp/hc-install v0.6.0/go.mod h1:10I912u3nntx9Umo1VAeYPUUuehk0aRQJYpMwbX5wQA=
+github.com/hashicorp/hcl/v2 v2.18.0 h1:wYnG7Lt31t2zYkcquwgKo6MWXzRUDIeIVU5naZwHLl8=
+github.com/hashicorp/hcl/v2 v2.18.0/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
+github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81SpgVtZNNtFSM=
+github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg=
+github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA=
+github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
+github.com/hashicorp/terraform-plugin-framework v1.4.2 h1:P7a7VP1GZbjc4rv921Xy5OckzhoiO3ig6SGxwelD2sI=
+github.com/hashicorp/terraform-plugin-framework v1.4.2/go.mod h1:GWl3InPFZi2wVQmdVnINPKys09s9mLmTZr95/ngLnbY=
+github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
+github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
+github.com/hashicorp/terraform-plugin-go v0.19.1 h1:lf/jTGTeELcz5IIbn/94mJdmnTjRYm6S6ct/JqCSr50=
+github.com/hashicorp/terraform-plugin-go v0.19.1/go.mod h1:5NMIS+DXkfacX6o5HCpswda5yjkSYfKzn1Nfl9l+qRs=
+github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
+github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0 h1:wcOKYwPI9IorAJEBLzgclh3xVolO7ZorYd6U1vnok14=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0/go.mod h1:qH/34G25Ugdj5FcM95cSoXzUgIbgfhVLXCcEcYaMwq8=
+github.com/hashicorp/terraform-plugin-testing v1.5.1 h1:T4aQh9JAhmWo4+t1A7x+rnxAJHCDIYW9kXyo4sVO92c=
+github.com/hashicorp/terraform-plugin-testing v1.5.1/go.mod h1:dg8clO6K59rZ8w9EshBmDp1CxTIPu3yA4iaDpX1h5u0=
+github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
+github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
+github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
+github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
+github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I=
+github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
+github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
+github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
+github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
+github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/zclconf/go-cty v1.14.0 h1:/Xrd39K7DXbHzlisFP9c4pHao4yyf+/Ug9LEz+Y/yhc=
+github.com/zclconf/go-cty v1.14.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
+golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
+google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
+google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/v3.6.0/internal/diagnostics/diagnostics.go b/v3.6.0/internal/diagnostics/diagnostics.go
new file mode 100644
index 0000000..43551b8
--- /dev/null
+++ b/v3.6.0/internal/diagnostics/diagnostics.go
@@ -0,0 +1,51 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package diagnostics
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+)
+
+const RetryMsg = "Retry the Terraform operation. If the error still occurs or happens regularly, please contact the provider developer with hardware and operating system information.\n\n"
+
+func RandomReadError(errMsg string) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	diags.AddError(
+		"Random Read Error",
+		"While attempting to generate a random value for this resource, a read error was generated.\n\n"+
+			RetryMsg+
+			fmt.Sprintf("Original Error: %s", errMsg),
+	)
+
+	return diags
+}
+
+func HashGenerationError(errMsg string) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	diags.AddError(
+		"Hash Generation Error",
+		"While attempting to generate a hash from the password an error occurred.\n\n"+
+			"Verify that the state contains a populated 'result' field, using 'terraform state show', and retry the operation\n\n"+
+			fmt.Sprintf("Original Error: %s", errMsg),
+	)
+
+	return diags
+}
+
+func RandomnessGenerationError(errMsg string) diag.Diagnostics {
+	var diags diag.Diagnostics
+
+	diags.AddError(
+		"Randomness Generation Error",
+		"While attempting to generate a random value for this resource, an insufficient number of random bytes were generated.\n\n"+
+			RetryMsg+
+			fmt.Sprintf("Original Error: %s", errMsg),
+	)
+
+	return diags
+}
diff --git a/v3.6.0/internal/planmodifiers/bool/boolplanmodifiers.go b/v3.6.0/internal/planmodifiers/bool/boolplanmodifiers.go
new file mode 100644
index 0000000..86b99fe
--- /dev/null
+++ b/v3.6.0/internal/planmodifiers/bool/boolplanmodifiers.go
@@ -0,0 +1,71 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package boolplanmodifiers
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+// NumberNumericAttributePlanModifier returns a plan modifier that keep the values
+// held in number and numeric attributes synchronised.
+func NumberNumericAttributePlanModifier() planmodifier.Bool {
+	return &numberNumericAttributePlanModifier{}
+}
+
+type numberNumericAttributePlanModifier struct {
+}
+
+func (d *numberNumericAttributePlanModifier) Description(ctx context.Context) string {
+	return "Ensures that number and numeric attributes are kept synchronised."
+}
+
+func (d *numberNumericAttributePlanModifier) MarkdownDescription(ctx context.Context) string {
+	return d.Description(ctx)
+}
+
+func (d *numberNumericAttributePlanModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
+	numberConfig := types.Bool{}
+	diags := req.Config.GetAttribute(ctx, path.Root("number"), &numberConfig)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	numericConfig := types.Bool{}
+	diags = req.Config.GetAttribute(ctx, path.Root("numeric"), &numericConfig)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	if !numberConfig.IsNull() && !numericConfig.IsNull() && (numberConfig.ValueBool() != numericConfig.ValueBool()) {
+		resp.Diagnostics.AddError(
+			"Number and numeric are both configured with different values",
+			"Number is deprecated, use numeric instead",
+		)
+		return
+	}
+
+	// Default to true for both number and numeric when both are null.
+	if numberConfig.IsNull() && numericConfig.IsNull() {
+		resp.PlanValue = types.BoolValue(true)
+		return
+	}
+
+	// Default to using value for numeric if number is null.
+	if numberConfig.IsNull() && !numericConfig.IsNull() {
+		resp.PlanValue = numericConfig
+		return
+	}
+
+	// Default to using value for number if numeric is null.
+	if !numberConfig.IsNull() && numericConfig.IsNull() {
+		resp.PlanValue = numberConfig
+		return
+	}
+}
diff --git a/v3.6.0/internal/planmodifiers/map/mapplanmodifiers.go b/v3.6.0/internal/planmodifiers/map/mapplanmodifiers.go
new file mode 100644
index 0000000..312b06d
--- /dev/null
+++ b/v3.6.0/internal/planmodifiers/map/mapplanmodifiers.go
@@ -0,0 +1,109 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package mapplanmodifiers
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+)
+
+func RequiresReplaceIfValuesNotNull() planmodifier.Map {
+	return requiresReplaceIfValuesNotNullModifier{}
+}
+
+type requiresReplaceIfValuesNotNullModifier struct{}
+
+func (r requiresReplaceIfValuesNotNullModifier) PlanModifyMap(ctx context.Context, req planmodifier.MapRequest, resp *planmodifier.MapResponse) {
+	if req.State.Raw.IsNull() {
+		// if we're creating the resource, no need to delete and
+		// recreate it
+		return
+	}
+
+	if req.Plan.Raw.IsNull() {
+		// if we're deleting the resource, no need to delete and
+		// recreate it
+		return
+	}
+
+	// If there are no differences, do not mark the resource for replacement
+	// and ensure the plan matches the configuration.
+	if req.ConfigValue.Equal(req.StateValue) {
+		return
+	}
+
+	if req.StateValue.IsNull() {
+		// terraform-plugin-sdk would store maps as null if all keys had null
+		// values. To prevent unintentional replacement plans when migrating
+		// to terraform-plugin-framework, only trigger replacement when the
+		// prior state (map) is null and when there are not null map values.
+		allNullValues := true
+
+		for _, configValue := range req.ConfigValue.Elements() {
+			if !configValue.IsNull() {
+				allNullValues = false
+			}
+		}
+
+		if allNullValues {
+			return
+		}
+	} else {
+		// terraform-plugin-sdk would completely omit storing map keys with
+		// null values, so this also must prevent unintentional replacement
+		// in that case as well.
+		allNewNullValues := true
+
+		configMap := req.ConfigValue
+
+		stateMap := req.StateValue
+
+		for configKey, configValue := range configMap.Elements() {
+			stateValue, ok := stateMap.Elements()[configKey]
+
+			// If the key doesn't exist in state and the config value is
+			// null, do not trigger replacement.
+			if !ok && configValue.IsNull() {
+				continue
+			}
+
+			// If the state value exists, and it is equal to the config value,
+			// do not trigger replacement.
+			if configValue.Equal(stateValue) {
+				continue
+			}
+
+			allNewNullValues = false
+			break
+		}
+
+		for stateKey := range stateMap.Elements() {
+			_, ok := configMap.Elements()[stateKey]
+
+			// If the key doesn't exist in the config, but there is a state
+			// value, trigger replacement.
+			if !ok {
+				allNewNullValues = false
+				break
+			}
+		}
+
+		if allNewNullValues {
+			return
+		}
+	}
+
+	resp.RequiresReplace = true
+}
+
+// Description returns a human-readable description of the plan modifier.
+func (r requiresReplaceIfValuesNotNullModifier) Description(ctx context.Context) string {
+	return "If the value of this attribute changes, Terraform will destroy and recreate the resource."
+}
+
+// MarkdownDescription returns a markdown description of the plan modifier.
+func (r requiresReplaceIfValuesNotNullModifier) MarkdownDescription(ctx context.Context) string {
+	return "If the value of this attribute changes, Terraform will destroy and recreate the resource."
+}
diff --git a/v3.6.0/internal/planmodifiers/string/stringplanmodifier.go b/v3.6.0/internal/planmodifiers/string/stringplanmodifier.go
new file mode 100644
index 0000000..b0b5460
--- /dev/null
+++ b/v3.6.0/internal/planmodifiers/string/stringplanmodifier.go
@@ -0,0 +1,44 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package stringplanmodifiers
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+)
+
+// RequiresReplaceUnlessEmptyStringToNull returns a
+// resource.RequiresReplaceIfFunc that returns true unless the change is from
+// an empty string to null. This plan modifier allows practitioners to fix
+// their configurations in this situation without replacing the resource.
+//
+// For example, version 3.4.2 errantly setup the random_password and
+// random_string resource override_special attributes with an empty string
+// default value plan modifier.
+func RequiresReplaceUnlessEmptyStringToNull() stringplanmodifier.RequiresReplaceIfFunc {
+	return func(ctx context.Context, req planmodifier.StringRequest, resp *stringplanmodifier.RequiresReplaceIfFuncResponse) {
+		// If the configuration is unknown, this cannot be sure what to do yet.
+		if req.ConfigValue.IsUnknown() {
+			resp.RequiresReplace = false
+			return
+		}
+
+		// If the configuration is not null or the state is already null,
+		// replace the resource.
+		if !req.ConfigValue.IsNull() || req.StateValue.IsNull() {
+			resp.RequiresReplace = true
+			return
+		}
+
+		// If the state is not an empty string, replace the resource.
+		if req.StateValue.ValueString() != "" {
+			resp.RequiresReplace = true
+			return
+		}
+
+		resp.RequiresReplace = false
+	}
+}
diff --git a/v3.6.0/internal/provider/provider.go b/v3.6.0/internal/provider/provider.go
new file mode 100644
index 0000000..1843c9f
--- /dev/null
+++ b/v3.6.0/internal/provider/provider.go
@@ -0,0 +1,47 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/provider"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+)
+
+func New() provider.Provider {
+	return &randomProvider{}
+}
+
+var _ provider.Provider = (*randomProvider)(nil)
+
+type randomProvider struct{}
+
+func (p *randomProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
+	resp.TypeName = "random"
+}
+
+func (p *randomProvider) Schema(context.Context, provider.SchemaRequest, *provider.SchemaResponse) {
+}
+
+func (p *randomProvider) Configure(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse) {
+}
+
+func (p *randomProvider) Resources(context.Context) []func() resource.Resource {
+	return []func() resource.Resource{
+		NewIdResource,
+		NewBytesResource,
+		NewIntegerResource,
+		NewPasswordResource,
+		NewPetResource,
+		NewShuffleResource,
+		NewStringResource,
+		NewUuidResource,
+	}
+}
+
+func (p *randomProvider) DataSources(context.Context) []func() datasource.DataSource {
+	return nil
+}
diff --git a/v3.6.0/internal/provider/provider_test.go b/v3.6.0/internal/provider/provider_test.go
new file mode 100644
index 0000000..fb8194c
--- /dev/null
+++ b/v3.6.0/internal/provider/provider_test.go
@@ -0,0 +1,62 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+	"github.com/hashicorp/terraform-plugin-go/tfprotov5"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+//nolint:unparam
+func protoV5ProviderFactories() map[string]func() (tfprotov5.ProviderServer, error) {
+	return map[string]func() (tfprotov5.ProviderServer, error){
+		"random": providerserver.NewProtocol5WithError(New()),
+	}
+}
+
+func providerVersion221() map[string]resource.ExternalProvider {
+	return map[string]resource.ExternalProvider{
+		"random": {
+			VersionConstraint: "2.2.1",
+			Source:            "hashicorp/random",
+		},
+	}
+}
+
+func providerVersion313() map[string]resource.ExternalProvider {
+	return map[string]resource.ExternalProvider{
+		"random": {
+			VersionConstraint: "3.1.3",
+			Source:            "hashicorp/random",
+		},
+	}
+}
+
+func providerVersion320() map[string]resource.ExternalProvider {
+	return map[string]resource.ExternalProvider{
+		"random": {
+			VersionConstraint: "3.2.0",
+			Source:            "hashicorp/random",
+		},
+	}
+}
+
+func providerVersion332() map[string]resource.ExternalProvider {
+	return map[string]resource.ExternalProvider{
+		"random": {
+			VersionConstraint: "3.3.2",
+			Source:            "hashicorp/random",
+		},
+	}
+}
+
+func providerVersion342() map[string]resource.ExternalProvider {
+	return map[string]resource.ExternalProvider{
+		"random": {
+			VersionConstraint: "3.4.2",
+			Source:            "hashicorp/random",
+		},
+	}
+}
diff --git a/v3.6.0/internal/provider/resource_bytes.go b/v3.6.0/internal/provider/resource_bytes.go
new file mode 100644
index 0000000..c143eaf
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_bytes.go
@@ -0,0 +1,177 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"crypto/rand"
+	"encoding/base64"
+	"encoding/hex"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/diagnostics"
+)
+
+var (
+	_ resource.Resource                = (*bytesResource)(nil)
+	_ resource.ResourceWithImportState = (*bytesResource)(nil)
+)
+
+func NewBytesResource() resource.Resource {
+	return &bytesResource{}
+}
+
+type bytesResource struct {
+}
+
+func (r *bytesResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_bytes"
+}
+
+func (r *bytesResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = bytesSchemaV0()
+}
+
+func (r *bytesResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan bytesModelV0
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	bytes := make([]byte, plan.Length.ValueInt64())
+	_, err := rand.Read(bytes)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Create Random bytes error",
+			"There was an error during random generation.\n\n"+
+				diagnostics.RetryMsg+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	u := &bytesModelV0{
+		Length:  plan.Length,
+		Base64:  types.StringValue(base64.StdEncoding.EncodeToString(bytes)),
+		Hex:     types.StringValue(hex.EncodeToString(bytes)),
+		Keepers: plan.Keepers,
+	}
+
+	diags = resp.State.Set(ctx, u)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *bytesResource) Read(context.Context, resource.ReadRequest, *resource.ReadResponse) {
+}
+
+func (r *bytesResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model bytesModelV0
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *bytesResource) Delete(context.Context, resource.DeleteRequest, *resource.DeleteResponse) {
+}
+
+func (r *bytesResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	bytes, err := base64.StdEncoding.DecodeString(req.ID)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random bytes Error",
+			"There was an error during the parsing of the base64 string.\n\n"+
+				diagnostics.RetryMsg+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	var state bytesModelV0
+
+	state.Length = types.Int64Value(int64(len(bytes)))
+	state.Base64 = types.StringValue(req.ID)
+	state.Hex = types.StringValue(hex.EncodeToString(bytes))
+	state.Keepers = types.MapNull(types.StringType)
+
+	diags := resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+type bytesModelV0 struct {
+	Length  types.Int64  `tfsdk:"length"`
+	Keepers types.Map    `tfsdk:"keepers"`
+	Base64  types.String `tfsdk:"base64"`
+	Hex     types.String `tfsdk:"hex"`
+}
+
+func bytesSchemaV0() schema.Schema {
+	return schema.Schema{
+		Version: 0,
+		Description: "The resource `random_bytes` generates random bytes that are intended to be " +
+			"used as a secret, or key. Use this in preference to `random_id` when the output is " +
+			"considered sensitive, and should not be displayed in the CLI.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifier.RequiresReplace(),
+				},
+			},
+			"length": schema.Int64Attribute{
+				Description: "The number of bytes requested. The minimum value for length is 1.",
+				Required:    true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+				Validators: []validator.Int64{
+					int64validator.AtLeast(1),
+				},
+			},
+			"base64": schema.StringAttribute{
+				Description: "The generated bytes presented in base64 string format.",
+				Computed:    true,
+				Sensitive:   true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"hex": schema.StringAttribute{
+				Description: "The generated bytes presented in hex string format.",
+				Computed:    true,
+				Sensitive:   true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
diff --git a/v3.6.0/internal/provider/resource_bytes_test.go b/v3.6.0/internal/provider/resource_bytes_test.go
new file mode 100644
index 0000000..c9c950b
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_bytes_test.go
@@ -0,0 +1,578 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"fmt"
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/terraform"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccResourceBytes(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_bytes" "basic" {
+							length = 32
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestMatchResourceAttr("random_bytes.basic", "base64", regexp.MustCompile(`^[A-Za-z/+\d]{43}=$`)),
+					resource.TestMatchResourceAttr("random_bytes.basic", "hex", regexp.MustCompile(`^[a-f\d]{64}$`)),
+					resource.TestCheckResourceAttr("random_bytes.basic", "length", "32"),
+				),
+			},
+			{
+				// Usage of ImportStateIdFunc is required as the value passed to the `terraform import` command needs
+				// to be the bytes encoded with base64.
+				ImportStateIdFunc: func(s *terraform.State) (string, error) {
+					resource := "random_bytes.basic"
+					rs, ok := s.RootModule().Resources[resource]
+					if !ok {
+						return "", fmt.Errorf("not found: %s", resource)
+					}
+					if rs.Primary.Attributes["base64"] == "" {
+						return "", fmt.Errorf("no base64 attribute is set")
+					}
+
+					return rs.Primary.Attributes["base64"], nil
+				},
+				ResourceName:                         "random_bytes.basic",
+				ImportState:                          true,
+				ImportStateVerify:                    true,
+				ImportStateVerifyIdentifierAttribute: "base64",
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_ImportWithoutKeepersThenUpdateShouldNotTriggerChange(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				ImportState:        true,
+				ImportStateId:      "hkvbcU5f8qGysTFhkI4gzf3yRWC1jXW3aRLCNQFOtNw=",
+				ImportStatePersist: true,
+				ResourceName:       "random_bytes.basic",
+				Config: `resource "random_bytes" "basic" {
+							length = 32
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_bytes.basic", "base64", "hkvbcU5f8qGysTFhkI4gzf3yRWC1jXW3aRLCNQFOtNw="),
+					resource.TestCheckResourceAttr("random_bytes.basic", "hex", "864bdb714e5ff2a1b2b13161908e20cdfdf24560b58d75b76912c235014eb4dc"),
+					resource.TestCheckResourceAttr("random_bytes.basic", "length", "32"),
+				),
+			},
+			{
+				Config: `resource "random_bytes" "basic" {
+							length = 32
+						}`,
+				PlanOnly: true,
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_LengthErrors(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_bytes" "invalid_length" {
+							length = 0
+						}`,
+				ExpectError: regexp.MustCompile(`.*Attribute length value must be at least 1, got: 0`),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Length_ForceReplacement(t *testing.T) {
+	var bytes1, bytes2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 1
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_bytes.test", "length", "1"),
+					testExtractResourceAttr("random_bytes.test", "base64", &bytes1),
+					resource.TestCheckResourceAttrWith("random_bytes.test", "hex", testCheckLen(2)),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 2
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_bytes.test", "length", "2"),
+					testExtractResourceAttr("random_bytes.test", "base64", &bytes2),
+					resource.TestCheckResourceAttrWith("random_bytes.test", "hex", testCheckLen(4)),
+					testCheckAttributeValuesDiffer(&bytes1, &bytes2),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Keep_EmptyMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Keep_NullMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Keep_NullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Keep_NullValues(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Keep_Value(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Keep_Values(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceBytes_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result1),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_bytes" "test" {
+					length = 12
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_bytes.test", "hex", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_bytes.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
diff --git a/v3.6.0/internal/provider/resource_id.go b/v3.6.0/internal/provider/resource_id.go
new file mode 100644
index 0000000..9ad4bfa
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_id.go
@@ -0,0 +1,258 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"crypto/rand"
+	"encoding/base64"
+	"encoding/hex"
+	"fmt"
+	"math/big"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/diagnostics"
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+)
+
+var (
+	_ resource.Resource                = (*idResource)(nil)
+	_ resource.ResourceWithImportState = (*idResource)(nil)
+)
+
+func NewIdResource() resource.Resource {
+	return &idResource{}
+}
+
+type idResource struct{}
+
+func (r *idResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_id"
+}
+
+func (r *idResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Description: `
+The resource ` + "`random_id`" + ` generates random numbers that are intended to be
+used as unique identifiers for other resources. If the output is considered 
+sensitive, and should not be displayed in the CLI, use ` + "`random_bytes`" + `
+instead.
+
+This resource *does* use a cryptographic random number generator in order
+to minimize the chance of collisions, making the results of this resource
+when a 16-byte identifier is requested of equivalent uniqueness to a
+type-4 UUID.
+
+This resource can be used in conjunction with resources that have
+the ` + "`create_before_destroy`" + ` lifecycle flag set to avoid conflicts with
+unique names during the brief period where both the old and new resources
+exist concurrently.
+`,
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+			"byte_length": schema.Int64Attribute{
+				Description: "The number of random bytes to produce. The minimum value is 1, which produces " +
+					"eight bits of randomness.",
+				Required: true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+			"prefix": schema.StringAttribute{
+				Description: "Arbitrary string to prefix the output value with. This string is supplied as-is, " +
+					"meaning it is not guaranteed to be URL-safe or base64 encoded.",
+				Optional: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"b64_url": schema.StringAttribute{
+				Description: "The generated id presented in base64, using the URL-friendly character set: " +
+					"case-sensitive letters, digits and the characters `_` and `-`.",
+				Computed: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"b64_std": schema.StringAttribute{
+				Description: "The generated id presented in base64 without additional transformations.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"hex": schema.StringAttribute{
+				Description: "The generated id presented in padded hexadecimal digits. This result will " +
+					"always be twice as long as the requested byte length.",
+				Computed: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"dec": schema.StringAttribute{
+				Description: "The generated id presented in non-padded decimal digits.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"id": schema.StringAttribute{
+				Description: "The generated id presented in base64 without additional transformations or prefix.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func (r *idResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan idModelV0
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	byteLength := plan.ByteLength.ValueInt64()
+	bytes := make([]byte, byteLength)
+
+	n, err := rand.Reader.Read(bytes)
+	if int64(n) != byteLength {
+		resp.Diagnostics.Append(diagnostics.RandomnessGenerationError(err.Error())...)
+		return
+	}
+	if err != nil {
+		resp.Diagnostics.Append(diagnostics.RandomReadError(err.Error())...)
+		return
+	}
+
+	id := base64.RawURLEncoding.EncodeToString(bytes)
+	prefix := plan.Prefix.ValueString()
+	b64Std := base64.StdEncoding.EncodeToString(bytes)
+	hexStr := hex.EncodeToString(bytes)
+
+	bigInt := big.Int{}
+	bigInt.SetBytes(bytes)
+	dec := bigInt.String()
+
+	i := idModelV0{
+		ID:         types.StringValue(id),
+		Keepers:    plan.Keepers,
+		ByteLength: types.Int64Value(plan.ByteLength.ValueInt64()),
+		Prefix:     plan.Prefix,
+		B64URL:     types.StringValue(prefix + id),
+		B64Std:     types.StringValue(prefix + b64Std),
+		Hex:        types.StringValue(prefix + hexStr),
+		Dec:        types.StringValue(prefix + dec),
+	}
+
+	diags = resp.State.Set(ctx, i)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *idResource) Read(context.Context, resource.ReadRequest, *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *idResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model idModelV0
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *idResource) Delete(context.Context, resource.DeleteRequest, *resource.DeleteResponse) {
+}
+
+func (r *idResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	id := req.ID
+	var prefix string
+
+	sep := strings.LastIndex(id, ",")
+	if sep != -1 {
+		prefix = id[:sep]
+		id = id[sep+1:]
+	}
+
+	bytes, err := base64.RawURLEncoding.DecodeString(id)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random ID Error",
+			"While attempting to import a random id there was a decoding error.\n\n+"+
+				diagnostics.RetryMsg+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	b64Std := base64.StdEncoding.EncodeToString(bytes)
+	hexStr := hex.EncodeToString(bytes)
+
+	bigInt := big.Int{}
+	bigInt.SetBytes(bytes)
+	dec := bigInt.String()
+
+	var state idModelV0
+
+	state.ID = types.StringValue(id)
+	state.ByteLength = types.Int64Value(int64(len(bytes)))
+	// Using types.MapValueMust to ensure map is known.
+	state.Keepers = types.MapValueMust(types.StringType, nil)
+	state.B64Std = types.StringValue(prefix + b64Std)
+	state.B64URL = types.StringValue(prefix + id)
+	state.Hex = types.StringValue(prefix + hexStr)
+	state.Dec = types.StringValue(prefix + dec)
+
+	if prefix == "" {
+		state.Prefix = types.StringNull()
+	} else {
+		state.Prefix = types.StringValue(prefix)
+	}
+
+	diags := resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+type idModelV0 struct {
+	ID         types.String `tfsdk:"id"`
+	Keepers    types.Map    `tfsdk:"keepers"`
+	ByteLength types.Int64  `tfsdk:"byte_length"`
+	Prefix     types.String `tfsdk:"prefix"`
+	B64URL     types.String `tfsdk:"b64_url"`
+	B64Std     types.String `tfsdk:"b64_std"`
+	Hex        types.String `tfsdk:"hex"`
+	Dec        types.String `tfsdk:"dec"`
+}
diff --git a/v3.6.0/internal/provider/resource_id_test.go b/v3.6.0/internal/provider/resource_id_test.go
new file mode 100644
index 0000000..a6fb758
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_id_test.go
@@ -0,0 +1,844 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccResourceID(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_id" "foo" {
+  							byte_length = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_id.foo", "b64_url", testCheckLen(6)),
+					resource.TestCheckResourceAttrWith("random_id.foo", "b64_std", testCheckLen(8)),
+					resource.TestCheckResourceAttrWith("random_id.foo", "hex", testCheckLen(8)),
+					resource.TestCheckResourceAttrWith("random_id.foo", "dec", testCheckMinLen(1)),
+				),
+			},
+			{
+				ResourceName:      "random_id.foo",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func TestAccResourceID_ImportWithPrefix(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_id" "bar" {
+  							byte_length = 4
+  							prefix      = "cloud-"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_id.bar", "b64_url", testCheckLen(12)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "b64_std", testCheckLen(14)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "hex", testCheckLen(14)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "dec", testCheckMinLen(1)),
+				),
+			},
+			{
+				ResourceName:        "random_id.bar",
+				ImportState:         true,
+				ImportStateIdPrefix: "cloud-,",
+				ImportStateVerify:   true,
+			},
+		},
+	})
+}
+
+func TestAccResourceID_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "bar" {
+  							byte_length = 4
+  							prefix      = "cloud-"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_id.bar", "b64_url", testCheckLen(12)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "b64_std", testCheckLen(14)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "hex", testCheckLen(14)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "dec", testCheckMinLen(1)),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "bar" {
+  							byte_length = 4
+  							prefix      = "cloud-"
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "bar" {
+  							byte_length = 4
+  							prefix      = "cloud-"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_id.bar", "b64_url", testCheckLen(12)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "b64_std", testCheckLen(14)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "hex", testCheckLen(14)),
+					resource.TestCheckResourceAttrWith("random_id.bar", "dec", testCheckMinLen(1)),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_EmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_NullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_NullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_NullValues(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_Value(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Keep_Values(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceID_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_id" "test" {
+					byte_length = 4
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_id.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_id.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
diff --git a/v3.6.0/internal/provider/resource_integer.go b/v3.6.0/internal/provider/resource_integer.go
new file mode 100644
index 0000000..a70e53c
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_integer.go
@@ -0,0 +1,229 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+	"github.com/terraform-providers/terraform-provider-random/internal/random"
+)
+
+var (
+	_ resource.Resource                = (*integerResource)(nil)
+	_ resource.ResourceWithImportState = (*integerResource)(nil)
+)
+
+func NewIntegerResource() resource.Resource {
+	return &integerResource{}
+}
+
+type integerResource struct{}
+
+func (r *integerResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_integer"
+}
+
+func (r *integerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Description: "The resource `random_integer` generates random values from a given range, described " +
+			"by the `min` and `max` attributes of a given resource.\n" +
+			"\n" +
+			"This resource can be used in conjunction with resources that have the `create_before_destroy` " +
+			"lifecycle flag set, to avoid conflicts with unique names during the brief period where both the " +
+			"old and new resources exist concurrently.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+			"min": schema.Int64Attribute{
+				Description: "The minimum inclusive value of the range.",
+				Required:    true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+			"max": schema.Int64Attribute{
+				Description: "The maximum inclusive value of the range.",
+				Required:    true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+			"seed": schema.StringAttribute{
+				Description: "A custom seed to always produce the same value.",
+				Optional:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"result": schema.Int64Attribute{
+				Description: "The random integer result.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.UseStateForUnknown(),
+				},
+			},
+			"id": schema.StringAttribute{
+				Description: "The string representation of the integer result.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func (r *integerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan integerModelV0
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	max := int(plan.Max.ValueInt64())
+	min := int(plan.Min.ValueInt64())
+	seed := plan.Seed.ValueString()
+
+	if max < min {
+		resp.Diagnostics.AddError(
+			"Create Random Integer Error",
+			"The minimum (min) value needs to be smaller than or equal to maximum (max) value.",
+		)
+		return
+	}
+
+	rand := random.NewRand(seed)
+	number := rand.Intn((max+1)-min) + min
+
+	u := &integerModelV0{
+		ID:      types.StringValue(strconv.Itoa(number)),
+		Keepers: plan.Keepers,
+		Min:     types.Int64Value(int64(min)),
+		Max:     types.Int64Value(int64(max)),
+		Result:  types.Int64Value(int64(number)),
+	}
+
+	if seed != "" {
+		u.Seed = types.StringValue(seed)
+	} else {
+		u.Seed = types.StringNull()
+	}
+
+	diags = resp.State.Set(ctx, u)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *integerResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *integerResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model integerModelV0
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *integerResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+}
+
+func (r *integerResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	parts := strings.Split(req.ID, ",")
+	if len(parts) != 3 && len(parts) != 4 {
+		resp.Diagnostics.AddError(
+			"Import Random Integer Error",
+			"Invalid import usage: expecting {result},{min},{max} or {result},{min},{max},{seed}",
+		)
+		return
+	}
+
+	result, err := strconv.ParseInt(parts[0], 10, 64)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random Integer Error",
+			"The value supplied could not be parsed as an integer.\n\n"+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	min, err := strconv.ParseInt(parts[1], 10, 64)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random Integer Error",
+			"The min value supplied could not be parsed as an integer.\n\n"+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	max, err := strconv.ParseInt(parts[2], 10, 64)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random Integer Error",
+			"The max value supplied could not be parsed as an integer.\n\n"+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	var state integerModelV0
+
+	state.ID = types.StringValue(parts[0])
+	// Using types.MapValueMust to ensure map is known.
+	state.Keepers = types.MapValueMust(types.StringType, nil)
+	state.Result = types.Int64Value(result)
+	state.Min = types.Int64Value(min)
+	state.Max = types.Int64Value(max)
+
+	if len(parts) == 4 {
+		state.Seed = types.StringValue(parts[3])
+	}
+
+	diags := resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+type integerModelV0 struct {
+	ID      types.String `tfsdk:"id"`
+	Keepers types.Map    `tfsdk:"keepers"`
+	Min     types.Int64  `tfsdk:"min"`
+	Max     types.Int64  `tfsdk:"max"`
+	Seed    types.String `tfsdk:"seed"`
+	Result  types.Int64  `tfsdk:"result"`
+}
diff --git a/v3.6.0/internal/provider/resource_integer_test.go b/v3.6.0/internal/provider/resource_integer_test.go
new file mode 100644
index 0000000..2d71b6b
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_integer_test.go
@@ -0,0 +1,1025 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/terraform"
+)
+
+func TestAccResourceInteger(t *testing.T) {
+	t.Parallel()
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+							max  = 3
+   							seed = "12345"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "3"),
+				),
+			},
+			{
+				ResourceName:      "random_integer.integer_1",
+				ImportState:       true,
+				ImportStateId:     "3,1,3,12345",
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_ChangeSeed(t *testing.T) {
+	t.Parallel()
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+							max  = 3
+   							seed = "12345"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "3"),
+				),
+			},
+			{
+				Config: `resource "random_integer" "integer_1" {
+							min  = 1
+   							max  = 3
+   							seed = "123456"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_SeedlessToSeeded(t *testing.T) {
+	t.Parallel()
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+   							max  = 3
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_integer.integer_1", "result", testCheckNotEmptyString("result")),
+				),
+			},
+			{
+				Config: `resource "random_integer" "integer_1" {
+							min  = 1
+   							max  = 3
+   							seed = "123456"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_SeededToSeedless(t *testing.T) {
+	t.Parallel()
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+							max  = 3
+   							seed = "12345"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "3"),
+				),
+			},
+			{
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+   							max  = 3
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_integer.integer_1", "result", testCheckNotEmptyString("result")),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Big(t *testing.T) {
+	t.Parallel()
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_integer" "integer_1" {
+   							max  = 7227701560655103598
+   							min  = 7227701560655103597
+   							seed = 12345
+						}`,
+			},
+			{
+				ResourceName:      "random_integer.integer_1",
+				ImportState:       true,
+				ImportStateId:     "7227701560655103598,7227701560655103597,7227701560655103598,12345",
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+							max  = 3
+   							seed = "12345"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "3"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+							max  = 3
+   							seed = "12345"
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "integer_1" {
+   							min  = 1
+							max  = 3
+   							seed = "12345"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_integer.integer_1", "result", "3"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_EmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_NullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_NullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_NullValues(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_Value(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Keep_Values(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceInteger_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_integer" "test" {
+					min = 1
+					max = 100000000
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_integer.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_integer.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func testCheckNotEmptyString(field string) func(input string) error {
+	return func(input string) error {
+		if input == "" {
+			return fmt.Errorf("%s is empty string", field)
+		}
+
+		return nil
+	}
+}
+
+func testExtractResourceAttr(resourceName string, attributeName string, attributeValue *string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		rs, ok := s.RootModule().Resources[resourceName]
+
+		if !ok {
+			return fmt.Errorf("resource name %s not found in state", resourceName)
+		}
+
+		attrValue, ok := rs.Primary.Attributes[attributeName]
+
+		if !ok {
+			return fmt.Errorf("attribute %s not found in resource %s state", attributeName, resourceName)
+		}
+
+		*attributeValue = attrValue
+
+		return nil
+	}
+}
+
+func testCheckAttributeValuesDiffer(i *string, j *string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		if testStringValue(i) == testStringValue(j) {
+			return fmt.Errorf("attribute values are the same")
+		}
+
+		return nil
+	}
+}
+
+func testCheckAttributeValuesEqual(i *string, j *string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		if testStringValue(i) != testStringValue(j) {
+			return fmt.Errorf("attribute values are different, got %s and %s", testStringValue(i), testStringValue(j))
+		}
+
+		return nil
+	}
+}
+
+func testStringValue(sPtr *string) string {
+	if sPtr == nil {
+		return ""
+	}
+
+	return *sPtr
+}
diff --git a/v3.6.0/internal/provider/resource_password.go b/v3.6.0/internal/provider/resource_password.go
new file mode 100644
index 0000000..5166f92
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_password.go
@@ -0,0 +1,1045 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"errors"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"golang.org/x/crypto/bcrypt"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/diagnostics"
+	boolplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/bool"
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+	stringplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/string"
+	"github.com/terraform-providers/terraform-provider-random/internal/random"
+)
+
+var (
+	_ resource.Resource                 = (*passwordResource)(nil)
+	_ resource.ResourceWithImportState  = (*passwordResource)(nil)
+	_ resource.ResourceWithUpgradeState = (*passwordResource)(nil)
+)
+
+func NewPasswordResource() resource.Resource {
+	return &passwordResource{}
+}
+
+type passwordResource struct{}
+
+func (r *passwordResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_password"
+}
+
+func (r *passwordResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = passwordSchemaV3()
+}
+
+func (r *passwordResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan passwordModelV3
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	params := random.StringParams{
+		Length:          plan.Length.ValueInt64(),
+		Upper:           plan.Upper.ValueBool(),
+		MinUpper:        plan.MinUpper.ValueInt64(),
+		Lower:           plan.Lower.ValueBool(),
+		MinLower:        plan.MinLower.ValueInt64(),
+		Numeric:         plan.Numeric.ValueBool(),
+		MinNumeric:      plan.MinNumeric.ValueInt64(),
+		Special:         plan.Special.ValueBool(),
+		MinSpecial:      plan.MinSpecial.ValueInt64(),
+		OverrideSpecial: plan.OverrideSpecial.ValueString(),
+	}
+
+	result, err := random.CreateString(params)
+	if err != nil {
+		resp.Diagnostics.Append(diagnostics.RandomReadError(err.Error())...)
+		return
+	}
+
+	hash, err := generateHash(string(result))
+	if err != nil {
+		resp.Diagnostics.Append(diagnostics.HashGenerationError(err.Error())...)
+	}
+
+	plan.BcryptHash = types.StringValue(hash)
+	plan.ID = types.StringValue("none")
+	plan.Result = types.StringValue(string(result))
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *passwordResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *passwordResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model passwordModelV3
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *passwordResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+}
+
+func (r *passwordResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	id := req.ID
+
+	state := passwordModelV3{
+		ID:              types.StringValue("none"),
+		Result:          types.StringValue(id),
+		Length:          types.Int64Value(int64(len(id))),
+		Special:         types.BoolValue(true),
+		Upper:           types.BoolValue(true),
+		Lower:           types.BoolValue(true),
+		Number:          types.BoolValue(true),
+		Numeric:         types.BoolValue(true),
+		MinSpecial:      types.Int64Value(0),
+		MinUpper:        types.Int64Value(0),
+		MinLower:        types.Int64Value(0),
+		MinNumeric:      types.Int64Value(0),
+		Keepers:         types.MapNull(types.StringType),
+		OverrideSpecial: types.StringNull(),
+	}
+
+	hash, err := generateHash(id)
+	if err != nil {
+		resp.Diagnostics.Append(diagnostics.HashGenerationError(err.Error())...)
+	}
+
+	state.BcryptHash = types.StringValue(hash)
+
+	diags := resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *passwordResource) UpgradeState(context.Context) map[int64]resource.StateUpgrader {
+	schemaV0 := passwordSchemaV0()
+	schemaV1 := passwordSchemaV1()
+	schemaV2 := passwordSchemaV2()
+
+	return map[int64]resource.StateUpgrader{
+		0: {
+			PriorSchema:   &schemaV0,
+			StateUpgrader: upgradePasswordStateV0toV3,
+		},
+		1: {
+			PriorSchema:   &schemaV1,
+			StateUpgrader: upgradePasswordStateV1toV3,
+		},
+		2: {
+			PriorSchema:   &schemaV2,
+			StateUpgrader: upgradePasswordStateV2toV3,
+		},
+	}
+}
+
+func upgradePasswordStateV0toV3(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
+	type modelV0 struct {
+		ID              types.String `tfsdk:"id"`
+		Keepers         types.Map    `tfsdk:"keepers"`
+		Length          types.Int64  `tfsdk:"length"`
+		Special         types.Bool   `tfsdk:"special"`
+		Upper           types.Bool   `tfsdk:"upper"`
+		Lower           types.Bool   `tfsdk:"lower"`
+		Number          types.Bool   `tfsdk:"number"`
+		MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+		MinUpper        types.Int64  `tfsdk:"min_upper"`
+		MinLower        types.Int64  `tfsdk:"min_lower"`
+		MinSpecial      types.Int64  `tfsdk:"min_special"`
+		OverrideSpecial types.String `tfsdk:"override_special"`
+		Result          types.String `tfsdk:"result"`
+	}
+
+	var passwordDataV0 modelV0
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &passwordDataV0)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Setting fields that can contain null to non-null to prevent forced replacement.
+	// This can occur in cases where import has been used in provider versions v3.3.1 and earlier.
+	// If import has been used with v3.3.1, for instance then length, lower, number, special, upper,
+	// min_lower, min_numeric, min_special and min_upper attributes will all be null in state.
+	length := passwordDataV0.Length
+
+	if length.IsNull() {
+		length = types.Int64Value(int64(len(passwordDataV0.Result.ValueString())))
+	}
+
+	minNumeric := passwordDataV0.MinNumeric
+
+	if minNumeric.IsNull() {
+		minNumeric = types.Int64Value(0)
+	}
+
+	minUpper := passwordDataV0.MinUpper
+
+	if minUpper.IsNull() {
+		minUpper = types.Int64Value(0)
+	}
+
+	minLower := passwordDataV0.MinLower
+
+	if minLower.IsNull() {
+		minLower = types.Int64Value(0)
+	}
+
+	minSpecial := passwordDataV0.MinSpecial
+
+	if minSpecial.IsNull() {
+		minSpecial = types.Int64Value(0)
+	}
+
+	special := passwordDataV0.Special
+
+	if special.IsNull() {
+		special = types.BoolValue(true)
+	}
+
+	upper := passwordDataV0.Upper
+
+	if upper.IsNull() {
+		upper = types.BoolValue(true)
+	}
+
+	lower := passwordDataV0.Lower
+
+	if lower.IsNull() {
+		lower = types.BoolValue(true)
+	}
+
+	number := passwordDataV0.Number
+
+	if number.IsNull() {
+		number = types.BoolValue(true)
+	}
+
+	passwordDataV3 := passwordModelV3{
+		Keepers:         passwordDataV0.Keepers,
+		Length:          length,
+		Special:         special,
+		Upper:           upper,
+		Lower:           lower,
+		Number:          number,
+		Numeric:         number,
+		MinNumeric:      minNumeric,
+		MinUpper:        minUpper,
+		MinLower:        minLower,
+		MinSpecial:      minSpecial,
+		OverrideSpecial: passwordDataV0.OverrideSpecial,
+		Result:          passwordDataV0.Result,
+		ID:              passwordDataV0.ID,
+	}
+
+	hash, err := generateHash(passwordDataV3.Result.ValueString())
+	if err != nil {
+		resp.Diagnostics.Append(diagnostics.HashGenerationError(err.Error())...)
+		return
+	}
+
+	passwordDataV3.BcryptHash = types.StringValue(hash)
+
+	diags := resp.State.Set(ctx, passwordDataV3)
+	resp.Diagnostics.Append(diags...)
+}
+
+func upgradePasswordStateV1toV3(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
+	type modelV1 struct {
+		ID              types.String `tfsdk:"id"`
+		Keepers         types.Map    `tfsdk:"keepers"`
+		Length          types.Int64  `tfsdk:"length"`
+		Special         types.Bool   `tfsdk:"special"`
+		Upper           types.Bool   `tfsdk:"upper"`
+		Lower           types.Bool   `tfsdk:"lower"`
+		Number          types.Bool   `tfsdk:"number"`
+		MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+		MinUpper        types.Int64  `tfsdk:"min_upper"`
+		MinLower        types.Int64  `tfsdk:"min_lower"`
+		MinSpecial      types.Int64  `tfsdk:"min_special"`
+		OverrideSpecial types.String `tfsdk:"override_special"`
+		Result          types.String `tfsdk:"result"`
+		BcryptHash      types.String `tfsdk:"bcrypt_hash"`
+	}
+
+	var passwordDataV1 modelV1
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &passwordDataV1)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Setting fields that can contain null to non-null to prevent forced replacement.
+	// This can occur in cases where import has been used in provider versions v3.3.1 and earlier.
+	// If import has been used with v3.3.1, for instance then length, lower, number, special, upper,
+	// min_lower, min_numeric, min_special and min_upper attributes will all be null in state.
+	length := passwordDataV1.Length
+
+	if length.IsNull() {
+		length = types.Int64Value(int64(len(passwordDataV1.Result.ValueString())))
+	}
+
+	minNumeric := passwordDataV1.MinNumeric
+
+	if minNumeric.IsNull() {
+		minNumeric = types.Int64Value(0)
+	}
+
+	minUpper := passwordDataV1.MinUpper
+
+	if minUpper.IsNull() {
+		minUpper = types.Int64Value(0)
+	}
+
+	minLower := passwordDataV1.MinLower
+
+	if minLower.IsNull() {
+		minLower = types.Int64Value(0)
+	}
+
+	minSpecial := passwordDataV1.MinSpecial
+
+	if minSpecial.IsNull() {
+		minSpecial = types.Int64Value(0)
+	}
+
+	special := passwordDataV1.Special
+
+	if special.IsNull() {
+		special = types.BoolValue(true)
+	}
+
+	upper := passwordDataV1.Upper
+
+	if upper.IsNull() {
+		upper = types.BoolValue(true)
+	}
+
+	lower := passwordDataV1.Lower
+
+	if lower.IsNull() {
+		lower = types.BoolValue(true)
+	}
+
+	number := passwordDataV1.Number
+
+	if number.IsNull() {
+		number = types.BoolValue(true)
+	}
+
+	passwordDataV3 := passwordModelV3{
+		Keepers:         passwordDataV1.Keepers,
+		Length:          length,
+		Special:         special,
+		Upper:           upper,
+		Lower:           lower,
+		Number:          number,
+		Numeric:         number,
+		MinNumeric:      minNumeric,
+		MinUpper:        minUpper,
+		MinLower:        minLower,
+		MinSpecial:      minSpecial,
+		OverrideSpecial: passwordDataV1.OverrideSpecial,
+		BcryptHash:      passwordDataV1.BcryptHash,
+		Result:          passwordDataV1.Result,
+		ID:              passwordDataV1.ID,
+	}
+
+	diags := resp.State.Set(ctx, passwordDataV3)
+	resp.Diagnostics.Append(diags...)
+}
+
+func upgradePasswordStateV2toV3(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
+	type passwordModelV2 struct {
+		ID              types.String `tfsdk:"id"`
+		Keepers         types.Map    `tfsdk:"keepers"`
+		Length          types.Int64  `tfsdk:"length"`
+		Special         types.Bool   `tfsdk:"special"`
+		Upper           types.Bool   `tfsdk:"upper"`
+		Lower           types.Bool   `tfsdk:"lower"`
+		Number          types.Bool   `tfsdk:"number"`
+		Numeric         types.Bool   `tfsdk:"numeric"`
+		MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+		MinUpper        types.Int64  `tfsdk:"min_upper"`
+		MinLower        types.Int64  `tfsdk:"min_lower"`
+		MinSpecial      types.Int64  `tfsdk:"min_special"`
+		OverrideSpecial types.String `tfsdk:"override_special"`
+		Result          types.String `tfsdk:"result"`
+		BcryptHash      types.String `tfsdk:"bcrypt_hash"`
+	}
+
+	var passwordDataV2 passwordModelV2
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &passwordDataV2)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Setting fields that can contain null to non-null to prevent forced replacement.
+	// This can occur in cases where import has been used in provider versions v3.3.1 and earlier.
+	// If import has been used with v3.3.1, for instance then length, lower, number, special, upper,
+	// min_lower, min_numeric, min_special and min_upper attributes will all be null in state.
+	length := passwordDataV2.Length
+
+	if length.IsNull() {
+		length = types.Int64Value(int64(len(passwordDataV2.Result.ValueString())))
+	}
+
+	minNumeric := passwordDataV2.MinNumeric
+
+	if minNumeric.IsNull() {
+		minNumeric = types.Int64Value(0)
+	}
+
+	minUpper := passwordDataV2.MinUpper
+
+	if minUpper.IsNull() {
+		minUpper = types.Int64Value(0)
+	}
+
+	minLower := passwordDataV2.MinLower
+
+	if minLower.IsNull() {
+		minLower = types.Int64Value(0)
+	}
+
+	minSpecial := passwordDataV2.MinSpecial
+
+	if minSpecial.IsNull() {
+		minSpecial = types.Int64Value(0)
+	}
+
+	special := passwordDataV2.Special
+
+	if special.IsNull() {
+		special = types.BoolValue(true)
+	}
+
+	upper := passwordDataV2.Upper
+
+	if upper.IsNull() {
+		upper = types.BoolValue(true)
+	}
+
+	lower := passwordDataV2.Lower
+
+	if lower.IsNull() {
+		lower = types.BoolValue(true)
+	}
+
+	number := passwordDataV2.Number
+
+	if number.IsNull() {
+		number = types.BoolValue(true)
+	}
+
+	numeric := passwordDataV2.Number
+
+	if numeric.IsNull() {
+		numeric = types.BoolValue(true)
+	}
+
+	// Schema version 2 to schema version 3 is a duplicate of the data,
+	// however the BcryptHash value may have been incorrectly generated.
+	//nolint:gosimple // V3 model will expand over time so all fields are written out to help future code changes.
+	passwordDataV3 := passwordModelV3{
+		BcryptHash:      passwordDataV2.BcryptHash,
+		ID:              passwordDataV2.ID,
+		Keepers:         passwordDataV2.Keepers,
+		Length:          length,
+		Lower:           lower,
+		MinLower:        minLower,
+		MinNumeric:      minNumeric,
+		MinSpecial:      minSpecial,
+		MinUpper:        minUpper,
+		Number:          number,
+		Numeric:         numeric,
+		OverrideSpecial: passwordDataV2.OverrideSpecial,
+		Result:          passwordDataV2.Result,
+		Special:         special,
+		Upper:           upper,
+	}
+
+	// Set the duplicated data now so we can easily return early below.
+	// The BcryptHash value will be adjusted later if it is incorrect.
+	resp.Diagnostics.Append(resp.State.Set(ctx, passwordDataV3)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// If the BcryptHash value does not correctly verify against the Result
+	// value we should regenerate it.
+	err := bcrypt.CompareHashAndPassword([]byte(passwordDataV2.BcryptHash.ValueString()), []byte(passwordDataV2.Result.ValueString()))
+
+	// If the hash matched the password, there is nothing to do.
+	if err == nil {
+		return
+	}
+
+	if !errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
+		resp.Diagnostics.AddError(
+			"Version 3 State Upgrade Error",
+			"An unexpected error occurred when comparing the state version 2 password and bcrypt hash. "+
+				"This is always an issue in the provider and should be reported to the provider developers.\n\n"+
+				"Original Error: "+err.Error(),
+		)
+		return
+	}
+
+	// Regenerate the BcryptHash value.
+	newBcryptHash, err := bcrypt.GenerateFromPassword([]byte(passwordDataV2.Result.ValueString()), bcrypt.DefaultCost)
+
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Version 3 State Upgrade Error",
+			"An unexpected error occurred when generating a new password bcrypt hash. "+
+				"Check the error below and ensure the system executing Terraform can properly generate randomness.\n\n"+
+				"Original Error: "+err.Error(),
+		)
+		return
+	}
+
+	passwordDataV3.BcryptHash = types.StringValue(string(newBcryptHash))
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, passwordDataV3)...)
+}
+
+// generateHash truncates strings that are longer than 72 bytes in
+// order to avoid the error returned from bcrypt.GenerateFromPassword
+// in versions v0.5.0 and above: https://pkg.go.dev/golang.org/x/crypto@v0.8.0/bcrypt#GenerateFromPassword
+func generateHash(toHash string) (string, error) {
+	bytesHash := []byte(toHash)
+	bytesToHash := bytesHash
+
+	if len(bytesHash) > 72 {
+		bytesToHash = bytesHash[:72]
+	}
+
+	hash, err := bcrypt.GenerateFromPassword(bytesToHash, bcrypt.DefaultCost)
+
+	return string(hash), err
+}
+
+func passwordSchemaV3() schema.Schema {
+	return schema.Schema{
+		Version: 3,
+		Description: "Identical to [random_string](string.html) with the exception that the result is " +
+			"treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive " +
+			"data handling in the " +
+			"[Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).\n\n" +
+			"This resource *does* use a cryptographic random number generator.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+				Validators: []validator.Int64{
+					int64validator.AtLeast(1),
+					int64validator.AtLeastSumOf(
+						path.MatchRoot("min_upper"),
+						path.MatchRoot("min_lower"),
+						path.MatchRoot("min_numeric"),
+						path.MatchRoot("min_special"),
+					),
+				},
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifier.RequiresReplace(),
+				}},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`. " +
+					"**NOTE**: This is deprecated, use `numeric` instead.",
+				Optional: true,
+				Computed: true,
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifiers.NumberNumericAttributePlanModifier(),
+					boolplanmodifier.RequiresReplace(),
+				},
+				DeprecationMessage: "**NOTE**: This is deprecated, use `numeric` instead.",
+			},
+
+			"numeric": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifiers.NumberNumericAttributePlanModifier(),
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplaceIf(
+						stringplanmodifiers.RequiresReplaceUnlessEmptyStringToNull(),
+						"Replace on modification unless updating from empty string (\"\") to null.",
+						"Replace on modification unless updating from empty string (`\"\"`) to `null`.",
+					),
+				},
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+				Sensitive:   true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+
+			"bcrypt_hash": schema.StringAttribute{
+				Description: "A bcrypt hash of the generated random string. " +
+					"**NOTE**: If the generated random string is greater than 72 bytes in length, " +
+					"`bcrypt_hash` will contain a hash of the first 72 bytes.",
+				Computed:  true,
+				Sensitive: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+
+			"id": schema.StringAttribute{
+				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func passwordSchemaV2() schema.Schema {
+	return schema.Schema{
+		Version: 2,
+		Description: "Identical to [random_string](string.html) with the exception that the result is " +
+			"treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive " +
+			"data handling in the " +
+			"[Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).\n\n" +
+			"This resource *does* use a cryptographic random number generator.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`. " +
+					"**NOTE**: This is deprecated, use `numeric` instead.",
+				Optional:           true,
+				Computed:           true,
+				DeprecationMessage: "**NOTE**: This is deprecated, use `numeric` instead.",
+			},
+
+			"numeric": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				Computed: true,
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+				Sensitive:   true,
+			},
+
+			"bcrypt_hash": schema.StringAttribute{
+				Description: "A bcrypt hash of the generated random string. " +
+					"**NOTE**: If the generated random string is greater than 72 bytes in length, " +
+					"`bcrypt_hash` will contain a hash of the first 72 bytes.",
+				Computed:  true,
+				Sensitive: true,
+			},
+
+			"id": schema.StringAttribute{
+				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
+				Computed:    true,
+			},
+		},
+	}
+}
+
+func passwordSchemaV1() schema.Schema {
+	return schema.Schema{
+		Version: 1,
+		Description: "Identical to [random_string](string.html) with the exception that the result is " +
+			"treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive " +
+			"data handling in the " +
+			"[Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).\n\n" +
+			"This resource *does* use a cryptographic random number generator.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				Computed: true,
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+				Sensitive:   true,
+			},
+
+			"bcrypt_hash": schema.StringAttribute{
+				Description: "A bcrypt hash of the generated random string. " +
+					"**NOTE**: If the generated random string is greater than 72 bytes in length, " +
+					"`bcrypt_hash` will contain a hash of the first 72 bytes.",
+				Computed:  true,
+				Sensitive: true,
+			},
+
+			"id": schema.StringAttribute{
+				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
+				Computed:    true,
+			},
+		},
+	}
+}
+
+func passwordSchemaV0() schema.Schema {
+	return schema.Schema{
+		Description: "Identical to [random_string](string.html) with the exception that the result is " +
+			"treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive " +
+			"data handling in the " +
+			"[Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).\n\n" +
+			"This resource *does* use a cryptographic random number generator.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				Computed: true,
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+				Sensitive:   true,
+			},
+
+			"id": schema.StringAttribute{
+				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
+				Computed:    true,
+			},
+		},
+	}
+}
+
+type passwordModelV3 struct {
+	ID              types.String `tfsdk:"id"`
+	Keepers         types.Map    `tfsdk:"keepers"`
+	Length          types.Int64  `tfsdk:"length"`
+	Special         types.Bool   `tfsdk:"special"`
+	Upper           types.Bool   `tfsdk:"upper"`
+	Lower           types.Bool   `tfsdk:"lower"`
+	Number          types.Bool   `tfsdk:"number"`
+	Numeric         types.Bool   `tfsdk:"numeric"`
+	MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+	MinUpper        types.Int64  `tfsdk:"min_upper"`
+	MinLower        types.Int64  `tfsdk:"min_lower"`
+	MinSpecial      types.Int64  `tfsdk:"min_special"`
+	OverrideSpecial types.String `tfsdk:"override_special"`
+	Result          types.String `tfsdk:"result"`
+	BcryptHash      types.String `tfsdk:"bcrypt_hash"`
+}
diff --git a/v3.6.0/internal/provider/resource_password_test.go b/v3.6.0/internal/provider/resource_password_test.go
new file mode 100644
index 0000000..d4c7f50
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_password_test.go
@@ -0,0 +1,2819 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"regexp"
+	"runtime"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	res "github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/tfsdk"
+	"github.com/hashicorp/terraform-plugin-go/tftypes"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/terraform"
+	"golang.org/x/crypto/bcrypt"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/random"
+)
+
+func TestGenerateHash(t *testing.T) {
+	t.Parallel()
+
+	testCases := map[string]struct {
+		input random.StringParams
+	}{
+		"defaults": {
+			input: random.StringParams{
+				Length:  73, // Required
+				Lower:   true,
+				Numeric: true,
+				Special: true,
+				Upper:   true,
+			},
+		},
+	}
+
+	for name, testCase := range testCases {
+		name, testCase := name, testCase
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+
+			randomBytes, err := random.CreateString(testCase.input)
+
+			if err != nil {
+				t.Fatalf("unexpected random.CreateString error: %s", err)
+			}
+
+			hash, err := generateHash(string(randomBytes))
+
+			if err != nil {
+				t.Fatalf("unexpected generateHash error: %s", err)
+			}
+
+			err = bcrypt.CompareHashAndPassword([]byte(hash), randomBytes)
+
+			if err != nil {
+				t.Fatalf("unexpected bcrypt.CompareHashAndPassword error: %s", err)
+			}
+		})
+	}
+}
+
+func TestAccResourcePassword_Import(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_password" "basic" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.basic", "result", testCheckLen(12)),
+				),
+			},
+			{
+				ResourceName: "random_password.basic",
+				// Usage of ImportStateIdFunc is required as the value passed to the `terraform import` command needs
+				// to be the password itself, as the password resource sets ID to "none" and "result" to the password
+				// supplied during import.
+				ImportStateIdFunc: func(s *terraform.State) (string, error) {
+					id := "random_password.basic"
+					rs, ok := s.RootModule().Resources[id]
+					if !ok {
+						return "", fmt.Errorf("not found: %s", id)
+					}
+					if rs.Primary.ID == "" {
+						return "", fmt.Errorf("no ID is set")
+					}
+
+					return rs.Primary.Attributes["result"], nil
+				},
+				ImportState:             true,
+				ImportStateVerify:       true,
+				ImportStateVerifyIgnore: []string{"bcrypt_hash"},
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_BcryptHash(t *testing.T) {
+	t.Parallel()
+
+	var result, bcryptHash string
+
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_password" "test" {
+							length = 73
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "bcrypt_hash", &bcryptHash),
+					testExtractResourceAttr("random_password.test", "result", &result),
+					testBcryptHashValid(&bcryptHash, &result),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_BcryptHash_FromVersion3_3_2 verifies behaviour when
+// upgrading state from schema V2 to V3 without a bcrypt_hash update.
+func TestAccResourcePassword_BcryptHash_FromVersion3_3_2(t *testing.T) {
+	var bcryptHash1, bcryptHash2, result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "bcrypt_hash", &bcryptHash1),
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					testBcryptHashValid(&bcryptHash1, &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "bcrypt_hash", &bcryptHash2),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&bcryptHash1, &bcryptHash2),
+					testBcryptHashValid(&bcryptHash2, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_BcryptHash_FromVersion3_4_2 verifies behaviour when
+// upgrading state from schema V2 to V3 with an expected bcrypt_hash update.
+func TestAccResourcePassword_BcryptHash_FromVersion3_4_2(t *testing.T) {
+	var bcryptHash1, bcryptHash2, result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion342(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "bcrypt_hash", &bcryptHash1),
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					testBcryptHashInvalid(&bcryptHash1, &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "bcrypt_hash", &bcryptHash2),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&bcryptHash1, &bcryptHash2),
+					testBcryptHashValid(&bcryptHash2, &result2),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Override(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_password" "override" {
+							length = 4
+							override_special = "!"
+							lower = false
+							upper = false
+							numeric = false
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.override", "result", testCheckLen(4)),
+					resource.TestCheckResourceAttr("random_password.override", "result", "!!!!"),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_OverrideSpecial_FromVersion3_3_2 verifies behaviour
+// when upgrading the provider version from 3.3.2, which set the
+// override_special value to null and should not result in a plan difference.
+// Reference: https://github.com/hashicorp/terraform-provider-random/issues/306
+func TestAccResourcePassword_OverrideSpecial_FromVersion3_3_2(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckNoResourceAttr("random_password.test", "override_special"),
+					testExtractResourceAttr("random_password.test", "result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckNoResourceAttr("random_password.test", "override_special"),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_OverrideSpecial_FromVersion3_4_2 verifies behaviour
+// when upgrading the provider version from 3.4.2, which set the
+// override_special value to "", while other versions do not.
+// Reference: https://github.com/hashicorp/terraform-provider-random/issues/306
+func TestAccResourcePassword_OverrideSpecial_FromVersion3_4_2(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion342(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_password.test", "override_special", ""),
+					testExtractResourceAttr("random_password.test", "result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckNoResourceAttr("random_password.test", "override_special"),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_Import_FromVersion3_1_3 verifies behaviour when resource has been imported and stores
+// null for length, lower, number, special, upper, min_lower, min_numeric, min_special, min_upper attributes in state.
+// v3.1.3 was selected as this is the last provider version using schema version 0.
+func TestAccResourcePassword_Import_FromVersion3_1_3(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion313(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				ResourceName:       "random_password.test",
+				ImportState:        true,
+				ImportStateId:      "Z=:cbrJE?Ltg",
+				ImportStatePersist: true,
+				ImportStateCheck: composeImportStateCheck(
+					testCheckNoResourceAttrInstanceState("length"),
+					testCheckNoResourceAttrInstanceState("number"),
+					testCheckNoResourceAttrInstanceState("upper"),
+					testCheckNoResourceAttrInstanceState("lower"),
+					testCheckNoResourceAttrInstanceState("special"),
+					testCheckNoResourceAttrInstanceState("min_numeric"),
+					testCheckNoResourceAttrInstanceState("min_upper"),
+					testCheckNoResourceAttrInstanceState("min_lower"),
+					testCheckNoResourceAttrInstanceState("min_special"),
+					testExtractResourceAttrInstanceState("result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.test", "result", testCheckLen(12)),
+					resource.TestCheckResourceAttr("random_password.test", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "min_numeric", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_upper", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_lower", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_special", "0"),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_Import_FromVersion3_2_0 verifies behaviour when resource has been imported and stores
+// null for length, lower, number, special, upper, min_lower, min_numeric, min_special, min_upper attributes in state.
+// v3.2.0 was selected as this is the last provider version using schema version 1.
+func TestAccResourcePassword_Import_FromVersion3_2_0(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion320(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				ResourceName:       "random_password.test",
+				ImportState:        true,
+				ImportStateId:      "Z=:cbrJE?Ltg",
+				ImportStatePersist: true,
+				ImportStateCheck: composeImportStateCheck(
+					testCheckNoResourceAttrInstanceState("length"),
+					testCheckNoResourceAttrInstanceState("number"),
+					testCheckNoResourceAttrInstanceState("upper"),
+					testCheckNoResourceAttrInstanceState("lower"),
+					testCheckNoResourceAttrInstanceState("special"),
+					testCheckNoResourceAttrInstanceState("min_numeric"),
+					testCheckNoResourceAttrInstanceState("min_upper"),
+					testCheckNoResourceAttrInstanceState("min_lower"),
+					testCheckNoResourceAttrInstanceState("min_special"),
+					testExtractResourceAttrInstanceState("result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.test", "result", testCheckLen(12)),
+					resource.TestCheckResourceAttr("random_password.test", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "min_numeric", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_upper", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_lower", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_special", "0"),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_Import_FromVersion3_4_2 verifies behaviour when resource has been imported and stores
+// empty map {} for keepers and empty string for override_special in state.
+// v3.4.2 was selected as this is the last provider version using schema version 2.
+func TestAccResourcePassword_Import_FromVersion3_4_2(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion342(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				ResourceName:       "random_password.test",
+				ImportState:        true,
+				ImportStateId:      "Z=:cbrJE?Ltg",
+				ImportStatePersist: true,
+				ImportStateCheck: composeImportStateCheck(
+					testCheckResourceAttrInstanceState("length"),
+					testCheckResourceAttrInstanceState("number"),
+					testCheckResourceAttrInstanceState("numeric"),
+					testCheckResourceAttrInstanceState("upper"),
+					testCheckResourceAttrInstanceState("lower"),
+					testCheckResourceAttrInstanceState("special"),
+					testCheckResourceAttrInstanceState("min_numeric"),
+					testCheckResourceAttrInstanceState("min_upper"),
+					testCheckResourceAttrInstanceState("min_lower"),
+					testCheckResourceAttrInstanceState("min_special"),
+					testExtractResourceAttrInstanceState("result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.test", "result", testCheckLen(12)),
+					resource.TestCheckResourceAttr("random_password.test", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.test", "min_numeric", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_upper", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_lower", "0"),
+					resource.TestCheckResourceAttr("random_password.test", "min_special", "0"),
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_StateUpgradeV0toV3 covers the state upgrades from V0 to V3.
+// This includes the addition of `numeric` and `bcrypt_hash` attributes.
+// v3.1.3 is used as this is last version before `bcrypt_hash` attributed was added.
+func TestAccResourcePassword_StateUpgradeV0toV3(t *testing.T) {
+	t.Parallel()
+
+	cases := []struct {
+		name                string
+		configBeforeUpgrade string
+		configDuringUpgrade string
+		beforeStateUpgrade  []resource.TestCheckFunc
+		afterStateUpgrade   []resource.TestCheckFunc
+	}{
+		{
+			name: "bcrypt_hash",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckNoResourceAttr("random_password.default", "bcrypt_hash"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttrSet("random_password.default", "bcrypt_hash"),
+			},
+		},
+		{
+			name: "number is absent before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is absent before numeric is true during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric")},
+		},
+		{
+			name: "number is absent before numeric is false during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before numeric is false during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is false during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is absent during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is true during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			resource.UnitTest(t, resource.TestCase{
+				Steps: []resource.TestStep{
+					{
+						ExternalProviders: map[string]resource.ExternalProvider{"random": {
+							VersionConstraint: "3.1.3",
+							Source:            "hashicorp/random",
+						}},
+						Config: c.configBeforeUpgrade,
+						Check:  resource.ComposeTestCheckFunc(c.beforeStateUpgrade...),
+					},
+					{
+						ProtoV5ProviderFactories: protoV5ProviderFactories(),
+						Config:                   c.configDuringUpgrade,
+						Check:                    resource.ComposeTestCheckFunc(c.afterStateUpgrade...),
+					},
+				},
+			})
+		})
+	}
+}
+
+// TestAccResourcePassword_StateUpgrade_V1toV3 covers the state upgrades from V1 to V3.
+// This includes the addition of `numeric` attribute.
+// v3.2.0 was used as this is the last version before `number` was deprecated and `numeric` attribute
+// was added.
+func TestAccResourcePassword_StateUpgradeV1toV3(t *testing.T) {
+	t.Parallel()
+
+	cases := []struct {
+		name                string
+		configBeforeUpgrade string
+		configDuringUpgrade string
+		beforeStateUpgrade  []resource.TestCheckFunc
+		afterStateUpgrade   []resource.TestCheckFunc
+	}{
+		{
+			name: "number is absent before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is absent before numeric is true during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is absent before numeric is false during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before numeric is true during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before numeric is false during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is false during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is absent during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is true during",
+			configBeforeUpgrade: `resource "random_password" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_password" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_password.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_password.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_password.default", "number", "random_password.default", "numeric"),
+			},
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			if c.configDuringUpgrade == "" {
+				c.configDuringUpgrade = c.configBeforeUpgrade
+			}
+
+			// TODO: Why is resource.Test not being used here
+			resource.UnitTest(t, resource.TestCase{
+				Steps: []resource.TestStep{
+					{
+						ExternalProviders: map[string]resource.ExternalProvider{"random": {
+							VersionConstraint: "3.2.0",
+							Source:            "hashicorp/random",
+						}},
+						Config: c.configBeforeUpgrade,
+						Check:  resource.ComposeTestCheckFunc(c.beforeStateUpgrade...),
+					},
+					{
+						ProtoV5ProviderFactories: protoV5ProviderFactories(),
+						Config:                   c.configDuringUpgrade,
+						Check:                    resource.ComposeTestCheckFunc(c.afterStateUpgrade...),
+					},
+				},
+			})
+		})
+	}
+}
+
+func TestAccResourcePassword_Min(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_UpgradeFromVersion2_2_1 verifies behaviour when upgrading state from schema V0 to V3.
+func TestAccResourcePassword_UpgradeFromVersion2_2_1(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		PreCheck: func() {
+			if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+				t.Skip("This test requires darwin/amd64 to download the old provider version. Setting TF_ACC_TERRAFORM_PATH to darwin/amd64 compatible Terraform binary can be used as a workaround.")
+			}
+		},
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion221(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_password.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_password.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_password.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_password.min", "min_numeric", "4"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_password.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_password.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_password.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_password.min", "min_numeric", "4"),
+					resource.TestCheckResourceAttrSet("random_password.min", "bcrypt_hash"),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_UpgradeFromVersion3_2_0 verifies behaviour when upgrading state from schema V1 to V3.
+func TestAccResourcePassword_UpgradeFromVersion3_2_0(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion320(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_password.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_password.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_password.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_password.min", "min_numeric", "4"),
+					resource.TestCheckResourceAttrSet("random_password.min", "bcrypt_hash"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_password.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_password.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_password.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_password.min", "min_numeric", "4"),
+					resource.TestCheckResourceAttrSet("random_password.min", "bcrypt_hash"),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourcePassword_UpgradeFromVersion3_3_2 verifies behaviour when upgrading from SDKv2 to the Framework.
+func TestAccResourcePassword_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_password.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_password.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_password.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_password.min", "min_numeric", "4"),
+					resource.TestCheckResourceAttrSet("random_password.min", "bcrypt_hash"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_password.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_password.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_password.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_password.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_password.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_password.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_password.min", "min_numeric", "4"),
+					resource.TestCheckResourceAttrSet("random_password.min", "bcrypt_hash"),
+				),
+			},
+		},
+	})
+}
+
+func TestUpgradePasswordStateV0toV3(t *testing.T) {
+	t.Parallel()
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: passwordSchemaV0(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	upgradePasswordStateV0toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"bcrypt_hash":      tftypes.String,
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"bcrypt_hash":      tftypes.NewValue(tftypes.String, "hash"),
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	var bcryptHash, result string
+
+	diags := resp.State.GetAttribute(context.Background(), path.Root("bcrypt_hash"), &bcryptHash)
+	if diags.HasError() {
+		t.Errorf("error retrieving bcyrpt_hash from state: %s", diags.Errors())
+	}
+
+	diags = resp.State.GetAttribute(context.Background(), path.Root("result"), &result)
+	if diags.HasError() {
+		t.Errorf("error retrieving bcyrpt_hash from state: %s", diags.Errors())
+	}
+
+	err := bcrypt.CompareHashAndPassword([]byte(bcryptHash), []byte(result))
+	if err != nil {
+		t.Errorf("unexpected bcrypt comparison error: %s", err)
+	}
+
+	// rawTransformed allows equality testing to be used by mutating the bcrypt_hash value in the response to a known value.
+	rawTransformed, err := tftypes.Transform(resp.State.Raw, func(path *tftypes.AttributePath, value tftypes.Value) (tftypes.Value, error) {
+		bcryptHashPath := tftypes.NewAttributePath().WithAttributeName("bcrypt_hash")
+
+		if path.Equal(bcryptHashPath) {
+			return tftypes.NewValue(tftypes.String, "hash"), nil
+		}
+		return value, nil
+	})
+	if err != nil {
+		t.Errorf("error transforming actual response: %s", err)
+	}
+
+	resp.State.Raw = rawTransformed
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradePasswordStateV0toV3_NullValues(t *testing.T) {
+	t.Parallel()
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, nil),
+				"lower":            tftypes.NewValue(tftypes.Bool, nil),
+				"min_lower":        tftypes.NewValue(tftypes.Number, nil),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, nil),
+				"min_special":      tftypes.NewValue(tftypes.Number, nil),
+				"min_upper":        tftypes.NewValue(tftypes.Number, nil),
+				"number":           tftypes.NewValue(tftypes.Bool, nil),
+				"override_special": tftypes.NewValue(tftypes.String, nil),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, nil),
+				"upper":            tftypes.NewValue(tftypes.Bool, nil),
+			}),
+			Schema: passwordSchemaV0(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	upgradePasswordStateV0toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"bcrypt_hash":      tftypes.String,
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"bcrypt_hash":      tftypes.NewValue(tftypes.String, "hash"),
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, nil),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	var bcryptHash, result string
+
+	diags := resp.State.GetAttribute(context.Background(), path.Root("bcrypt_hash"), &bcryptHash)
+	if diags.HasError() {
+		t.Errorf("error retrieving bcyrpt_hash from state: %s", diags.Errors())
+	}
+
+	diags = resp.State.GetAttribute(context.Background(), path.Root("result"), &result)
+	if diags.HasError() {
+		t.Errorf("error retrieving bcyrpt_hash from state: %s", diags.Errors())
+	}
+
+	err := bcrypt.CompareHashAndPassword([]byte(bcryptHash), []byte(result))
+	if err != nil {
+		t.Errorf("unexpected bcrypt comparison error: %s", err)
+	}
+
+	// rawTransformed allows equality testing to be used by mutating the bcrypt_hash value in the response to a known value.
+	rawTransformed, err := tftypes.Transform(resp.State.Raw, func(path *tftypes.AttributePath, value tftypes.Value) (tftypes.Value, error) {
+		bcryptHashPath := tftypes.NewAttributePath().WithAttributeName("bcrypt_hash")
+
+		if path.Equal(bcryptHashPath) {
+			return tftypes.NewValue(tftypes.String, "hash"), nil
+		}
+		return value, nil
+	})
+	if err != nil {
+		t.Errorf("error transforming actual response: %s", err)
+	}
+
+	resp.State.Raw = rawTransformed
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradePasswordStateV1toV3(t *testing.T) {
+	t.Parallel()
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+					"bcrypt_hash":      tftypes.String,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+				"bcrypt_hash":      tftypes.NewValue(tftypes.String, "bcrypt_hash"),
+			}),
+			Schema: passwordSchemaV1(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	upgradePasswordStateV1toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+					"bcrypt_hash":      tftypes.String,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+				"bcrypt_hash":      tftypes.NewValue(tftypes.String, "bcrypt_hash"),
+			}),
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradePasswordStateV1toV3_NullValues(t *testing.T) {
+	t.Parallel()
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+					"bcrypt_hash":      tftypes.String,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, nil),
+				"lower":            tftypes.NewValue(tftypes.Bool, nil),
+				"min_lower":        tftypes.NewValue(tftypes.Number, nil),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, nil),
+				"min_special":      tftypes.NewValue(tftypes.Number, nil),
+				"min_upper":        tftypes.NewValue(tftypes.Number, nil),
+				"number":           tftypes.NewValue(tftypes.Bool, nil),
+				"override_special": tftypes.NewValue(tftypes.String, nil),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, nil),
+				"upper":            tftypes.NewValue(tftypes.Bool, nil),
+				"bcrypt_hash":      tftypes.NewValue(tftypes.String, "bcrypt_hash"),
+			}),
+			Schema: passwordSchemaV1(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	upgradePasswordStateV1toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+					"bcrypt_hash":      tftypes.String,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, nil),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+				"bcrypt_hash":      tftypes.NewValue(tftypes.String, "bcrypt_hash"),
+			}),
+			Schema: passwordSchemaV3(),
+		},
+	}
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradePasswordStateV2toV3(t *testing.T) {
+	t.Parallel()
+
+	testCases := map[string]struct {
+		request  res.UpgradeStateRequest
+		expected *res.UpgradeStateResponse
+	}{
+		"valid-hash": {
+			request: res.UpgradeStateRequest{
+				State: &tfsdk.State{
+					Raw: tftypes.NewValue(tftypes.Object{
+						AttributeTypes: map[string]tftypes.Type{
+							"bcrypt_hash":      tftypes.String,
+							"id":               tftypes.String,
+							"keepers":          tftypes.Map{ElementType: tftypes.String},
+							"length":           tftypes.Number,
+							"lower":            tftypes.Bool,
+							"min_lower":        tftypes.Number,
+							"min_numeric":      tftypes.Number,
+							"min_special":      tftypes.Number,
+							"min_upper":        tftypes.Number,
+							"number":           tftypes.Bool,
+							"numeric":          tftypes.Bool,
+							"override_special": tftypes.String,
+							"result":           tftypes.String,
+							"special":          tftypes.Bool,
+							"upper":            tftypes.Bool,
+						},
+					}, map[string]tftypes.Value{
+						"bcrypt_hash":      tftypes.NewValue(tftypes.String, "$2a$10$d9zhEkVg.O1jZ6fEIMRlRuu/vMa0/4UIzeK5joaTBhZJlYiIPhWWa"),
+						"id":               tftypes.NewValue(tftypes.String, "none"),
+						"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+						"length":           tftypes.NewValue(tftypes.Number, 20),
+						"lower":            tftypes.NewValue(tftypes.Bool, true),
+						"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+						"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+						"min_special":      tftypes.NewValue(tftypes.Number, 0),
+						"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+						"number":           tftypes.NewValue(tftypes.Bool, true),
+						"numeric":          tftypes.NewValue(tftypes.Bool, true),
+						"override_special": tftypes.NewValue(tftypes.String, ""),
+						"result":           tftypes.NewValue(tftypes.String, "n:um[a9kO&x!L=9og[EM"),
+						"special":          tftypes.NewValue(tftypes.Bool, true),
+						"upper":            tftypes.NewValue(tftypes.Bool, true),
+					}),
+					Schema: passwordSchemaV2(),
+				},
+			},
+			expected: &res.UpgradeStateResponse{
+				State: tfsdk.State{
+					Raw: tftypes.NewValue(tftypes.Object{
+						AttributeTypes: map[string]tftypes.Type{
+							"bcrypt_hash":      tftypes.String,
+							"id":               tftypes.String,
+							"keepers":          tftypes.Map{ElementType: tftypes.String},
+							"length":           tftypes.Number,
+							"lower":            tftypes.Bool,
+							"min_lower":        tftypes.Number,
+							"min_numeric":      tftypes.Number,
+							"min_special":      tftypes.Number,
+							"min_upper":        tftypes.Number,
+							"number":           tftypes.Bool,
+							"numeric":          tftypes.Bool,
+							"override_special": tftypes.String,
+							"result":           tftypes.String,
+							"special":          tftypes.Bool,
+							"upper":            tftypes.Bool,
+						},
+					}, map[string]tftypes.Value{
+						// The difference checking should compare this actual
+						// value since it should not be updated.
+						"bcrypt_hash":      tftypes.NewValue(tftypes.String, "$2a$10$d9zhEkVg.O1jZ6fEIMRlRuu/vMa0/4UIzeK5joaTBhZJlYiIPhWWa"),
+						"id":               tftypes.NewValue(tftypes.String, "none"),
+						"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+						"length":           tftypes.NewValue(tftypes.Number, 20),
+						"lower":            tftypes.NewValue(tftypes.Bool, true),
+						"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+						"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+						"min_special":      tftypes.NewValue(tftypes.Number, 0),
+						"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+						"number":           tftypes.NewValue(tftypes.Bool, true),
+						"numeric":          tftypes.NewValue(tftypes.Bool, true),
+						"override_special": tftypes.NewValue(tftypes.String, ""),
+						"result":           tftypes.NewValue(tftypes.String, "n:um[a9kO&x!L=9og[EM"),
+						"special":          tftypes.NewValue(tftypes.Bool, true),
+						"upper":            tftypes.NewValue(tftypes.Bool, true),
+					}),
+					Schema: passwordSchemaV3(),
+				},
+			},
+		},
+		"invalid-hash": {
+			request: res.UpgradeStateRequest{
+				State: &tfsdk.State{
+					Raw: tftypes.NewValue(tftypes.Object{
+						AttributeTypes: map[string]tftypes.Type{
+							"bcrypt_hash":      tftypes.String,
+							"id":               tftypes.String,
+							"keepers":          tftypes.Map{ElementType: tftypes.String},
+							"length":           tftypes.Number,
+							"lower":            tftypes.Bool,
+							"min_lower":        tftypes.Number,
+							"min_numeric":      tftypes.Number,
+							"min_special":      tftypes.Number,
+							"min_upper":        tftypes.Number,
+							"number":           tftypes.Bool,
+							"numeric":          tftypes.Bool,
+							"override_special": tftypes.String,
+							"result":           tftypes.String,
+							"special":          tftypes.Bool,
+							"upper":            tftypes.Bool,
+						},
+					}, map[string]tftypes.Value{
+						"bcrypt_hash":      tftypes.NewValue(tftypes.String, "$2a$10$bPOZGBpGe4XIgbpVaWNya.dz/HsU1GDLjuEposH2wf.vUO5rA1wXe"),
+						"id":               tftypes.NewValue(tftypes.String, "none"),
+						"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+						"length":           tftypes.NewValue(tftypes.Number, 20),
+						"lower":            tftypes.NewValue(tftypes.Bool, true),
+						"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+						"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+						"min_special":      tftypes.NewValue(tftypes.Number, 0),
+						"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+						"number":           tftypes.NewValue(tftypes.Bool, true),
+						"numeric":          tftypes.NewValue(tftypes.Bool, true),
+						"override_special": tftypes.NewValue(tftypes.String, ""),
+						"result":           tftypes.NewValue(tftypes.String, "$7r>NiN4Z%uAxpU]:DuB"),
+						"special":          tftypes.NewValue(tftypes.Bool, true),
+						"upper":            tftypes.NewValue(tftypes.Bool, true),
+					}),
+					Schema: passwordSchemaV2(),
+				},
+			},
+			expected: &res.UpgradeStateResponse{
+				State: tfsdk.State{
+					Raw: tftypes.NewValue(tftypes.Object{
+						AttributeTypes: map[string]tftypes.Type{
+							"bcrypt_hash":      tftypes.String,
+							"id":               tftypes.String,
+							"keepers":          tftypes.Map{ElementType: tftypes.String},
+							"length":           tftypes.Number,
+							"lower":            tftypes.Bool,
+							"min_lower":        tftypes.Number,
+							"min_numeric":      tftypes.Number,
+							"min_special":      tftypes.Number,
+							"min_upper":        tftypes.Number,
+							"number":           tftypes.Bool,
+							"numeric":          tftypes.Bool,
+							"override_special": tftypes.String,
+							"result":           tftypes.String,
+							"special":          tftypes.Bool,
+							"upper":            tftypes.Bool,
+						},
+					}, map[string]tftypes.Value{
+						// bcrypt_hash is randomly generated, so the difference checking
+						// will ignore this value.
+						"bcrypt_hash":      tftypes.NewValue(tftypes.String, nil),
+						"id":               tftypes.NewValue(tftypes.String, "none"),
+						"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+						"length":           tftypes.NewValue(tftypes.Number, 20),
+						"lower":            tftypes.NewValue(tftypes.Bool, true),
+						"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+						"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+						"min_special":      tftypes.NewValue(tftypes.Number, 0),
+						"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+						"number":           tftypes.NewValue(tftypes.Bool, true),
+						"numeric":          tftypes.NewValue(tftypes.Bool, true),
+						"override_special": tftypes.NewValue(tftypes.String, ""),
+						"result":           tftypes.NewValue(tftypes.String, "$7r>NiN4Z%uAxpU]:DuB"),
+						"special":          tftypes.NewValue(tftypes.Bool, true),
+						"upper":            tftypes.NewValue(tftypes.Bool, true),
+					}),
+					Schema: passwordSchemaV3(),
+				},
+			},
+		},
+		"valid-hash-null-values": {
+			request: res.UpgradeStateRequest{
+				State: &tfsdk.State{
+					Raw: tftypes.NewValue(tftypes.Object{
+						AttributeTypes: map[string]tftypes.Type{
+							"bcrypt_hash":      tftypes.String,
+							"id":               tftypes.String,
+							"keepers":          tftypes.Map{ElementType: tftypes.String},
+							"length":           tftypes.Number,
+							"lower":            tftypes.Bool,
+							"min_lower":        tftypes.Number,
+							"min_numeric":      tftypes.Number,
+							"min_special":      tftypes.Number,
+							"min_upper":        tftypes.Number,
+							"number":           tftypes.Bool,
+							"numeric":          tftypes.Bool,
+							"override_special": tftypes.String,
+							"result":           tftypes.String,
+							"special":          tftypes.Bool,
+							"upper":            tftypes.Bool,
+						},
+					}, map[string]tftypes.Value{
+						"bcrypt_hash":      tftypes.NewValue(tftypes.String, "$2a$10$d9zhEkVg.O1jZ6fEIMRlRuu/vMa0/4UIzeK5joaTBhZJlYiIPhWWa"),
+						"id":               tftypes.NewValue(tftypes.String, "none"),
+						"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+						"length":           tftypes.NewValue(tftypes.Number, nil),
+						"lower":            tftypes.NewValue(tftypes.Bool, nil),
+						"min_lower":        tftypes.NewValue(tftypes.Number, nil),
+						"min_numeric":      tftypes.NewValue(tftypes.Number, nil),
+						"min_special":      tftypes.NewValue(tftypes.Number, nil),
+						"min_upper":        tftypes.NewValue(tftypes.Number, nil),
+						"number":           tftypes.NewValue(tftypes.Bool, nil),
+						"numeric":          tftypes.NewValue(tftypes.Bool, nil),
+						"override_special": tftypes.NewValue(tftypes.String, ""),
+						"result":           tftypes.NewValue(tftypes.String, "n:um[a9kO&x!L=9og[EM"),
+						"special":          tftypes.NewValue(tftypes.Bool, nil),
+						"upper":            tftypes.NewValue(tftypes.Bool, nil),
+					}),
+					Schema: passwordSchemaV2(),
+				},
+			},
+			expected: &res.UpgradeStateResponse{
+				State: tfsdk.State{
+					Raw: tftypes.NewValue(tftypes.Object{
+						AttributeTypes: map[string]tftypes.Type{
+							"bcrypt_hash":      tftypes.String,
+							"id":               tftypes.String,
+							"keepers":          tftypes.Map{ElementType: tftypes.String},
+							"length":           tftypes.Number,
+							"lower":            tftypes.Bool,
+							"min_lower":        tftypes.Number,
+							"min_numeric":      tftypes.Number,
+							"min_special":      tftypes.Number,
+							"min_upper":        tftypes.Number,
+							"number":           tftypes.Bool,
+							"numeric":          tftypes.Bool,
+							"override_special": tftypes.String,
+							"result":           tftypes.String,
+							"special":          tftypes.Bool,
+							"upper":            tftypes.Bool,
+						},
+					}, map[string]tftypes.Value{
+						// The difference checking should compare this actual
+						// value since it should not be updated.
+						"bcrypt_hash":      tftypes.NewValue(tftypes.String, "$2a$10$d9zhEkVg.O1jZ6fEIMRlRuu/vMa0/4UIzeK5joaTBhZJlYiIPhWWa"),
+						"id":               tftypes.NewValue(tftypes.String, "none"),
+						"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+						"length":           tftypes.NewValue(tftypes.Number, 20),
+						"lower":            tftypes.NewValue(tftypes.Bool, true),
+						"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+						"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+						"min_special":      tftypes.NewValue(tftypes.Number, 0),
+						"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+						"number":           tftypes.NewValue(tftypes.Bool, true),
+						"numeric":          tftypes.NewValue(tftypes.Bool, true),
+						"override_special": tftypes.NewValue(tftypes.String, ""),
+						"result":           tftypes.NewValue(tftypes.String, "n:um[a9kO&x!L=9og[EM"),
+						"special":          tftypes.NewValue(tftypes.Bool, true),
+						"upper":            tftypes.NewValue(tftypes.Bool, true),
+					}),
+					Schema: passwordSchemaV3(),
+				},
+			},
+		},
+	}
+
+	for name, testCase := range testCases {
+		name, testCase := name, testCase
+
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+
+			got := res.UpgradeStateResponse{
+				State: tfsdk.State{
+					Schema: testCase.expected.State.Schema,
+				},
+			}
+
+			upgradePasswordStateV2toV3(context.Background(), testCase.request, &got)
+
+			// Since bcrypt_hash is generated, this test is very involved to
+			// ensure the test case is set up properly and the generated
+			// value is removed to prevent false positive differences.
+			var err error
+			var requestBcryptHash, requestResult, expectedBcryptHash, gotBcryptHash, gotResult string
+
+			bcryptHashPath := tftypes.NewAttributePath().WithAttributeName("bcrypt_hash")
+			resultPath := tftypes.NewAttributePath().WithAttributeName("result")
+
+			requestBcryptHashValue, err := testTftypesValueAtPath(testCase.request.State.Raw, bcryptHashPath)
+
+			if err != nil {
+				t.Fatalf("unexpected error getting request bcrypt_hash value: %s", err)
+			}
+
+			if err := requestBcryptHashValue.As(&requestBcryptHash); err != nil {
+				t.Fatalf("unexpected error converting request bcrypt_hash to string: %s", err)
+			}
+
+			requestResultValue, err := testTftypesValueAtPath(testCase.request.State.Raw, resultPath)
+
+			if err != nil {
+				t.Fatalf("unexpected error getting request result value: %s", err)
+			}
+
+			if err := requestResultValue.As(&requestResult); err != nil {
+				t.Fatalf("unexpected error converting request result to string: %s", err)
+			}
+
+			expectedBcryptHashValue, err := testTftypesValueAtPath(testCase.expected.State.Raw, bcryptHashPath)
+
+			if err != nil {
+				t.Fatalf("unexpected error getting expected bcrypt_hash value: %s", err)
+			}
+
+			if err := expectedBcryptHashValue.As(&expectedBcryptHash); err != nil {
+				t.Fatalf("unexpected error converting expected bcrypt_hash to string: %s", err)
+			}
+
+			gotBcryptHashValue, err := testTftypesValueAtPath(got.State.Raw, bcryptHashPath)
+
+			if err != nil {
+				t.Fatalf("unexpected error getting got bcrypt_hash value: %s", err)
+			}
+
+			if err := gotBcryptHashValue.As(&gotBcryptHash); err != nil {
+				t.Fatalf("unexpected error converting got bcrypt_hash to string: %s", err)
+			}
+
+			gotResultValue, err := testTftypesValueAtPath(got.State.Raw, resultPath)
+
+			if err != nil {
+				t.Fatalf("unexpected error getting got result value: %s", err)
+			}
+
+			if err := gotResultValue.As(&gotResult); err != nil {
+				t.Fatalf("unexpected error converting got result to string: %s", err)
+			}
+
+			err = bcrypt.CompareHashAndPassword([]byte(requestBcryptHash), []byte(requestResult))
+
+			// If the request bcrypt_hash was valid, it should be in expected
+			// and got. Otherwise, it should be regenerated which will be a
+			// random value which must be stripped to prevent false positives.
+			if err == nil {
+				// Ensure the test case is valid.
+				if !requestBcryptHashValue.Equal(expectedBcryptHashValue) {
+					t.Fatal("expected request bcrypt_hash in expected")
+				}
+
+				// Ensure the request bcrypt_hash was not modified.
+				if !requestBcryptHashValue.Equal(gotBcryptHashValue) {
+					t.Fatal("expected request bcrypt_hash in got")
+				}
+			} else {
+				// If we got a different error than mismatched hash, then the
+				// test case might not be valid.
+				if !errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
+					t.Fatalf("unexpected request bcrypt_hash error: %s", err)
+				}
+
+				// Ensure the test case has null values on both sides as a
+				// regenerated bcrypt_hash cannot be equality compared.
+				if !expectedBcryptHashValue.IsNull() {
+					t.Fatal("expected null bcrypt_hash in expected")
+				}
+
+				// Prevent differences from the got bcrypt_path being randomly
+				// generated.
+				got.State.Raw, err = tftypes.Transform(
+					got.State.Raw,
+					func(path *tftypes.AttributePath, value tftypes.Value) (tftypes.Value, error) {
+						// Purposefully set bcrypt_hash value to nil.
+						if path.Equal(bcryptHashPath) {
+							return tftypes.NewValue(tftypes.String, nil), nil
+						}
+
+						return value, nil
+					},
+				)
+
+				if err != nil {
+					t.Fatalf("unexpected error transforming got: %s", err)
+				}
+			}
+
+			// The got bcrypt_hash should always be valid.
+			if err := bcrypt.CompareHashAndPassword([]byte(gotBcryptHash), []byte(gotResult)); err != nil {
+				t.Errorf("unexpected error comparing got bcrypt_hash and result: %s", err)
+			}
+
+			// Ensure all state values are checked.
+			if diff := cmp.Diff(*testCase.expected, got); diff != "" {
+				t.Errorf("unexpected difference: %s", diff)
+			}
+		})
+	}
+}
+
+func TestAccResourcePassword_NumberNumericErrors(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_password" "number_numeric_differ" {
+  							length = 1
+							number = false
+  							numeric = true
+						}`,
+				ExpectError: regexp.MustCompile(`.*Number and numeric are both configured with different values`),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_EmptyMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_NullMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_NullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_NullValues(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_Value(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Keep_Values(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePassword_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_password" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_password.test", "result", &result2),
+					testCheckAttributeValuesDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_password.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func testBcryptHashInvalid(hash *string, password *string) resource.TestCheckFunc {
+	return func(_ *terraform.State) error {
+		if hash == nil || *hash == "" {
+			return fmt.Errorf("expected hash value")
+		}
+
+		if password == nil || *password == "" {
+			return fmt.Errorf("expected password value")
+		}
+
+		err := bcrypt.CompareHashAndPassword([]byte(*hash), []byte(*password))
+
+		if !errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
+			return fmt.Errorf("unexpected error: %s", err)
+		}
+
+		return nil
+	}
+}
+
+func testBcryptHashValid(hash *string, password *string) resource.TestCheckFunc {
+	return func(_ *terraform.State) error {
+		if hash == nil || *hash == "" {
+			return fmt.Errorf("expected hash value")
+		}
+
+		if password == nil || *password == "" {
+			return fmt.Errorf("expected password value")
+		}
+
+		return bcrypt.CompareHashAndPassword([]byte(*hash), []byte(*password))
+	}
+}
+
+func composeImportStateCheck(fs ...resource.ImportStateCheckFunc) resource.ImportStateCheckFunc {
+	return func(s []*terraform.InstanceState) error {
+		for i, f := range fs {
+			if err := f(s); err != nil {
+				return fmt.Errorf("check %d/%d error: %s", i+1, len(fs), err)
+			}
+		}
+
+		return nil
+	}
+}
+
+//nolint:unparam
+func testExtractResourceAttrInstanceState(attributeName string, attributeValue *string) resource.ImportStateCheckFunc {
+	return func(is []*terraform.InstanceState) error {
+		if len(is) != 1 {
+			return fmt.Errorf("unexpected number of instance states: %d", len(is))
+		}
+
+		s := is[0]
+
+		attrValue, ok := s.Attributes[attributeName]
+		if !ok {
+			return fmt.Errorf("attribute %s not found in instance state", attributeName)
+		}
+
+		*attributeValue = attrValue
+
+		return nil
+	}
+}
+
+func testCheckNoResourceAttrInstanceState(attributeName string) resource.ImportStateCheckFunc {
+	return func(is []*terraform.InstanceState) error {
+		if len(is) != 1 {
+			return fmt.Errorf("unexpected number of instance states: %d", len(is))
+		}
+
+		s := is[0]
+
+		_, ok := s.Attributes[attributeName]
+		if ok {
+			return fmt.Errorf("attribute %s found in instance state", attributeName)
+		}
+
+		return nil
+	}
+}
+
+func testCheckResourceAttrInstanceState(attributeName string) resource.ImportStateCheckFunc {
+	return func(is []*terraform.InstanceState) error {
+		if len(is) != 1 {
+			return fmt.Errorf("unexpected number of instance states: %d", len(is))
+		}
+
+		s := is[0]
+
+		_, ok := s.Attributes[attributeName]
+		if !ok {
+			return fmt.Errorf("attribute %s not found in instance state", attributeName)
+		}
+
+		return nil
+	}
+}
diff --git a/v3.6.0/internal/provider/resource_pet.go b/v3.6.0/internal/provider/resource_pet.go
new file mode 100644
index 0000000..e6bf758
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_pet.go
@@ -0,0 +1,160 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	petname "github.com/dustinkirkland/golang-petname"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+)
+
+var _ resource.Resource = (*petResource)(nil)
+
+func NewPetResource() resource.Resource {
+	return &petResource{}
+}
+
+type petResource struct{}
+
+func (r *petResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_pet"
+}
+
+func (r *petResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Description: "The resource `random_pet` generates random pet names that are intended to be used as " +
+			"unique identifiers for other resources.\n" +
+			"\n" +
+			"This resource can be used in conjunction with resources that have the `create_before_destroy` " +
+			"lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old " +
+			"and new resources exist concurrently.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+			"length": schema.Int64Attribute{
+				Description: "The length (in words) of the pet name. Defaults to 2",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(2),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+			"prefix": schema.StringAttribute{
+				Description: "A string to prefix the name with.",
+				Optional:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"separator": schema.StringAttribute{
+				Description: "The character to separate words in the pet name. Defaults to \"-\"",
+				Optional:    true,
+				Computed:    true,
+				Default:     stringdefault.StaticString("-"),
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"id": schema.StringAttribute{
+				Description: "The random pet name.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func (r *petResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	// This is necessary to ensure each call to petname is properly randomised:
+	// the library uses `rand.Intn()` and does NOT seed `rand.Seed()` by default,
+	// so this call takes care of that.
+	petname.NonDeterministicMode()
+
+	var plan petModelV0
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	length := plan.Length.ValueInt64()
+	separator := plan.Separator.ValueString()
+	prefix := plan.Prefix.ValueString()
+
+	pet := strings.ToLower(petname.Generate(int(length), separator))
+
+	pn := petModelV0{
+		Keepers:   plan.Keepers,
+		Length:    types.Int64Value(length),
+		Separator: types.StringValue(separator),
+	}
+
+	if prefix != "" {
+		pet = fmt.Sprintf("%s%s%s", prefix, separator, pet)
+		pn.Prefix = types.StringValue(prefix)
+	} else {
+		pn.Prefix = types.StringNull()
+	}
+
+	pn.ID = types.StringValue(pet)
+
+	diags = resp.State.Set(ctx, pn)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *petResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *petResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model petModelV0
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *petResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+}
+
+type petModelV0 struct {
+	ID        types.String `tfsdk:"id"`
+	Keepers   types.Map    `tfsdk:"keepers"`
+	Length    types.Int64  `tfsdk:"length"`
+	Prefix    types.String `tfsdk:"prefix"`
+	Separator types.String `tfsdk:"separator"`
+}
diff --git a/v3.6.0/internal/provider/resource_pet_test.go b/v3.6.0/internal/provider/resource_pet_test.go
new file mode 100644
index 0000000..f0ac15f
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_pet_test.go
@@ -0,0 +1,825 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccResourcePet(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_pet" "pet_1" {
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_pet.pet_1", "id", testCheckPetLen("-", 2)),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_EmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_NullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_NullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_NullValues(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_Value(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Keep_Values(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_pet.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_pet.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Length(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_pet" "pet_1" {
+  							length = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_pet.pet_1", "id", testCheckPetLen("-", 4)),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Prefix(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_pet" "pet_1" {
+  							prefix = "consul"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_pet.pet_1", "id", testCheckPetLen("-", 3)),
+					resource.TestMatchResourceAttr("random_pet.pet_1", "id", regexp.MustCompile("^consul-")),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_Separator(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_pet" "pet_1" {
+  							length = 3
+  							separator = "_"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_pet.pet_1", "id", testCheckPetLen("_", 3)),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourcePet_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_pet" "pet_1" {
+  							prefix = "consul"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_pet.pet_1", "id", testCheckPetLen("-", 3)),
+					resource.TestMatchResourceAttr("random_pet.pet_1", "id", regexp.MustCompile("^consul-")),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "pet_1" {
+  							prefix = "consul"
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_pet" "pet_1" {
+  							prefix = "consul"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_pet.pet_1", "id", testCheckPetLen("-", 3)),
+					resource.TestMatchResourceAttr("random_pet.pet_1", "id", regexp.MustCompile("^consul-")),
+				),
+			},
+		},
+	})
+}
+
+func testCheckPetLen(separator string, expectedLen int) func(input string) error {
+	return func(input string) error {
+		petNameParts := strings.Split(input, separator)
+
+		if len(petNameParts) != expectedLen {
+			return fmt.Errorf("expected length %d, actual length %d", expectedLen, len(petNameParts))
+		}
+
+		return nil
+	}
+}
diff --git a/v3.6.0/internal/provider/resource_shuffle.go b/v3.6.0/internal/provider/resource_shuffle.go
new file mode 100644
index 0000000..60bf124
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_shuffle.go
@@ -0,0 +1,194 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+	"github.com/terraform-providers/terraform-provider-random/internal/random"
+)
+
+var _ resource.Resource = (*shuffleResource)(nil)
+
+func NewShuffleResource() resource.Resource {
+	return &shuffleResource{}
+}
+
+type shuffleResource struct{}
+
+func (r *shuffleResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_shuffle"
+}
+
+func (r *shuffleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Description: "The resource `random_shuffle` generates a random permutation of a list of strings " +
+			"given as an argument.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+			"seed": schema.StringAttribute{
+				Description: "Arbitrary string with which to seed the random number generator, in order to " +
+					"produce less-volatile permutations of the list.\n" +
+					"\n" +
+					"**Important:** Even with an identical seed, it is not guaranteed that the same permutation " +
+					"will be produced across different versions of Terraform. This argument causes the " +
+					"result to be *less volatile*, but not fixed for all time.",
+				Optional: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"input": schema.ListAttribute{
+				Description: "The list of strings to shuffle.",
+				ElementType: types.StringType,
+				Required:    true,
+				PlanModifiers: []planmodifier.List{
+					listplanmodifier.RequiresReplace(),
+				},
+			},
+			"result_count": schema.Int64Attribute{
+				Description: "The number of results to return. Defaults to the number of items in the " +
+					"`input` list. If fewer items are requested, some elements will be excluded from the " +
+					"result. If more items are requested, items will be repeated in the result but not more " +
+					"frequently than the number of items in the input list.",
+				Optional: true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+			"result": schema.ListAttribute{
+				Description: "Random permutation of the list of strings given in `input`.",
+				ElementType: types.StringType,
+				Computed:    true,
+				PlanModifiers: []planmodifier.List{
+					listplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"id": schema.StringAttribute{
+				Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func (r *shuffleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan shuffleModelV0
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	input := plan.Input
+	seed := plan.Seed.ValueString()
+	resultCount := plan.ResultCount.ValueInt64()
+
+	if resultCount == 0 {
+		resultCount = int64(len(input.Elements()))
+	}
+
+	result := make([]attr.Value, 0, resultCount)
+
+	if len(input.Elements()) > 0 {
+		rand := random.NewRand(seed)
+
+		// Keep producing permutations until we fill our result
+	Batches:
+		for {
+			perm := rand.Perm(len(input.Elements()))
+
+			for _, i := range perm {
+				result = append(result, input.Elements()[i])
+
+				if int64(len(result)) >= resultCount {
+					break Batches
+				}
+			}
+		}
+	}
+
+	res, diags := types.ListValue(types.StringType, result)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	s := shuffleModelV0{
+		ID:      types.StringValue("-"),
+		Keepers: plan.Keepers,
+		Input:   plan.Input,
+		Result:  res,
+	}
+
+	if plan.Seed.IsNull() {
+		s.Seed = types.StringNull()
+	} else {
+		s.Seed = types.StringValue(seed)
+	}
+
+	if plan.ResultCount.IsNull() {
+		s.ResultCount = types.Int64Null()
+	} else {
+		s.ResultCount = types.Int64Value(resultCount)
+	}
+
+	diags = resp.State.Set(ctx, s)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *shuffleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *shuffleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model shuffleModelV0
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *shuffleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+}
+
+type shuffleModelV0 struct {
+	ID          types.String `tfsdk:"id"`
+	Keepers     types.Map    `tfsdk:"keepers"`
+	Seed        types.String `tfsdk:"seed"`
+	Input       types.List   `tfsdk:"input"`
+	ResultCount types.Int64  `tfsdk:"result_count"`
+	Result      types.List   `tfsdk:"result"`
+}
diff --git a/v3.6.0/internal/provider/resource_shuffle_test.go b/v3.6.0/internal/provider/resource_shuffle_test.go
new file mode 100644
index 0000000..450685a
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_shuffle_test.go
@@ -0,0 +1,994 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/hashicorp/terraform-plugin-testing/terraform"
+)
+
+// These results are current as of Go 1.6. The Go
+// "rand" package does not guarantee that the random
+// number generator will generate the same results
+// forever, but the maintainers endeavor not to change
+// it gratuitously.
+// These tests allow us to detect such changes and
+// document them when they arise, but the docs for this
+// resource specifically warn that results are not
+// guaranteed consistent across Terraform releases.
+func TestAccResourceShuffle(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_shuffle" "default_length" {
+    						input = ["a", "b", "c", "d", "e"]
+    						seed = "-"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.default_length", "result.#", testAccResourceShuffleCheckLength("5")),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.0", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.1", "c"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.2", "b"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.3", "e"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.4", "d"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_EmptyMap(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_NullMap(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_NullValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_NullValues(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_Value(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Keep_Values(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsEqual(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var result1, result2 []string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result1),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "test" {
+					input = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttrList("random_shuffle.test", "result", &result2),
+					testCheckAttributeValueListsDiffer(&result1, &result2),
+					resource.TestCheckResourceAttr("random_shuffle.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Shorter(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_shuffle" "shorter_length" {
+    						input = ["a", "b", "c", "d", "e"]
+    						seed = "-"
+    						result_count = 3
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.shorter_length", "result.#", testAccResourceShuffleCheckLength("3")),
+					resource.TestCheckResourceAttr("random_shuffle.shorter_length", "result.0", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.shorter_length", "result.1", "c"),
+					resource.TestCheckResourceAttr("random_shuffle.shorter_length", "result.2", "b"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Longer(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_shuffle" "longer_length" {
+    						input = ["a", "b", "c", "d", "e"]
+    						seed = "-"
+    						result_count = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.longer_length", "result.#", testAccResourceShuffleCheckLength("12")),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.0", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.1", "c"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.2", "b"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.3", "e"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.4", "d"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.5", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.6", "e"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.7", "d"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.8", "c"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.9", "b"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.10", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.longer_length", "result.11", "b"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_Empty(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_shuffle" "empty_length" {
+    						input = []
+    						seed = "-"
+    						result_count = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.empty_length", "result.#", testAccResourceShuffleCheckLength("0")),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_One(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_shuffle" "one_length" {
+    						input = ["a"]
+    						seed = "-"
+    						result_count = 1
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.one_length", "result.#", testAccResourceShuffleCheckLength("1")),
+					resource.TestCheckResourceAttr("random_shuffle.one_length", "result.0", "a"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceShuffle_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_shuffle" "default_length" {
+    						input = ["a", "b", "c", "d", "e"]
+    						seed = "-"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.default_length", "result.#", testAccResourceShuffleCheckLength("5")),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.0", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.1", "c"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.2", "b"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.3", "e"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.4", "d"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "default_length" {
+    						input = ["a", "b", "c", "d", "e"]
+    						seed = "-"
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_shuffle" "default_length" {
+    						input = ["a", "b", "c", "d", "e"]
+    						seed = "-"
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_shuffle.default_length", "result.#", testAccResourceShuffleCheckLength("5")),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.0", "a"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.1", "c"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.2", "b"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.3", "e"),
+					resource.TestCheckResourceAttr("random_shuffle.default_length", "result.4", "d"),
+				),
+			},
+		},
+	})
+}
+
+func testAccResourceShuffleCheckLength(expectedLength string) func(input string) error {
+	return func(input string) error {
+		if input != expectedLength {
+			return fmt.Errorf("got length %s; expected length %s", input, expectedLength)
+		}
+
+		return nil
+	}
+}
+
+//nolint:unparam
+func testExtractResourceAttrList(resourceName string, attributeName string, attributeValue *[]string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		rs, ok := s.RootModule().Resources[resourceName]
+
+		if !ok {
+			return fmt.Errorf("resource name %s not found in state", resourceName)
+		}
+
+		elementCountAttr := attributeName + ".#"
+
+		elementCountValue, ok := rs.Primary.Attributes[elementCountAttr]
+
+		if !ok {
+			return fmt.Errorf("attribute %s not found in resource %s state", elementCountAttr, resourceName)
+		}
+
+		elementCount, err := strconv.Atoi(elementCountValue)
+
+		if err != nil {
+			return fmt.Errorf("attribute %s not integer: %w", elementCountAttr, err)
+		}
+
+		listValue := make([]string, elementCount)
+
+		for i := 0; i < elementCount; i++ {
+			attr := attributeName + "." + strconv.Itoa(i)
+
+			attrValue, ok := rs.Primary.Attributes[attr]
+
+			if !ok {
+				return fmt.Errorf("attribute %s not found in resource %s state", attr, resourceName)
+			}
+
+			listValue[i] = attrValue
+		}
+
+		*attributeValue = listValue
+
+		return nil
+	}
+}
+
+func testCheckAttributeValueListsDiffer(i *[]string, j *[]string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		if reflect.DeepEqual(i, j) {
+			return fmt.Errorf("attribute values are the same")
+		}
+
+		return nil
+	}
+}
+
+func testCheckAttributeValueListsEqual(i *[]string, j *[]string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		if !reflect.DeepEqual(i, j) {
+			return fmt.Errorf("attribute values are different, got %v and %v", i, j)
+		}
+
+		return nil
+	}
+}
diff --git a/v3.6.0/internal/provider/resource_string.go b/v3.6.0/internal/provider/resource_string.go
new file mode 100644
index 0000000..91182ff
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_string.go
@@ -0,0 +1,730 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/diagnostics"
+	boolplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/bool"
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+	stringplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/string"
+	"github.com/terraform-providers/terraform-provider-random/internal/random"
+)
+
+var (
+	_ resource.Resource                 = (*stringResource)(nil)
+	_ resource.ResourceWithImportState  = (*stringResource)(nil)
+	_ resource.ResourceWithUpgradeState = (*stringResource)(nil)
+)
+
+func NewStringResource() resource.Resource {
+	return &stringResource{}
+}
+
+type stringResource struct{}
+
+func (r *stringResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_string"
+}
+
+func (r *stringResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = stringSchemaV3()
+}
+
+func (r *stringResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan stringModelV3
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	params := random.StringParams{
+		Length:          plan.Length.ValueInt64(),
+		Upper:           plan.Upper.ValueBool(),
+		MinUpper:        plan.MinUpper.ValueInt64(),
+		Lower:           plan.Lower.ValueBool(),
+		MinLower:        plan.MinLower.ValueInt64(),
+		Numeric:         plan.Numeric.ValueBool(),
+		MinNumeric:      plan.MinNumeric.ValueInt64(),
+		Special:         plan.Special.ValueBool(),
+		MinSpecial:      plan.MinSpecial.ValueInt64(),
+		OverrideSpecial: plan.OverrideSpecial.ValueString(),
+	}
+
+	result, err := random.CreateString(params)
+	if err != nil {
+		resp.Diagnostics.Append(diagnostics.RandomReadError(err.Error())...)
+		return
+	}
+
+	plan.ID = types.StringValue(string(result))
+	plan.Result = types.StringValue(string(result))
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *stringResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *stringResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model stringModelV3
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *stringResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+}
+
+func (r *stringResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	id := req.ID
+
+	state := stringModelV3{
+		ID:              types.StringValue(id),
+		Result:          types.StringValue(id),
+		Length:          types.Int64Value(int64(len(id))),
+		Special:         types.BoolValue(true),
+		Upper:           types.BoolValue(true),
+		Lower:           types.BoolValue(true),
+		Number:          types.BoolValue(true),
+		Numeric:         types.BoolValue(true),
+		MinSpecial:      types.Int64Value(0),
+		MinUpper:        types.Int64Value(0),
+		MinLower:        types.Int64Value(0),
+		MinNumeric:      types.Int64Value(0),
+		OverrideSpecial: types.StringNull(),
+		Keepers:         types.MapNull(types.StringType),
+	}
+
+	diags := resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+func (r *stringResource) UpgradeState(context.Context) map[int64]resource.StateUpgrader {
+	schemaV1 := stringSchemaV1()
+	schemaV2 := stringSchemaV2()
+
+	return map[int64]resource.StateUpgrader{
+		1: {
+			PriorSchema:   &schemaV1,
+			StateUpgrader: upgradeStringStateV1toV3,
+		},
+		2: {
+			PriorSchema:   &schemaV2,
+			StateUpgrader: upgradeStringStateV2toV3,
+		},
+	}
+}
+
+func upgradeStringStateV1toV3(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
+	type modelV1 struct {
+		ID              types.String `tfsdk:"id"`
+		Keepers         types.Map    `tfsdk:"keepers"`
+		Length          types.Int64  `tfsdk:"length"`
+		Special         types.Bool   `tfsdk:"special"`
+		Upper           types.Bool   `tfsdk:"upper"`
+		Lower           types.Bool   `tfsdk:"lower"`
+		Number          types.Bool   `tfsdk:"number"`
+		MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+		MinUpper        types.Int64  `tfsdk:"min_upper"`
+		MinLower        types.Int64  `tfsdk:"min_lower"`
+		MinSpecial      types.Int64  `tfsdk:"min_special"`
+		OverrideSpecial types.String `tfsdk:"override_special"`
+		Result          types.String `tfsdk:"result"`
+	}
+
+	var stringDataV1 modelV1
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &stringDataV1)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Setting fields that can contain null to non-null to prevent forced replacement.
+	// This can occur in cases where import has been used in provider versions v3.3.1 and earlier.
+	// If import has been used with v3.3.1, for instance then length, lower, number, special, upper,
+	// min_lower, min_numeric, min_special and min_upper attributes will all be null in state.
+	length := stringDataV1.Length
+
+	if length.IsNull() {
+		length = types.Int64Value(int64(len(stringDataV1.Result.ValueString())))
+	}
+
+	minNumeric := stringDataV1.MinNumeric
+
+	if minNumeric.IsNull() {
+		minNumeric = types.Int64Value(0)
+	}
+
+	minUpper := stringDataV1.MinUpper
+
+	if minUpper.IsNull() {
+		minUpper = types.Int64Value(0)
+	}
+
+	minLower := stringDataV1.MinLower
+
+	if minLower.IsNull() {
+		minLower = types.Int64Value(0)
+	}
+
+	minSpecial := stringDataV1.MinSpecial
+
+	if minSpecial.IsNull() {
+		minSpecial = types.Int64Value(0)
+	}
+
+	special := stringDataV1.Special
+
+	if special.IsNull() {
+		special = types.BoolValue(true)
+	}
+
+	upper := stringDataV1.Upper
+
+	if upper.IsNull() {
+		upper = types.BoolValue(true)
+	}
+
+	lower := stringDataV1.Lower
+
+	if lower.IsNull() {
+		lower = types.BoolValue(true)
+	}
+
+	number := stringDataV1.Number
+
+	if number.IsNull() {
+		number = types.BoolValue(true)
+	}
+
+	stringDataV3 := stringModelV3{
+		Keepers:         stringDataV1.Keepers,
+		Length:          length,
+		Special:         special,
+		Upper:           upper,
+		Lower:           lower,
+		Number:          number,
+		Numeric:         number,
+		MinNumeric:      minNumeric,
+		MinUpper:        minUpper,
+		MinLower:        minLower,
+		MinSpecial:      minSpecial,
+		OverrideSpecial: stringDataV1.OverrideSpecial,
+		Result:          stringDataV1.Result,
+		ID:              stringDataV1.ID,
+	}
+
+	diags := resp.State.Set(ctx, stringDataV3)
+	resp.Diagnostics.Append(diags...)
+}
+
+func upgradeStringStateV2toV3(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
+	type modelV2 struct {
+		ID              types.String `tfsdk:"id"`
+		Keepers         types.Map    `tfsdk:"keepers"`
+		Length          types.Int64  `tfsdk:"length"`
+		Special         types.Bool   `tfsdk:"special"`
+		Upper           types.Bool   `tfsdk:"upper"`
+		Lower           types.Bool   `tfsdk:"lower"`
+		Number          types.Bool   `tfsdk:"number"`
+		Numeric         types.Bool   `tfsdk:"numeric"`
+		MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+		MinUpper        types.Int64  `tfsdk:"min_upper"`
+		MinLower        types.Int64  `tfsdk:"min_lower"`
+		MinSpecial      types.Int64  `tfsdk:"min_special"`
+		OverrideSpecial types.String `tfsdk:"override_special"`
+		Result          types.String `tfsdk:"result"`
+	}
+
+	var stringDataV2 modelV2
+
+	resp.Diagnostics.Append(req.State.Get(ctx, &stringDataV2)...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Setting fields that can contain null to non-null to prevent forced replacement.
+	// This can occur in cases where import has been used in provider versions v3.3.1 and earlier.
+	// If import has been used with v3.3.1, for instance then length, lower, number, special, upper,
+	// min_lower, min_numeric, min_special and min_upper attributes will all be null in state.
+	length := stringDataV2.Length
+
+	if length.IsNull() {
+		length = types.Int64Value(int64(len(stringDataV2.Result.ValueString())))
+	}
+
+	minNumeric := stringDataV2.MinNumeric
+
+	if minNumeric.IsNull() {
+		minNumeric = types.Int64Value(0)
+	}
+
+	minUpper := stringDataV2.MinUpper
+
+	if minUpper.IsNull() {
+		minUpper = types.Int64Value(0)
+	}
+
+	minLower := stringDataV2.MinLower
+
+	if minLower.IsNull() {
+		minLower = types.Int64Value(0)
+	}
+
+	minSpecial := stringDataV2.MinSpecial
+
+	if minSpecial.IsNull() {
+		minSpecial = types.Int64Value(0)
+	}
+
+	special := stringDataV2.Special
+
+	if special.IsNull() {
+		special = types.BoolValue(true)
+	}
+
+	upper := stringDataV2.Upper
+
+	if upper.IsNull() {
+		upper = types.BoolValue(true)
+	}
+
+	lower := stringDataV2.Lower
+
+	if lower.IsNull() {
+		lower = types.BoolValue(true)
+	}
+
+	number := stringDataV2.Number
+
+	if number.IsNull() {
+		number = types.BoolValue(true)
+	}
+
+	stringDataV3 := stringModelV3{
+		Keepers:         stringDataV2.Keepers,
+		Length:          length,
+		Special:         special,
+		Upper:           upper,
+		Lower:           lower,
+		Number:          number,
+		Numeric:         number,
+		MinNumeric:      minNumeric,
+		MinUpper:        minUpper,
+		MinLower:        minLower,
+		MinSpecial:      minSpecial,
+		OverrideSpecial: stringDataV2.OverrideSpecial,
+		Result:          stringDataV2.Result,
+		ID:              stringDataV2.ID,
+	}
+
+	diags := resp.State.Set(ctx, stringDataV3)
+	resp.Diagnostics.Append(diags...)
+}
+
+func stringSchemaV3() schema.Schema {
+	return schema.Schema{
+		Version: 2,
+		Description: "The resource `random_string` generates a random permutation of alphanumeric " +
+			"characters and optionally special characters.\n" +
+			"\n" +
+			"This resource *does* use a cryptographic random number generator.\n" +
+			"\n" +
+			"Historically this resource's intended usage has been ambiguous as the original example used " +
+			"it in a password. For backwards compatibility it will continue to exist. For unique ids please " +
+			"use [random_id](id.html), for sensitive random values please use [random_password](password.html).",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+				Validators: []validator.Int64{
+					int64validator.AtLeast(1),
+					int64validator.AtLeastSumOf(
+						path.MatchRoot("min_upper"),
+						path.MatchRoot("min_lower"),
+						path.MatchRoot("min_numeric"),
+						path.MatchRoot("min_special"),
+					),
+				},
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     booldefault.StaticBool(true),
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`. " +
+					"**NOTE**: This is deprecated, use `numeric` instead.",
+				Optional: true,
+				Computed: true,
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifiers.NumberNumericAttributePlanModifier(),
+					boolplanmodifier.RequiresReplace(),
+				},
+				DeprecationMessage: "**NOTE**: This is deprecated, use `numeric` instead.",
+			},
+
+			"numeric": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+				PlanModifiers: []planmodifier.Bool{
+					boolplanmodifiers.NumberNumericAttributePlanModifier(),
+					boolplanmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+				Default:     int64default.StaticInt64(0),
+				PlanModifiers: []planmodifier.Int64{
+					int64planmodifier.RequiresReplace(),
+				},
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplaceIf(
+						stringplanmodifiers.RequiresReplaceUnlessEmptyStringToNull(),
+						"Replace on modification unless updating from empty string (\"\") to null.",
+						"Replace on modification unless updating from empty string (`\"\"`) to `null`.",
+					),
+				},
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+
+			"id": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func stringSchemaV2() schema.Schema {
+	return schema.Schema{
+		Version: 2,
+		Description: "The resource `random_string` generates a random permutation of alphanumeric " +
+			"characters and optionally special characters.\n" +
+			"\n" +
+			"This resource *does* use a cryptographic random number generator.\n" +
+			"\n" +
+			"Historically this resource's intended usage has been ambiguous as the original example used " +
+			"it in a password. For backwards compatibility it will continue to exist. For unique ids please " +
+			"use [random_id](id.html), for sensitive random values please use [random_password](password.html).",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`. " +
+					"**NOTE**: This is deprecated, use `numeric` instead.",
+				Optional:           true,
+				Computed:           true,
+				DeprecationMessage: "**NOTE**: This is deprecated, use `numeric` instead.",
+			},
+
+			"numeric": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				Computed: true,
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+			},
+
+			"id": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+			},
+		},
+	}
+}
+
+func stringSchemaV1() schema.Schema {
+	return schema.Schema{
+		Version: 1,
+		Description: "The resource `random_string` generates a random permutation of alphanumeric " +
+			"characters and optionally special characters.\n" +
+			"\n" +
+			"This resource *does* use a cryptographic random number generator.\n" +
+			"\n" +
+			"Historically this resource's intended usage has been ambiguous as the original example used " +
+			"it in a password. For backwards compatibility it will continue to exist. For unique ids please " +
+			"use [random_id](id.html), for sensitive random values please use [random_password](password.html).",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+			},
+
+			"length": schema.Int64Attribute{
+				Description: "The length of the string desired. The minimum value for length is 1 and, length " +
+					"must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).",
+				Required: true,
+			},
+
+			"special": schema.BoolAttribute{
+				Description: "Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"upper": schema.BoolAttribute{
+				Description: "Include uppercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"lower": schema.BoolAttribute{
+				Description: "Include lowercase alphabet characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"number": schema.BoolAttribute{
+				Description: "Include numeric characters in the result. Default value is `true`.",
+				Optional:    true,
+				Computed:    true,
+			},
+			"min_numeric": schema.Int64Attribute{
+				Description: "Minimum number of numeric characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_upper": schema.Int64Attribute{
+				Description: "Minimum number of uppercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_lower": schema.Int64Attribute{
+				Description: "Minimum number of lowercase alphabet characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"min_special": schema.Int64Attribute{
+				Description: "Minimum number of special characters in the result. Default value is `0`.",
+				Optional:    true,
+				Computed:    true,
+			},
+
+			"override_special": schema.StringAttribute{
+				Description: "Supply your own list of special characters to use for string generation.  This " +
+					"overrides the default character list in the special argument.  The `special` argument must " +
+					"still be set to true for any overwritten characters to be used in generation.",
+				Optional: true,
+				Computed: true,
+			},
+
+			"result": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+			},
+
+			"id": schema.StringAttribute{
+				Description: "The generated random string.",
+				Computed:    true,
+			},
+		},
+	}
+}
+
+type stringModelV3 struct {
+	ID              types.String `tfsdk:"id"`
+	Keepers         types.Map    `tfsdk:"keepers"`
+	Length          types.Int64  `tfsdk:"length"`
+	Special         types.Bool   `tfsdk:"special"`
+	Upper           types.Bool   `tfsdk:"upper"`
+	Lower           types.Bool   `tfsdk:"lower"`
+	Number          types.Bool   `tfsdk:"number"`
+	Numeric         types.Bool   `tfsdk:"numeric"`
+	MinNumeric      types.Int64  `tfsdk:"min_numeric"`
+	MinUpper        types.Int64  `tfsdk:"min_upper"`
+	MinLower        types.Int64  `tfsdk:"min_lower"`
+	MinSpecial      types.Int64  `tfsdk:"min_special"`
+	OverrideSpecial types.String `tfsdk:"override_special"`
+	Result          types.String `tfsdk:"result"`
+}
diff --git a/v3.6.0/internal/provider/resource_string_test.go b/v3.6.0/internal/provider/resource_string_test.go
new file mode 100644
index 0000000..992ebba
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_string_test.go
@@ -0,0 +1,1780 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"fmt"
+	"regexp"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	res "github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/tfsdk"
+	"github.com/hashicorp/terraform-plugin-go/tftypes"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccResourceString_Import(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_string" "basic" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.basic", "result", testCheckLen(12)),
+				),
+			},
+			{
+				ResourceName:      "random_string.basic",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_EmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_NullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_NullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_NullValues(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_Value(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Keep_Values(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_string.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_string.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Override(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_string" "override" {
+							length = 4
+							override_special = "!"
+							lower = false
+							upper = false
+							numeric = false
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.override", "result", testCheckLen(4)),
+					resource.TestCheckResourceAttr("random_string.override", "result", "!!!!"),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourceString_OverrideSpecial_FromVersion3_3_2 verifies behaviour
+// when upgrading the provider version from 3.3.2, which set the
+// override_special value to null and should not result in a plan difference.
+// Reference: https://github.com/hashicorp/terraform-provider-random/issues/306
+func TestAccResourceString_OverrideSpecial_FromVersion3_3_2(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckNoResourceAttr("random_string.test", "override_special"),
+					testExtractResourceAttr("random_string.test", "result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckNoResourceAttr("random_string.test", "override_special"),
+					testExtractResourceAttr("random_string.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourceString_OverrideSpecial_FromVersion3_4_2 verifies behaviour
+// when upgrading the provider version from 3.4.2, which set the
+// override_special value to "", while other versions do not.
+// Reference: https://github.com/hashicorp/terraform-provider-random/issues/306
+func TestAccResourceString_OverrideSpecial_FromVersion3_4_2(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion342(),
+				Config: `resource "random_string" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("random_string.test", "override_special", ""),
+					testExtractResourceAttr("random_string.test", "result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckNoResourceAttr("random_string.test", "override_special"),
+					testExtractResourceAttr("random_string.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceString_Min(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([!#@].*)`)),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourceString_StateUpgradeV1toV2 covers the state upgrade from V1 to V2.
+// This includes the deprecation of `number` and the addition of `numeric` attributes.
+// v3.2.0 was used as this is the last version before `number` was deprecated and `numeric` attribute
+// was added.
+func TestAccResourceString_StateUpgradeV1toV2(t *testing.T) {
+	t.Parallel()
+
+	cases := []struct {
+		name                string
+		configBeforeUpgrade string
+		configDuringUpgrade string
+		beforeStateUpgrade  []resource.TestCheckFunc
+		afterStateUpgrade   []resource.TestCheckFunc
+	}{
+		{
+			name: "number is absent before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is absent before numeric is true during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is absent before numeric is false during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before numeric is true during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is true before numeric is false during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+						number = true
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is false during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+						numeric = false
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "false"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before number and numeric are absent during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+		{
+			name: "number is false before numeric is true during",
+			configBeforeUpgrade: `resource "random_string" "default" {
+						length = 12
+						number = false
+					}`,
+			configDuringUpgrade: `resource "random_string" "default" {
+						length = 12
+						numeric = true
+					}`,
+			beforeStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "false"),
+				resource.TestCheckNoResourceAttr("random_string.default", "numeric"),
+			},
+			afterStateUpgrade: []resource.TestCheckFunc{
+				resource.TestCheckResourceAttr("random_string.default", "number", "true"),
+				resource.TestCheckResourceAttrPair("random_string.default", "number", "random_string.default", "numeric"),
+			},
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			resource.UnitTest(t, resource.TestCase{
+				Steps: []resource.TestStep{
+					{
+						ExternalProviders: map[string]resource.ExternalProvider{"random": {
+							VersionConstraint: "3.2.0",
+							Source:            "hashicorp/random",
+						}},
+						Config: c.configBeforeUpgrade,
+						Check:  resource.ComposeTestCheckFunc(c.beforeStateUpgrade...),
+					},
+					{
+						ProtoV5ProviderFactories: protoV5ProviderFactories(),
+						Config:                   c.configDuringUpgrade,
+						Check:                    resource.ComposeTestCheckFunc(c.afterStateUpgrade...),
+					},
+				},
+			})
+		})
+	}
+}
+
+func TestAccResourceString_LengthErrors(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_string" "invalid_length" {
+  							length = 2
+  							min_lower = 3
+						}`,
+				ExpectError: regexp.MustCompile(`.*Attribute length value must be at least sum of min_upper \+ min_lower \+\nmin_numeric \+ min_special, got: 2`),
+			},
+			{
+				Config: `resource "random_string" "invalid_length" {
+							length = 0
+						}`,
+				ExpectError: regexp.MustCompile(`.*Attribute length value must be at least 1, got: 0`),
+			},
+		},
+	})
+}
+
+// TestAccResourceString_UpgradeFromVersion3_2_0 verifies behaviour when upgrading state from schema V1 to V2.
+func TestAccResourceString_UpgradeFromVersion3_2_0(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion320(),
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_string.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_string.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_string.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_string.min", "min_numeric", "4"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_string.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_string.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_string.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_string.min", "min_numeric", "4"),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourceString_UpgradeFromVersion3_3_2 verifies behaviour when upgrading from SDKv2 to the Framework.
+func TestAccResourceString_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_string.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_string.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_string.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_string.min", "min_numeric", "4"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "min" {
+							length = 12
+							override_special = "!#@"
+							min_lower = 2
+							min_upper = 3
+							min_special = 1
+							min_numeric = 4
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.min", "result", testCheckLen(12)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([a-z].*){2,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([A-Z].*){3,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([0-9].*){4,}`)),
+					resource.TestMatchResourceAttr("random_string.min", "result", regexp.MustCompile(`([!#@])`)),
+					resource.TestCheckResourceAttr("random_string.min", "special", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "upper", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "lower", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "number", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_string.min", "min_special", "1"),
+					resource.TestCheckResourceAttr("random_string.min", "min_upper", "3"),
+					resource.TestCheckResourceAttr("random_string.min", "min_lower", "2"),
+					resource.TestCheckResourceAttr("random_string.min", "min_numeric", "4"),
+				),
+			},
+		},
+	})
+}
+
+func TestUpgradeStringStateV1toV3(t *testing.T) {
+	t.Parallel()
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: stringSchemaV1(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	upgradeStringStateV1toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradeStringStateV1toV3_NullValues(t *testing.T) {
+	t.Parallel()
+
+	raw := tftypes.NewValue(tftypes.Object{
+		AttributeTypes: map[string]tftypes.Type{
+			"id":               tftypes.String,
+			"keepers":          tftypes.Map{ElementType: tftypes.String},
+			"length":           tftypes.Number,
+			"lower":            tftypes.Bool,
+			"min_lower":        tftypes.Number,
+			"min_numeric":      tftypes.Number,
+			"min_special":      tftypes.Number,
+			"min_upper":        tftypes.Number,
+			"number":           tftypes.Bool,
+			"override_special": tftypes.String,
+			"result":           tftypes.String,
+			"special":          tftypes.Bool,
+			"upper":            tftypes.Bool,
+		},
+	}, map[string]tftypes.Value{
+		"id":               tftypes.NewValue(tftypes.String, "none"),
+		"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+		"length":           tftypes.NewValue(tftypes.Number, nil),
+		"lower":            tftypes.NewValue(tftypes.Bool, nil),
+		"min_lower":        tftypes.NewValue(tftypes.Number, nil),
+		"min_numeric":      tftypes.NewValue(tftypes.Number, nil),
+		"min_special":      tftypes.NewValue(tftypes.Number, nil),
+		"min_upper":        tftypes.NewValue(tftypes.Number, nil),
+		"number":           tftypes.NewValue(tftypes.Bool, nil),
+		"override_special": tftypes.NewValue(tftypes.String, nil),
+		"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+		"special":          tftypes.NewValue(tftypes.Bool, nil),
+		"upper":            tftypes.NewValue(tftypes.Bool, nil),
+	})
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw:    raw,
+			Schema: stringSchemaV1(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	upgradeStringStateV1toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, nil),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradeStringStateV2toV3(t *testing.T) {
+	t.Parallel()
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: stringSchemaV2(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	upgradeStringStateV2toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, "!#$%\u0026*()-_=+[]{}\u003c\u003e:?"),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+func TestUpgradeStringStateV2toV3_NullValues(t *testing.T) {
+	t.Parallel()
+
+	raw := tftypes.NewValue(tftypes.Object{
+		AttributeTypes: map[string]tftypes.Type{
+			"id":               tftypes.String,
+			"keepers":          tftypes.Map{ElementType: tftypes.String},
+			"length":           tftypes.Number,
+			"lower":            tftypes.Bool,
+			"min_lower":        tftypes.Number,
+			"min_numeric":      tftypes.Number,
+			"min_special":      tftypes.Number,
+			"min_upper":        tftypes.Number,
+			"number":           tftypes.Bool,
+			"numeric":          tftypes.Bool,
+			"override_special": tftypes.String,
+			"result":           tftypes.String,
+			"special":          tftypes.Bool,
+			"upper":            tftypes.Bool,
+		},
+	}, map[string]tftypes.Value{
+		"id":               tftypes.NewValue(tftypes.String, "none"),
+		"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+		"length":           tftypes.NewValue(tftypes.Number, nil),
+		"lower":            tftypes.NewValue(tftypes.Bool, nil),
+		"min_lower":        tftypes.NewValue(tftypes.Number, nil),
+		"min_numeric":      tftypes.NewValue(tftypes.Number, nil),
+		"min_special":      tftypes.NewValue(tftypes.Number, nil),
+		"min_upper":        tftypes.NewValue(tftypes.Number, nil),
+		"number":           tftypes.NewValue(tftypes.Bool, nil),
+		"numeric":          tftypes.NewValue(tftypes.Bool, nil),
+		"override_special": tftypes.NewValue(tftypes.String, nil),
+		"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+		"special":          tftypes.NewValue(tftypes.Bool, nil),
+		"upper":            tftypes.NewValue(tftypes.Bool, nil),
+	})
+
+	req := res.UpgradeStateRequest{
+		State: &tfsdk.State{
+			Raw:    raw,
+			Schema: stringSchemaV2(),
+		},
+	}
+
+	resp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	upgradeStringStateV2toV3(context.Background(), req, resp)
+
+	expectedResp := &res.UpgradeStateResponse{
+		State: tfsdk.State{
+			Raw: tftypes.NewValue(tftypes.Object{
+				AttributeTypes: map[string]tftypes.Type{
+					"id":               tftypes.String,
+					"keepers":          tftypes.Map{ElementType: tftypes.String},
+					"length":           tftypes.Number,
+					"lower":            tftypes.Bool,
+					"min_lower":        tftypes.Number,
+					"min_numeric":      tftypes.Number,
+					"min_special":      tftypes.Number,
+					"min_upper":        tftypes.Number,
+					"number":           tftypes.Bool,
+					"numeric":          tftypes.Bool,
+					"override_special": tftypes.String,
+					"result":           tftypes.String,
+					"special":          tftypes.Bool,
+					"upper":            tftypes.Bool,
+				},
+			}, map[string]tftypes.Value{
+				"id":               tftypes.NewValue(tftypes.String, "none"),
+				"keepers":          tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
+				"length":           tftypes.NewValue(tftypes.Number, 16),
+				"lower":            tftypes.NewValue(tftypes.Bool, true),
+				"min_lower":        tftypes.NewValue(tftypes.Number, 0),
+				"min_numeric":      tftypes.NewValue(tftypes.Number, 0),
+				"min_special":      tftypes.NewValue(tftypes.Number, 0),
+				"min_upper":        tftypes.NewValue(tftypes.Number, 0),
+				"number":           tftypes.NewValue(tftypes.Bool, true),
+				"numeric":          tftypes.NewValue(tftypes.Bool, true),
+				"override_special": tftypes.NewValue(tftypes.String, nil),
+				"result":           tftypes.NewValue(tftypes.String, "DZy_3*tnonj%Q%Yx"),
+				"special":          tftypes.NewValue(tftypes.Bool, true),
+				"upper":            tftypes.NewValue(tftypes.Bool, true),
+			}),
+			Schema: stringSchemaV3(),
+		},
+	}
+
+	if !cmp.Equal(expectedResp, resp) {
+		t.Errorf("expected: %+v, got: %+v", expectedResp, resp)
+	}
+}
+
+// TestAccResourcePassword_String_FromVersion3_1_3 verifies behaviour when resource has been imported and stores
+// null for length, lower, number, special, upper, min_lower, min_numeric, min_special, min_upper attributes in state.
+// v3.1.3 was selected as this is the last provider version using schema version 1.
+func TestAccResourceString_Import_FromVersion3_1_3(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion313(),
+				Config: `resource "random_string" "test" {
+							length = 12
+						}`,
+				ResourceName:       "random_string.test",
+				ImportState:        true,
+				ImportStateId:      "Z=:cbrJE?Ltg",
+				ImportStatePersist: true,
+				ImportStateCheck: composeImportStateCheck(
+					testCheckNoResourceAttrInstanceState("length"),
+					testCheckNoResourceAttrInstanceState("number"),
+					testCheckNoResourceAttrInstanceState("upper"),
+					testCheckNoResourceAttrInstanceState("lower"),
+					testCheckNoResourceAttrInstanceState("special"),
+					testCheckNoResourceAttrInstanceState("min_numeric"),
+					testCheckNoResourceAttrInstanceState("min_upper"),
+					testCheckNoResourceAttrInstanceState("min_lower"),
+					testCheckNoResourceAttrInstanceState("min_special"),
+					testExtractResourceAttrInstanceState("result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+					length = 12
+				}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.test", "result", testCheckLen(12)),
+					resource.TestCheckResourceAttr("random_string.test", "number", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "upper", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "lower", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "special", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "min_numeric", "0"),
+					resource.TestCheckResourceAttr("random_string.test", "min_upper", "0"),
+					resource.TestCheckResourceAttr("random_string.test", "min_lower", "0"),
+					resource.TestCheckResourceAttr("random_string.test", "min_special", "0"),
+					testExtractResourceAttr("random_string.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+// TestAccResourceString_Import_FromVersion3_4_2 verifies behaviour when resource has been imported and stores
+// empty map {} for keepers and empty string for override_special in state.
+// v3.4.2 was selected as this is the last provider version using schema version 2.
+func TestAccResourceString_Import_FromVersion3_4_2(t *testing.T) {
+	var result1, result2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion342(),
+				Config: `resource "random_string" "test" {
+							length = 12
+						}`,
+				ResourceName:       "random_string.test",
+				ImportState:        true,
+				ImportStateId:      "Z=:cbrJE?Ltg",
+				ImportStatePersist: true,
+				ImportStateCheck: composeImportStateCheck(
+					testCheckResourceAttrInstanceState("length"),
+					testCheckResourceAttrInstanceState("number"),
+					testCheckResourceAttrInstanceState("numeric"),
+					testCheckResourceAttrInstanceState("upper"),
+					testCheckResourceAttrInstanceState("lower"),
+					testCheckResourceAttrInstanceState("special"),
+					testCheckResourceAttrInstanceState("min_numeric"),
+					testCheckResourceAttrInstanceState("min_upper"),
+					testCheckResourceAttrInstanceState("min_lower"),
+					testCheckResourceAttrInstanceState("min_special"),
+					testExtractResourceAttrInstanceState("result", &result1),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_string" "test" {
+							length = 12
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttrWith("random_string.test", "result", testCheckLen(12)),
+					resource.TestCheckResourceAttr("random_string.test", "number", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "numeric", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "upper", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "lower", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "special", "true"),
+					resource.TestCheckResourceAttr("random_string.test", "min_numeric", "0"),
+					resource.TestCheckResourceAttr("random_string.test", "min_upper", "0"),
+					resource.TestCheckResourceAttr("random_string.test", "min_lower", "0"),
+					resource.TestCheckResourceAttr("random_string.test", "min_special", "0"),
+					testExtractResourceAttr("random_string.test", "result", &result2),
+					testCheckAttributeValuesEqual(&result1, &result2),
+				),
+			},
+		},
+	})
+}
+
+func testCheckLen(expectedLen int) func(input string) error {
+	return func(input string) error {
+		if len(input) != expectedLen {
+			return fmt.Errorf("expected length %d, actual length %d", expectedLen, len(input))
+		}
+
+		return nil
+	}
+}
+
+//nolint:unparam
+func testCheckMinLen(minLen int) func(input string) error {
+	return func(input string) error {
+		if len(input) < minLen {
+			return fmt.Errorf("minimum length %d, actual length %d", minLen, len(input))
+		}
+
+		return nil
+	}
+}
diff --git a/v3.6.0/internal/provider/resource_uuid.go b/v3.6.0/internal/provider/resource_uuid.go
new file mode 100644
index 0000000..75e0167
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_uuid.go
@@ -0,0 +1,166 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/go-uuid"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/diagnostics"
+	mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
+)
+
+var (
+	_ resource.Resource                = (*uuidResource)(nil)
+	_ resource.ResourceWithImportState = (*uuidResource)(nil)
+)
+
+func NewUuidResource() resource.Resource {
+	return &uuidResource{}
+}
+
+type uuidResource struct{}
+
+func (r *uuidResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_uuid"
+}
+
+func (r *uuidResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Description: "The resource `random_uuid` generates a random uuid string that is intended to be " +
+			"used as a unique identifier for other resources.\n" +
+			"\n" +
+			"This resource uses [hashicorp/go-uuid](https://github.com/hashicorp/go-uuid) to generate a " +
+			"UUID-formatted string for use with services needing a unique string identifier.",
+		Attributes: map[string]schema.Attribute{
+			"keepers": schema.MapAttribute{
+				Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
+					"resource. See [the main provider documentation](../index.html) for more information.",
+				ElementType: types.StringType,
+				Optional:    true,
+				PlanModifiers: []planmodifier.Map{
+					mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
+				},
+			},
+			"result": schema.StringAttribute{
+				Description: "The generated uuid presented in string format.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"id": schema.StringAttribute{
+				Description: "The generated uuid presented in string format.",
+				Computed:    true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+		},
+	}
+}
+
+func (r *uuidResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	result, err := uuid.GenerateUUID()
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Create Random UUID error",
+			"There was an error during generation of a UUID.\n\n"+
+				diagnostics.RetryMsg+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	var plan uuidModelV0
+
+	diags := req.Plan.Get(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	u := &uuidModelV0{
+		ID:      types.StringValue(result),
+		Result:  types.StringValue(result),
+		Keepers: plan.Keepers,
+	}
+
+	diags = resp.State.Set(ctx, u)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
+func (r *uuidResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+}
+
+// Update ensures the plan value is copied to the state to complete the update.
+func (r *uuidResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var model uuidModelV0
+
+	resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
+}
+
+// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
+// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
+func (r *uuidResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+}
+
+func (r *uuidResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	bytes, err := uuid.ParseUUID(req.ID)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random UUID Error",
+			"There was an error during the parsing of the UUID.\n\n"+
+				diagnostics.RetryMsg+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	result, err := uuid.FormatUUID(bytes)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Import Random UUID Error",
+			"There was an error during the formatting of the UUID.\n\n"+
+				diagnostics.RetryMsg+
+				fmt.Sprintf("Original Error: %s", err),
+		)
+		return
+	}
+
+	var state uuidModelV0
+
+	state.ID = types.StringValue(result)
+	state.Result = types.StringValue(result)
+	state.Keepers = types.MapValueMust(types.StringType, nil)
+
+	diags := resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+}
+
+type uuidModelV0 struct {
+	ID      types.String `tfsdk:"id"`
+	Keepers types.Map    `tfsdk:"keepers"`
+	Result  types.String `tfsdk:"result"`
+}
diff --git a/v3.6.0/internal/provider/resource_uuid_test.go b/v3.6.0/internal/provider/resource_uuid_test.go
new file mode 100644
index 0000000..d86d901
--- /dev/null
+++ b/v3.6.0/internal/provider/resource_uuid_test.go
@@ -0,0 +1,761 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"regexp"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccResourceUUID(t *testing.T) {
+	resource.UnitTest(t, resource.TestCase{
+		ProtoV5ProviderFactories: protoV5ProviderFactories(),
+		Steps: []resource.TestStep{
+			{
+				Config: `resource "random_uuid" "basic" { 
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestMatchResourceAttr("random_uuid.basic", "result", regexp.MustCompile(`[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}`)),
+				),
+			},
+			{
+				ResourceName:      "random_uuid.basic",
+				ImportState:       true,
+				ImportStateVerify: true,
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_EmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_EmptyMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_NullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_NullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_NullValues(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_Value(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Keep_Values(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_EmptyMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_NullValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_ValueToEmptyMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_ValueToNullMap(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_ValueToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_Replace_ValueToNewValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_FrameworkMigration_NullMapToNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_FrameworkMigration_NullMapToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key" = "123"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_FrameworkMigration_NullMapToMultipleNullValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_FrameworkMigration_NullMapToMultipleValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = null
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "0"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_FrameworkMigration_NullMapValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesEqual(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_Keepers_FrameworkMigration_NullMapValueToValue(t *testing.T) {
+	var id1, id2 string
+
+	resource.ParallelTest(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = null
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id1),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "1"),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "test" {
+					keepers = {
+						"key1" = "123"
+						"key2" = "456"
+					}
+				}`,
+				Check: resource.ComposeTestCheckFunc(
+					testExtractResourceAttr("random_uuid.test", "id", &id2),
+					testCheckAttributeValuesDiffer(&id1, &id2),
+					resource.TestCheckResourceAttr("random_uuid.test", "keepers.%", "2"),
+				),
+			},
+		},
+	})
+}
+
+func TestAccResourceUUID_UpgradeFromVersion3_3_2(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		Steps: []resource.TestStep{
+			{
+				ExternalProviders: providerVersion332(),
+				Config: `resource "random_uuid" "basic" { 
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestMatchResourceAttr("random_uuid.basic", "result", regexp.MustCompile(`[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}`)),
+				),
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "basic" { 
+						}`,
+				PlanOnly: true,
+			},
+			{
+				ProtoV5ProviderFactories: protoV5ProviderFactories(),
+				Config: `resource "random_uuid" "basic" { 
+						}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestMatchResourceAttr("random_uuid.basic", "result", regexp.MustCompile(`[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}`)),
+				),
+			},
+		},
+	})
+}
diff --git a/v3.6.0/internal/provider/tftypes_test.go b/v3.6.0/internal/provider/tftypes_test.go
new file mode 100644
index 0000000..0b73b0e
--- /dev/null
+++ b/v3.6.0/internal/provider/tftypes_test.go
@@ -0,0 +1,26 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-go/tftypes"
+)
+
+func testTftypesValueAtPath(value tftypes.Value, path *tftypes.AttributePath) (tftypes.Value, error) {
+	valueAtPathRaw, remaining, err := tftypes.WalkAttributePath(value, path)
+
+	if err != nil {
+		return tftypes.Value{}, fmt.Errorf("unexpected error getting %s: %s (%s remaining)", path, err, remaining)
+	}
+
+	valueAtPath, ok := valueAtPathRaw.(tftypes.Value)
+
+	if !ok {
+		return tftypes.Value{}, fmt.Errorf("unexpected type converting %s to tftypes.Value, got: %T", path, valueAtPathRaw)
+	}
+
+	return valueAtPath, nil
+}
diff --git a/v3.6.0/internal/random/seed.go b/v3.6.0/internal/random/seed.go
new file mode 100644
index 0000000..45100d4
--- /dev/null
+++ b/v3.6.0/internal/random/seed.go
@@ -0,0 +1,27 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package random
+
+import (
+	"hash/crc64"
+	"math/rand"
+	"time"
+)
+
+// NewRand returns a seeded random number generator, using a seed derived
+// from the provided string.
+//
+// If the seed string is empty, the current time is used as a seed.
+func NewRand(seed string) *rand.Rand {
+	var seedInt int64
+	if seed != "" {
+		crcTable := crc64.MakeTable(crc64.ISO)
+		seedInt = int64(crc64.Checksum([]byte(seed), crcTable))
+	} else {
+		seedInt = time.Now().UnixNano()
+	}
+
+	randSource := rand.NewSource(seedInt)
+	return rand.New(randSource)
+}
diff --git a/v3.6.0/internal/random/string.go b/v3.6.0/internal/random/string.go
new file mode 100644
index 0000000..7b8f256
--- /dev/null
+++ b/v3.6.0/internal/random/string.go
@@ -0,0 +1,97 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package random
+
+import (
+	"crypto/rand"
+	"math/big"
+	"sort"
+)
+
+type StringParams struct {
+	Length          int64
+	Upper           bool
+	MinUpper        int64
+	Lower           bool
+	MinLower        int64
+	Numeric         bool
+	MinNumeric      int64
+	Special         bool
+	MinSpecial      int64
+	OverrideSpecial string
+}
+
+func CreateString(input StringParams) ([]byte, error) {
+	const numChars = "0123456789"
+	const lowerChars = "abcdefghijklmnopqrstuvwxyz"
+	const upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	var specialChars = "!@#$%&*()-_=+[]{}<>:?"
+	var result []byte
+
+	if input.OverrideSpecial != "" {
+		specialChars = input.OverrideSpecial
+	}
+
+	var chars = ""
+	if input.Upper {
+		chars += upperChars
+	}
+	if input.Lower {
+		chars += lowerChars
+	}
+	if input.Numeric {
+		chars += numChars
+	}
+	if input.Special {
+		chars += specialChars
+	}
+
+	minMapping := map[string]int64{
+		numChars:     input.MinNumeric,
+		lowerChars:   input.MinLower,
+		upperChars:   input.MinUpper,
+		specialChars: input.MinSpecial,
+	}
+
+	result = make([]byte, 0, input.Length)
+
+	for k, v := range minMapping {
+		s, err := generateRandomBytes(&k, v)
+		if err != nil {
+			return nil, err
+		}
+		result = append(result, s...)
+	}
+
+	s, err := generateRandomBytes(&chars, input.Length-int64(len(result)))
+	if err != nil {
+		return nil, err
+	}
+
+	result = append(result, s...)
+
+	order := make([]byte, len(result))
+	if _, err := rand.Read(order); err != nil {
+		return nil, err
+	}
+
+	sort.Slice(result, func(i, j int) bool {
+		return order[i] < order[j]
+	})
+
+	return result, nil
+}
+
+func generateRandomBytes(charSet *string, length int64) ([]byte, error) {
+	bytes := make([]byte, length)
+	setLen := big.NewInt(int64(len(*charSet)))
+	for i := range bytes {
+		idx, err := rand.Int(rand.Reader, setLen)
+		if err != nil {
+			return nil, err
+		}
+		bytes[i] = (*charSet)[idx.Int64()]
+	}
+	return bytes, nil
+}
diff --git a/v3.6.0/main.go b/v3.6.0/main.go
new file mode 100644
index 0000000..ec3f74f
--- /dev/null
+++ b/v3.6.0/main.go
@@ -0,0 +1,30 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"flag"
+	"log"
+
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+
+	"github.com/terraform-providers/terraform-provider-random/internal/provider"
+)
+
+func main() {
+	var debug bool
+
+	flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
+	flag.Parse()
+
+	err := providerserver.Serve(context.Background(), provider.New, providerserver.ServeOpts{
+		Address:         "registry.terraform.io/hashicorp/random",
+		Debug:           debug,
+		ProtocolVersion: 5,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/v3.6.0/templates/index.md.tmpl b/v3.6.0/templates/index.md.tmpl
new file mode 100644
index 0000000..c791fe2
--- /dev/null
+++ b/v3.6.0/templates/index.md.tmpl
@@ -0,0 +1,54 @@
+---
+page_title: "Provider: Random"
+description: |-
+  The Random provider is used to generate randomness.
+---
+
+# Random Provider
+
+The "random" provider allows the use of randomness within Terraform
+configurations. This is a *logical provider*, which means that it works
+entirely within Terraform's logic, and doesn't interact with any other
+services.
+
+Unconstrained randomness within a Terraform configuration would not be very
+useful, since Terraform's goal is to converge on a fixed configuration by
+applying a diff. Because of this, the "random" provider provides an idea of
+*managed randomness*: it provides resources that generate random values during
+their creation and then hold those values steady until the inputs are changed.
+
+Even with these resources, it is advisable to keep the use of randomness within
+Terraform configuration to a minimum, and retain it for special cases only;
+Terraform works best when the configuration is well-defined, since its behavior
+can then be more readily predicted.
+
+Unless otherwise stated within the documentation of a specific resource, this
+provider's results are **not** sufficiently random for cryptographic use.
+
+For more information on the specific resources available, see the links in the
+navigation bar. Read on for information on the general patterns that apply
+to this provider's resources.
+
+## Resource "Keepers"
+
+As noted above, the random resources generate randomness only when they are
+created; the results produced are stored in the Terraform state and re-used
+until the inputs change, prompting the resource to be recreated.
+
+The resources all provide a map argument called `keepers` that can be populated
+with arbitrary key/value pairs that should be selected such that they remain
+the same until new random values are desired.
+
+For example:
+
+{{ tffile "examples/provider/provider.tf" }}
+
+Resource "keepers" are optional. The other arguments to each resource must
+*also* remain constant in order to retain a random result.
+
+`keepers` are *not* treated as sensitive attributes; a value used for `keepers` will be displayed in Terraform UI output as plaintext.
+
+To force a random result to be replaced, the `taint` command can be used to
+produce a new result on the next run.
+
+{{- /* No schema in this provider, so no need for this: .SchemaMarkdown | trimspace */ -}}
\ No newline at end of file
diff --git a/v3.6.0/templates/resources/password.md.tmpl b/v3.6.0/templates/resources/password.md.tmpl
new file mode 100644
index 0000000..6b22dcd
--- /dev/null
+++ b/v3.6.0/templates/resources/password.md.tmpl
@@ -0,0 +1,85 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines "  " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+## Example Usage
+
+{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}}
+
+{{ .SchemaMarkdown | trimspace }}
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_password.password securepassword
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```terraform
+resource "random_password" "password" {
+  length = 16
+  lower  = false
+}
+```
+
+Then importing the resource using `terraform import random_password.password securepassword`,
+would result in the triggering of a replacement (i.e., destroy-create) during the next
+`terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_password.password securepassword`,
+replacement could be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+
+    ```terraform
+    resource "random_password" "password" {
+      length = 14
+      lower  = true
+    }
+    ```
+
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+
+    ```terraform
+    resource "random_password" "password" {
+      length = 14
+    }
+    ```
+
+
+3. `ignore_changes` specifying the attributes to ignore:
+
+    ```terraform
+    resource "random_password" "password" {
+      length = 16
+      lower  = false
+
+      lifecycle {
+        ignore_changes = [
+          length,
+          lower,
+        ]
+      }
+    }
+    ```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
diff --git a/v3.6.0/templates/resources/string.md.tmpl b/v3.6.0/templates/resources/string.md.tmpl
new file mode 100644
index 0000000..abe2e05
--- /dev/null
+++ b/v3.6.0/templates/resources/string.md.tmpl
@@ -0,0 +1,80 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines "  " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+## Example Usage
+
+{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}}
+
+{{ .SchemaMarkdown | trimspace }}
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import random_string.test test
+```
+
+### Limitations of Import
+
+Any attribute values that are specified within Terraform config will be
+ignored during import and all attributes that have defaults defined within
+the schema will have the default assigned.
+
+For instance, using the following config during import:
+```terraform
+resource "random_string" "test" {
+  length = 16
+  lower  = false
+}
+```
+
+Then importing the resource using `terraform import random_string.test test`,
+would result in the triggering of a replacement (i.e., destroy-create) during
+the next `terraform apply`.
+
+### Avoiding Replacement
+
+If the resource were imported using `terraform import random_string.test test`,
+replacement can be avoided by using:
+
+1. Attribute values that match the imported ID and defaults:
+    ```terraform
+    resource "random_string" "test" {
+      length = 4
+      lower  = true
+    }
+    ```
+
+2. Attribute values that match the imported ID and omit the attributes with defaults:
+    ```terraform
+    resource "random_string" "test" {
+      length = 4
+    }
+    ```
+
+3. `ignore_changes` specifying the attributes to ignore:
+    ```terraform
+    resource "random_string" "test" {
+      length = 16
+      lower  = false
+
+      lifecycle {
+        ignore_changes = [
+          length,
+          lower,
+        ]
+      }
+    }
+    ```
+
+    **NOTE** `ignore_changes` is only required until the resource is recreated after import,
+    after which it will use the configuration values specified.
\ No newline at end of file
diff --git a/v3.6.0/terraform-registry-manifest.json b/v3.6.0/terraform-registry-manifest.json
new file mode 100644
index 0000000..a8286e3
--- /dev/null
+++ b/v3.6.0/terraform-registry-manifest.json
@@ -0,0 +1,6 @@
+{
+    "version": 1,
+    "metadata": {
+        "protocol_versions": ["5.0"]
+    }
+}
\ No newline at end of file
diff --git a/v3.6.0/tools/go.mod b/v3.6.0/tools/go.mod
new file mode 100644
index 0000000..314503b
--- /dev/null
+++ b/v3.6.0/tools/go.mod
@@ -0,0 +1,94 @@
+module tools
+
+go 1.20
+
+require (
+	github.com/hashicorp/copywrite v0.18.0
+	github.com/hashicorp/terraform-plugin-docs v0.16.0
+)
+
+require (
+	github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
+	github.com/Masterminds/goutils v1.1.1 // indirect
+	github.com/Masterminds/semver/v3 v3.1.1 // indirect
+	github.com/Masterminds/sprig/v3 v3.2.2 // indirect
+	github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
+	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
+	github.com/armon/go-radix v1.0.0 // indirect
+	github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
+	github.com/bgentry/speakeasy v0.1.0 // indirect
+	github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect
+	github.com/bradleyfalzon/ghinstallation/v2 v2.5.0 // indirect
+	github.com/cli/go-gh v1.2.1 // indirect
+	github.com/cli/safeexec v1.0.0 // indirect
+	github.com/cli/shurcooL-graphql v0.0.2 // indirect
+	github.com/cloudflare/circl v1.3.3 // indirect
+	github.com/fatih/color v1.13.0 // indirect
+	github.com/fsnotify/fsnotify v1.5.4 // indirect
+	github.com/go-openapi/errors v0.20.2 // indirect
+	github.com/go-openapi/strfmt v0.21.3 // indirect
+	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
+	github.com/google/go-github/v45 v45.2.0 // indirect
+	github.com/google/go-github/v53 v53.0.0 // indirect
+	github.com/google/go-querystring v1.1.0 // indirect
+	github.com/google/uuid v1.3.0 // indirect
+	github.com/hashicorp/errwrap v1.1.0 // indirect
+	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-hclog v1.5.0 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	github.com/hashicorp/go-uuid v1.0.3 // indirect
+	github.com/hashicorp/go-version v1.6.0 // indirect
+	github.com/hashicorp/hc-install v0.5.2 // indirect
+	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/hashicorp/terraform-exec v0.18.1 // indirect
+	github.com/hashicorp/terraform-json v0.17.1 // indirect
+	github.com/henvic/httpretty v0.0.6 // indirect
+	github.com/huandu/xstrings v1.3.2 // indirect
+	github.com/imdario/mergo v0.3.13 // indirect
+	github.com/inconshreveable/mousetrap v1.0.1 // indirect
+	github.com/jedib0t/go-pretty v4.3.0+incompatible // indirect
+	github.com/jedib0t/go-pretty/v6 v6.4.6 // indirect
+	github.com/joho/godotenv v1.3.0 // indirect
+	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
+	github.com/knadh/koanf v1.5.0 // indirect
+	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/mattn/go-runewidth v0.0.13 // indirect
+	github.com/mergestat/timediff v0.0.3 // indirect
+	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
+	github.com/mitchellh/cli v1.1.5 // indirect
+	github.com/mitchellh/copystructure v1.2.0 // indirect
+	github.com/mitchellh/go-homedir v1.1.0 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/mitchellh/reflectwalk v1.0.2 // indirect
+	github.com/muesli/termenv v0.12.0 // indirect
+	github.com/oklog/ulid v1.3.1 // indirect
+	github.com/posener/complete v1.2.3 // indirect
+	github.com/rivo/uniseg v0.2.0 // indirect
+	github.com/rogpeppe/go-internal v1.10.0 // indirect
+	github.com/russross/blackfriday v1.6.0 // indirect
+	github.com/samber/lo v1.37.0 // indirect
+	github.com/shopspring/decimal v1.3.1 // indirect
+	github.com/spf13/cast v1.5.0 // indirect
+	github.com/spf13/cobra v1.6.1 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/thanhpk/randstr v1.0.4 // indirect
+	github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e // indirect
+	github.com/zclconf/go-cty v1.13.2 // indirect
+	go.mongodb.org/mongo-driver v1.10.0 // indirect
+	golang.org/x/crypto v0.14.0 // indirect
+	golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
+	golang.org/x/mod v0.11.0 // indirect
+	golang.org/x/net v0.17.0 // indirect
+	golang.org/x/oauth2 v0.8.0 // indirect
+	golang.org/x/sync v0.1.0 // indirect
+	golang.org/x/sys v0.13.0 // indirect
+	golang.org/x/term v0.13.0 // indirect
+	golang.org/x/text v0.13.0 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
+	google.golang.org/protobuf v1.28.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/v3.6.0/tools/go.sum b/v3.6.0/tools/go.sum
new file mode 100644
index 0000000..973e5f7
--- /dev/null
+++ b/v3.6.0/tools/go.sum
@@ -0,0 +1,654 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
+github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
+github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
+github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
+github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
+github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
+github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
+github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
+github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
+github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
+github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
+github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
+github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw=
+github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ=
+github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8=
+github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk=
+github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
+github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
+github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
+github.com/bradleyfalzon/ghinstallation/v2 v2.5.0 h1:yaYcGQ7yEIGbsJfW/9z7v1sLiZg/5rSNNXwmMct5XaE=
+github.com/bradleyfalzon/ghinstallation/v2 v2.5.0/go.mod h1:amcvPQMrRkWNdueWOjPytGL25xQGzox7425qMgzo+Vo=
+github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cli/go-gh v1.2.1 h1:xFrjejSsgPiwXFP6VYynKWwxLQcNJy3Twbu82ZDlR/o=
+github.com/cli/go-gh v1.2.1/go.mod h1:Jxk8X+TCO4Ui/GarwY9tByWm/8zp4jJktzVZNlTW5VM=
+github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
+github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
+github.com/cli/shurcooL-graphql v0.0.2 h1:rwP5/qQQ2fM0TzkUTwtt6E2LbIYf6R+39cUXTa04NYk=
+github.com/cli/shurcooL-graphql v0.0.2/go.mod h1:tlrLmw/n5Q/+4qSvosT+9/W5zc8ZMjnJeYBxSdb4nWA=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
+github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
+github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
+github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
+github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
+github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8=
+github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o=
+github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI=
+github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
+github.com/google/go-github/v53 v53.0.0 h1:T1RyHbSnpHYnoF0ZYKiIPSgPtuJ8G6vgc0MKodXsQDQ=
+github.com/google/go-github/v53 v53.0.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
+github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
+github.com/hashicorp/copywrite v0.18.0 h1:6f3aBDyQLBXhD6cdGSnsEM37vCDi3JJrkbR9HPBJf5c=
+github.com/hashicorp/copywrite v0.18.0/go.mod h1:6wvQH+ICDoD2bpjO1RJ6fi+h3aY5NeLEM12oTkEtFoc=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
+github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
+github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
+github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
+github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
+github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0=
+github.com/hashicorp/hc-install v0.5.2/go.mod h1:9QISwe6newMWIfEiXpzuu1k9HAGtQYgnSH8H9T8wmoI=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
+github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
+github.com/hashicorp/terraform-exec v0.18.1 h1:LAbfDvNQU1l0NOQlTuudjczVhHj061fNX5H8XZxHlH4=
+github.com/hashicorp/terraform-exec v0.18.1/go.mod h1:58wg4IeuAJ6LVsLUeD2DWZZoc/bYi6dzhLHzxM41980=
+github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA=
+github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
+github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI=
+github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA=
+github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
+github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
+github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/henvic/httpretty v0.0.6 h1:JdzGzKZBajBfnvlMALXXMVQWxWMF/ofTy8C3/OSUTxs=
+github.com/henvic/httpretty v0.0.6/go.mod h1:X38wLjWXHkXT7r2+uK8LjCMne9rsuNaBLJ+5cU2/Pmo=
+github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
+github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
+github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs=
+github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
+github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
+github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
+github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
+github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
+github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
+github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
+github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
+github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=
+github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mergestat/timediff v0.0.3 h1:ucCNh4/ZrTPjFZ081PccNbhx9spymCJkFxSzgVuPU+Y=
+github.com/mergestat/timediff v0.0.3/go.mod h1:yvMUaRu2oetc+9IbPLYBJviz6sA7xz8OXMDfhBl7YSI=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
+github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
+github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=
+github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc=
+github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
+github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
+github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
+github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw=
+github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
+github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
+github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
+github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
+github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e h1:BuzhfgfWQbX0dWzYzT1zsORLnHRv3bcRcsaUk0VmXA8=
+github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI=
+github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
+github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0=
+github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
+go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
+go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg=
+go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
+golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
+golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
+golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/v3.6.0/tools/tools.go b/v3.6.0/tools/tools.go
new file mode 100644
index 0000000..b02de1f
--- /dev/null
+++ b/v3.6.0/tools/tools.go
@@ -0,0 +1,22 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build generate
+
+package tools
+
+import (
+	// document generation
+	_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
+	// copywrite header generation
+	_ "github.com/hashicorp/copywrite"
+)
+
+// Generate copyright headers
+//go:generate go run github.com/hashicorp/copywrite headers -d .. --config ../.copywrite.hcl
+// Format Terraform code for use in documentation.
+// If you do not have Terraform installed, you can remove the formatting command, but it is suggested
+// to ensure the documentation is formatted properly.
+//go:generate terraform fmt -recursive ../examples/
+// Generate documentation.
+//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-dir ..